버그는 프로그래머의 숙명이다. 김밥을 마는 손에 밥풀이 묻는 것처럼, 비트와 바이트를 만지는 손에는 버그가 달라붙는다. 다익스트라(Dajikstra) 같은 사람은 프로그램의 정확성을 수학적으로 증명할 수 있는 방법을 연구했지만 죽기 전까지 완전한 방법을 찾을 수 없었다.
컴퓨터 프로그래밍은 수학처럼 순수한 논리 전개가 아니라 피와 살을 가진 사람의 구체적인 개입을 전제로 하기 때문이다. 인간의 행위가 개입하는 한 세상에 존재하는 어떤 것도 결함으로부터 자유로울 수 없다. 불완전함은 인간이 가진 자연스러운 속성의 하나이기에 키보드를 두드리는 사람의 손끝에서 버그가 쏟아져 나오는 것은 자연스러운 일이며 현대 프로그래밍 방법론의 한계다.
그래서 버그가 있느냐 없느냐는 논의의 대상이 될 수 없다. 그것이 얼마나 자주 발생하는지, 그것으로 인한 피해가 어느 정도인지를 문제로 삼을 수 있을 뿐이다.
소프트웨어를 다루는 사람이라면 누구나 자신이 저지른 실수를 깨닫고 심장이 멎을 것 같은 충격을 받아 본 경험이 있을 것이다. 심장이 한없이 작게 쪼그라들면서 세상에서 가장 외로운 사람이 된 것 같은 끔찍한 기분을 경험해보지 않은 사람은 진정한 소프트웨어를 개발해보지 않은 사람일 확률이 높다.
버그는 자신을 탄생시킨 사람을 충격과 공포의 도가니로 몰아넣는 잔인하고 배은망덕한 존재지만, 동시에 사람을 단단하고 강하게 만드는 채찍의 역할도 담당한다. 프로그래머가 실수 앞에서 좌절하는 것이 아니라 실수를 통해서 배우고 성장을 한다면 말이다.
버그에 대해서 이야기하자면 작년 여름에 월스트리트에서 회자되었던 전설적인 버그에 대해서 이야기하지 않을 수 없다. 그 버그가 초래한 피해는 우리 돈으로 5천억 원이 넘는 천문학적인 규모였다. 해당 버그를 낳은 사람이 자신이 실수를 깨닫는 순간 느꼈을 아득한 기분, 땅 밑이 꺼지고 하늘이 무너지는 것 같은 도저한 절망을 생각해보면 동종업계의 한 사람으로서 깊은 연민의 감정을 느끼지 않을 수 없다.
나이트 캐피털(Knight Capital)이라는 회사가 있었다. 정교한 트레이딩 알고리즘을 활용하여 주식거래 서비스를 전문적으로 제공하며 월스트리트에서 명성을 떨치던 회사였다. 하지만 이 회사는 지난 여름에 시카고에 있는 켓코(GETCO)라는 회사에게 합병되면서 KCG 홀딩스라는 회사로 재탄생했다.
말이 좋아서 재탄생이지 사실은 망해서 사라진 것이다. 앞길이 유망하던 나이트 캐피털이 한순간에 망할 수밖에 없었던 이유는 컴퓨터 시스템 안에 존재한 단 한 개의 버그 때문이었다. 이 버그는 탄생과 동시에 역사에 기록되는 전설이 되었다.
2012년 8월에 나이트 캐피털은 45분 만에 5천억원이 넘는 규모의 손실을 입는 악몽을 경험했다. 5천억 원이면 45분 동안 쉬지 않고 1초에 2억 원씩 손해를 봐야 도달할 수 있는 금액이다. 밤(night)이 아니라 나이트(Knight)를 이용한 '나이트메어'(Knightmare)라는 별칭으로 불리며 화제가 되었던 이 사건은 잘 나가던 나이트 캐피털을 불과 45분 만에 회생하기 어려운 궁지로 몰아넣었고 앞에서 말한 것처럼 문을 닫고 경쟁업체에게 합병이 되는 것으로 마무리가 되었다.
"상처에 모욕을 더하다"(add insult to injury)라는 영어 표현이 있다. 미국의 증권거래위원회(SEC)는 사건이 벌어지고 난 후 한참이 지난 최근에 와서 나이트 캐피털에게 컴퓨터 시스템과 관련한 ‘관리소홀’에 대한 죄를 물으며 (실제 손실액에 비하면 장난에 불과한) 15억 원의 벌금을 부과함으로써 나이트 캐피털의 쓰라린 상처에 모욕을 더해주었다.
사건의 정황을 자세하게 설명해주는 자료는 없지만, 미국 증권거래위원회의 보고서를 읽어보면 어느 정도 추측은 가능하다. 간단히 말해서 이 버그는 새로운 버전의 소프트웨어를 출시하는 작업을 담당한 IT 직원이 저지른 어이없는 실수로 인해서 발생했다.
나이트 캐피털은 자신의 클라이언트가 보내오는 주식거래 주문을 컴퓨터 시스템을 통해서 전달받는다. 이렇게 외부에서 전달되는 주문을 부모주문(parent order)이라고 부른다. 나이트 캐피털의 소프트웨어는 복잡한 알고리즘을 이용해서 부모주문을 여러 개의 자식주문(child order)으로 분할해서 실제 주식시장으로 전송한다.
엄청난 분량으로 쏟아져 들어오는 부모주문을 엄청나게 빠른 속도로 자식주문으로 분할해서 시장에 쏟아 붓는 것이다. 네트워크 프로토콜에 익숙한 사람이라면 이러한 소프트웨어를 일종의 라우터(router0라고 생각하면 이해가 쉬울 것이다.
나이트 캐피털은 2012월 8월 1일에 새로 개발을 완료한 소프트웨어를 현장에 출시했다. 전보다 빠르고 정교한 알고리즘을 장착한 코드는 나이트 캐피털에게 더 많은 수익을 안겨줄 것으로 기대되었다. 시스템 관리자는 (C++로 작성된 것으로 추측되는) 새로운 소프트웨어 코드를 병렬적으로 동작하는 서버 8대에 각각 설치하고 구성파일 안에 있는 플래그(flag) 변수를 활성화했다.
변수의 값을 ‘거짓’에서 ‘참’으로 변경함으로써 앞으로 새로운 코드가 사용되도록 만든 것이다. 이 변수는 오래 전에 사용되었던 비슷한 성격의 코드를 활성화하기 위해서 사용되던 변수였는데, 그 코드는 8년 전부터 아예 사용이 되지 않았다.
낡은 코드는 조만간 완전히 삭제될 예정이었기 때문에 (왜 진작 삭제하지 않았을까!) 새로운 코드를 출시하면서 낡은 코드가 사용하던 변수를 ‘재사용’하기로 결정한 것이다. 이렇게 구성파일 내부의 변수 값을 ‘참’으로 변경하고 시스템을 시작하자 8대 서버에서 새로운 소프트웨어가 동작을 개시했다. 모든 것은 의도한 대로 움직였고, 문제는 어디에도 없었다. 적어도 그런 것처럼 보였다.
하지만 새로운 코드를 8대의 서버에 출시하는 일을 담당한 직원은 코드를 처음 7대의 서버까지만 설치하고 무슨 이유에서인지 마지막 8번째 서버엔 설치하지 않았다. 잘못의 경중을 떠나서 누구나 저지를 수 있는 단순한 실수였다.
하지만 월스트리트 역사의 한 페이지에 기록될 끔찍한 나이트메어는 이렇게 어처구니없는 실수에서 시작되었다. 구성 파일의 변수를 변경하는 작업을 맡은 직원은 (8번째 서버에 이렇게 치명적인 실수가 저질러졌다는 사실을 알지 못한 채) 변수의 값을 ‘참’으로 바꾸었고, 이렇게 바뀐 값은 알라딘 램프 안에 갇혀있던 지니를 세상으로 불러내고, 단단하게 닫혀있던 판도라 상자의 뚜껑을 활짝 열고 말았다. 8년 동안 동작하지 않던 낡은 코드가 오래된 잠을 깨고 일어나서 동작을 개시한 것이다.
영업이 개시되자 나이트 캐피털의 클라이언트들은 엄청난 규모의 주식거래 주문을 전송하기 시작했다. 7대의 서버 위에서 동작하는 새로운 알고리즘은 빠르고 정교한 논리를 통해서 최대한의 이익을 얻기 위한 자식주문을 생성하여 조심스럽게 시장에 내어놓았다.
그와 동시에 깊은 겨울잠에서 깨어난 8번째 서버의 코드는 아무도 모르게 기괴한 거래주문을 시장에 쏟아내기 시작했다. 나이트 캐피털과 그의 고객들이 결코 원하지 않았을 터무니없는 주문이 45분 동안 막대한 규모로 시장에 쏟아져 나왔고, 상황을 알아차리고 소스라치게 놀란 나이트 캐피털이 컴퓨터 시스템을 모두 셧다운 시켰을 때는 이미 4억 6천만 달러, 우리돈으로 5천억 원이 넘는 규모의 손해가 발생하고 난 다음이었다.
여기에는 몇 가지 기술적인 교훈이 있다. 우선 사용되지 않는 낡은 코드는 반드시 삭제를 해서 없애야 한다는 점이다. 실행파일만이 아니라 소스코드에도 적용되는 이야기다. 어떤 프로그래머들은 삭제해서 없애야 하는 이전의 논리를 주석처리를 해서 남겨놓거나 심지어 if 구문을 통해서 우회한다.
상당히 나쁘고 위험한 습관이다. 두 번째는 소프트웨어 전개과정은 반드시 정확한 설명을 담고 있는 문서에 기반 해야 한다는 점이다. 다른 사람들이 전개 직전에 문서를 철저하게 검토하고, 전개가 수행된 다음에는 반드시 실제 전개된 내용과 문서의 내용을 비교 검토해야 한다.
SEC가 나이트 캐피털에게 벌금을 부과한 이유는 바로 이러한 기본적인 절차가 지켜지지 않았기 때문이었다. 세 번째는 구성파일 안에 있는 변수의 재사용이다. 변수를 하나 새롭게 도입하는 것이 그렇게 힘들고 어려운 일이었을까?
새로운 변수를 도입했더라면 설령 코드의 전개과정에서 실수가 저질러졌다고 하더라도 8번째 서버에서 낡은 코드를 잠에서 깨우는 일은 벌어지지 않았을 것이다. 효율성을 명목으로 코드의 간명함과 안전성을 해치는 행동은 전문가답지 않은 행동이다.
관련기사
- 5천억원짜리 SW버그가 주는 메시지2013.11.18
- SW개발의 8:2 법칙, 그리고 불편한 진실2013.11.18
- 소프트웨어 개발자와 영어의 힘2013.11.18
- SW개발과 빨리빨리 문화의 저주2013.11.18
다시 한 번 이야기하지만 인간은 불완전한 존재다. 그래서 컴퓨터 프로그래밍이라는 행위, 시스템 관리라는 행위도 불완전할 수밖에 없다. 문서, 절차, 검토, 확인, 테스트와 같은 부가적인 행위들이 때로는 불필요한 요식행위처럼 느껴지기도 하지만, 때로는 불완전한 존재인 우리에게 도움을 주기도 한다는 점을 기억하자.
우리가 오늘 작성한 코드 안에도 버그는 살아서 숨 쉬고 있다. 버그는 우리의 숙명이다.
*본 칼럼 내용은 본지 편집방향과 다를 수 있습니다.