
틀린 답을 올리면 정답이 온다, 커닝햄의 법칙(Cunningham’s Law)
프로그램에서 가끔 이상한 오류가 난다는 신고를 받고 원인을 찾으려고 디버거를 켜면, 거짓말처럼 오류가 사라지는 경우가 있습니다. 확인용 출력 한 줄을 넣었을 뿐인데 문제가 멈추고, 그 줄을 지우면 다시 나타나기도 합니다. 개발자들은 이렇게 들여다보는 순간 숨어 버리는 버그에 물리학자의 이름을 빌린 별명을 붙였습니다. 바로 ‘하이젠버그(Heisenbug)’입니다.
하이젠버그란 쉽게 말해 원인을 조사하려고 하면 사라지거나 행동이 달라지는 소프트웨어 버그를 의미합니다. 관찰하는 행위 자체가 대상의 상태를 바꾼다는 관찰자 효과를 빗댄 말로, 재현과 추적이 특히 어려운 버그를 가리킬 때 씁니다.
본 자료에서는 하이젠버그라는 이름이 어디서 왔는지부터 버그가 숨는 이유, 함께 쓰이는 버그 별명들, 그리고 하이젠버그를 잡는 방법까지 차례로 살펴보겠습니다.
보려고 하면 숨는 버그, 하이젠버그
하이젠버그라는 이름의 유래

이 별명은 물리학의 유명한 원리와 프로그래머들의 농담이 만나 생겨났습니다.
(1) 물리학자 이름을 빌린 말장난
하이젠버그는 불확정성 원리를 내놓은 독일 물리학자 베르너 하이젠베르크(Werner Heisenberg)의 이름에 벌레를 뜻하는 버그(bug)를 겹친 말장난입니다. 관찰하려는 순간 대상이 달라진다는 관찰자 효과를 떠올리게 하려는 의도가 담겨 있습니다.
(2) 기록에 처음 나타난 시점
알려진 가장 이른 기록은 1983년 미국 컴퓨터 학회(ACM)의 출판물입니다. 1985년에는 데이터베이스 연구자 짐 그레이(Jim Gray)가 소프트웨어 장애를 다룬 논문에서 이 말을 써서 그가 만든 말로 잘못 알려지기도 했습니다.
(3) 전자공학의 오래된 이웃
전자공학에는 비슷한 현상을 부르는 프로브 효과(probe effect)라는 말이 먼저 있었습니다. 측정용 탐침을 회로에 대는 것만으로 장치의 동작이 바뀌는 현상입니다.
다만 이 이름에는 비판도 따릅니다. 불확정성 원리와 관찰자 효과는 서로 다른 개념인데, 별명이 둘을 하나처럼 섞어 버린다는 지적입니다. 그래서 하이젠버그는 정확한 과학 용어라기보다 개발 현장의 재치 있는 은어로 받아들이는 편이 좋습니다.
하이젠버그는 왜 숨을까

버그가 정말 사람의 눈치를 보는 것은 아닙니다. 원인을 살피려는 도구와 방법이 프로그램의 실행 조건을 조금씩 바꾸기 때문입니다.
(1) 실행 시간이 달라진다
디버거로 한 줄씩 실행하면 프로그램이 평소보다 훨씬 느려집니다. 여러 작업이 동시에 돌아가는 프로그램에서는 작업 순서가 조금만 어긋나도 생기는 경쟁 상태(race condition)가 흔한데, 속도가 바뀌면 그 어긋남이 일어나지 않을 수 있습니다.
(2) 메모리 배치가 달라진다
확인용 출력문을 넣거나 디버깅용으로 다시 빌드하면 변수가 놓이는 메모리 위치가 바뀝니다. 초기화하지 않은 변수나 엉뚱한 곳을 가리키는 포인터가 원인이라면, 위치가 바뀌는 순간 증상도 함께 바뀝니다.
(3) 최적화 여부가 달라진다
성능을 위해 최적화한 프로그램에서만 오류가 나고, 디버깅을 위해 최적화를 끈 프로그램에서는 멀쩡한 경우도 많습니다. 예를 들어 계산 값을 레지스터에 둘 때와 메모리로 옮길 때 정밀도가 달라 실수 비교 결과가 바뀔 수 있습니다.
결국 하이젠버그는 따로 존재하는 진짜 결함이 실행 조건에 따라 겉으로 드러났다 숨었다 하는 모습입니다. 증상이 사라졌다고 원인까지 사라진 것은 아니라는 점이 핵심입니다.

하이젠버그와 함께 쓰이는 버그 별명

하이젠버그가 널리 쓰이면서 과학자의 이름을 빌린 버그 별명이 여럿 생겼습니다.
- 보어버그(Bohrbug): 물리학자 닐스 보어의 원자 모형처럼 정해진 규칙을 따라, 같은 조건이면 언제나 똑같이 나타나는 버그입니다. 재현이 쉬워 비교적 잡기 쉽습니다.
- 만델버그(Mandelbug): 원인이 너무 복잡해 행동이 혼란스러워 보이는 버그입니다. 프랙털을 연구한 수학자 브누아 망델브로의 이름에서 왔습니다.
- 슈뢰딩버그(Schrödinbug): 코드를 읽던 개발자가 애초에 동작할 리 없는 코드였다는 사실을 알아챈 뒤부터 실제로 문제를 일으키는 버그입니다.
- 힉스버그슨(Higgs-bugson): 기록과 사용자 신고로 보아 분명히 있을 것 같지만 개발 환경에서는 재현하기 어려운 버그입니다.
이 별명들은 대부분 농담에서 출발했지만, 버그를 재현할 수 있는지와 원인이 얼마나 복잡한지를 짧게 나눠 부르는 데 쓸모가 있습니다.
하이젠버그를 잡는 방법

하이젠버그는 까다롭지만 접근 방식을 바꾸면 충분히 붙잡을 수 있습니다.
(1) 실행을 멈추지 않고 기록을 남긴다
디버거로 프로그램을 세우는 대신, 실행 흐름을 덜 건드리는 가벼운 기록을 남기고 문제가 난 뒤에 살펴봅니다. 관찰이 주는 영향을 줄이는 것이 첫 번째 원칙입니다.
(2) 같은 조건을 그대로 되살린다
문제가 난 빌드 설정, 입력 값, 실행 환경을 최대한 똑같이 맞춥니다. 실행 과정을 녹화해 두었다가 똑같이 되돌려 보는 도구를 쓰는 방법도 있습니다.
(3) 원인 후보를 좁힌다
초기화하지 않은 변수, 잘못된 포인터, 작업 사이의 순서 문제처럼 하이젠버그를 자주 일으키는 원인부터 차례로 점검합니다. 코드 검사 도구와 메모리 검사 도구가 이 과정을 크게 덜어 줍니다.
(4) 사라졌다고 끝내지 않는다
코드 한 줄을 바꿨더니 증상이 멈췄다면, 버그가 고쳐진 것인지 잠시 숨은 것인지 따져 봐야 합니다. 원인을 설명할 수 있을 때 비로소 해결했다고 말할 수 있습니다.
하이젠버그는 관찰하는 도구조차 시스템의 일부라는 사실을 개발자에게 일깨워 줍니다. 버그가 보이지 않는 순간에도 실행 조건이 무엇을 바꾸었는지 묻는 태도가 필요합니다.
증상이 사라진 순간에 만족하지 않고 그 이유까지 끝까지 추적하는 것, 그것이 믿을 수 있는 소프트웨어 개발의 첫걸음입니다.
이 글 PDF 구매
1,000원한국어 PDF · 같은 계정으로 다시 다운로드할 수 있어요.





