본문으로 건너뛰기

버그 제보

이상한 점을 알려 주시면 고칠게요. 지금 보고 있는 페이지와 브라우저 정보가 함께 담겨요.

페이지:

Career

디버깅 사고법: 가설을 세우고 반증한다

작성 2026. 10. 21.추가
목차7개 항목
출처와 참고

Devon H. O'Dell의 「The Debugging Mindset」(ACM Queue, 2017)을 바탕으로 재구성한 노트다.

디버깅이 어려운 이유

개발자는 시간의 3550%를 검증과 디버깅에 쓰고, 디버깅·테스트·검증 비용은 프로젝트 예산의 5075%로 추정된다. 도구와 언어가 좋아져 버그 하나를 잡는 시간은 줄었지만 디버깅에 쓰는 총시간은 크게 줄지 않았다. 그래서 버그를 없애는 데 집착하기보다 디버깅을 문제 해결 연습으로 받아들이고, 빨리 배우는 법을 익히는 편이 낫다.

버그는 멘탈 모델이 틀린 자리에서 생긴다. 소프트웨어는 시간에 따른 상태 변화를 기술하고, 상태와 전이의 수는 조합적으로 커진다. 그래서 개발자는 시스템 동작을 근사한 멘탈 모델(mental model) 위에서 추론한다. 모델이 틀린 곳에서 잘못된 가정 위에 코드가 쌓인다. 버그는 한 번의 실수가 아니라 프로그래밍 중에 쌓인 인지 붕괴의 사슬이다.

가장 고약한 버그는 자기 모델이 완전하다고 믿을 때 생긴다. 구현이 옳다고 가정했으니 어디서 틀렸는지 정의상 모른다. 이런 버그는 새 지식을 얻어야만 풀린다. 그래서 디버깅은 코드 작성보다 어렵고, 본질적으로 학습이다.

도구는 만능이 아니다. 문제에 맞는 도구가 없거나, 재현에 필요한 부하를 감당하지 못하거나, 도구를 모를 수 있다. 런타임을 블랙박스로 감추는 언어(VM, 인터프리터)는 멘탈 모델의 범위를 줄여 주지만, 버그가 그 런타임 안에 있으면 이해에 구멍이 남는다. 형식 검증 언어로 「증명된」 코드도 문제를 잘못 이해했다면 여전히 디버깅이 필요하다. 필요하면 도구를 직접 만들거나 도구 없이 해 낼 수 있어야 한다.

과학적 방법으로 디버깅하기

디버깅은 예술이 아니라 과학이다. 과학적 방법은 새 지식을 얻으려고 만든 절차이고, 디버깅은 지식을 얻는 일이기 때문이다.

1. 문제에 대한 일반 이론을 세운다
2. 가설로 이어질 질문을 던진다
3. 가설을 세운다
4. 데이터를 모아 가설을 검증한다
5. 반복한다

가장 많이 건너뛰는 단계가 가설 세우기다. 가설 없이 이것저것 바꿔 보는 테스트는 헛수고다. 직감도 쓸모 있지만 오랜 경험이 있어야 하고, 직감만 쓰면 낯선 버그 앞에서 손쓸 틀이 없다.

좋은 가설의 조건

좋은 가설은 문제를 설명하고, 검증할 수 있고, 반증할 수 있다. 같은 버그를 두고 세운 가설 세 개를 비교하면 차이가 보인다.

가설평가
「로깅 모듈에 경쟁 상태가 있다」직감 수준. 검증은 가능하지만 맞다고 확인돼도 어떻게 고칠지 알려 주지 않는다
「동시에 로그를 넣는 생산자들이 같은 항목을 큐에 넣을 때 경쟁 상태가 생긴다」재현을 한 듯 정보가 더 있다. 하지만 왜 같은 항목이 들어가는지 예측하지 못하고, 경쟁 상태가 최종 결함도 아니다
「풀이 비었을 때의 반환 코드를 잘못 처리해서, 풀의 작업 객체를 쓰는 동시 생산자 사이에 경쟁이 생기고, 나중에 소비자가 같은 객체를 꽉 찬 풀에 여러 번 되넣으려다 이중 해제(double free)가 난다」가장 좋다. 왜 생기는지(원인)와 무엇이 실패하는지(증상)를 함께 설명하고, 원인이 실패와 다른 시점·위치에 있다는 것까지 짚는다. 이 가설만 회귀 테스트가 무엇을 확인해야 하는지 알려 준다
  • 반증 가능성(falsifiability)이 핵심이다. 틀렸다고 증명할 방법이 없는 가설은 어떤 테스트로도 「확인」되므로 아무것도 알려 주지 않는다.
  • 제대로 된 가설을 세웠다면 대개 버그를 이미 이해한 것이다.
  • 어려운 버그일수록 멘탈 모델을 내려놓는다. 모델이 틀려서 버그가 생겼으니, 그 모델로 원인을 설명하려는 것이 바로 잘못된 길이다.

주석은 규범이 아니라 참고다

버그가 의심되는 코드의 주석은 기존 멘탈 모델을 강화해 버그를 덮는다. 「모든 항목을 비운다」는 주석 아래 i <= count로 하나를 더 비우는 off-by-one 코드가 있으면, 주석은 맞지만 불완전하고 읽는 사람은 코드가 당연히 옳다고 넘어간다. 디버깅할 때 주석은 참고(informative)로만 읽고 규범(normative)으로 믿지 않는다.

마인드셋: 버그를 능력의 한계로 보지 않는다

심리학의 자기 이론(self-theories of intelligence)은 지능을 보는 관점을 양 끝으로 나눈다.

고정 관점(entity theory, 고정 마인드셋)성장 관점(incremental theory, 성장 마인드셋)
지능은타고나며 바뀌지 않는다노력으로 늘어난다
어려운 문제는내 능력의 한계배움의 일부
동기똑똑해 보이기실제 성과
개발 조직에서 드러나는 모습영웅 숭배, 가면 증후군, 카고 컬트, 쉬운 일만 골라 많이 하기, 포기, 협업 회피어려운 문제에 정면으로 덤빈다, 남을 가르치고 돕는다, 팀에서 잘 일한다

관점은 영역마다 다를 수 있다. 지능 일반은 성장한다고 믿으면서 「디버깅은 타고나는 것」이라고 믿을 수 있다. 그리고 관점은 옮겨 갈 수 있다.

  • 능력이 아니라 노력을 칭찬한다. 까다로운 버그를 잡은 동료에게 「천재네」보다 「끈질기게 파고든 덕분이다」라고 말한다. 능력 칭찬은 고정 관점을, 노력 칭찬은 성장 관점을 키운다. 칭찬을 듣는 당사자가 아니라 옆에서 듣는 사람에게도 같은 효과가 있다.
  • 버그를 개인의 실패로 다루지 않는다. 시스템 전체를 혼자 설계·운영하는 개발자는 드물다.
  • 배울 것이 있는 일을 준다. 쉬운 일만 맡겼다면 미안해하고 다음엔 더 도전적인 일을 준다. 사람은 혼자 할 수 있는 수준보다 조금 위에서 가장 잘 배운다(근접 발달 영역).
  • 좌절을 말하는 동료에게는 「이걸 끝내면 무엇을 배우게 될까」로 다시 틀을 잡는다.

감정 다루기 자체는 개발자의 마음가짐, 비난 없는 문화는 친절한 엔지니어링에 있다.

디버깅 실력을 키우는 습관

습관하는 법
능동적 회상(active recall)memcpy의 인자 순서가 (dest, src, n)인지 (src, dest, n)인지 헷갈리면, 문서를 보기 전에 먼저 추측해 코드를 쓰고 그다음 확인한다. 바로 찾아보는 습관은 기억을 키우지 않는다
나눠 공부하기(segmented study)하루 종일 한 버그에 매달리면 매몰 비용 오류에 빠진다. 서로 관계없는 일 한두 개를 곁에 두고 막히면 갈아탄다. 쉬고 자고 돌아와 풀리는 것은 우연이 아니다. 관리자는 이런 전환을 명시적으로 허용한다
끈기나눠 공부하기는 포기가 아니다. 자기 능력의 가장자리에서 오래 연습하는 끈기(grit)가 성공과 가장 강하게 연결된다
호기심가르칠 때는 내 방식이 모두에게 최선이라고 가정하지 않는다. 배우는 사람이 이미 아는 것에 새 지식을 이을 수 있게 그 사람의 관점에서 설명한다

정리

  • 버그는 틀린 멘탈 모델에서 생기고, 디버깅은 그 틀린 곳을 배우는 일이다.
  • 과학적 방법을 따르되 가설 세우기를 건너뛰지 않는다. 좋은 가설은 원인과 실패를 함께 설명하고 반증할 수 있다.
  • 어려운 버그일수록 기존 모델과 주석을 의심한다.
  • 버그를 능력의 한계가 아니라 배움으로 본다. 노력을 칭찬하고, 막히면 잠시 다른 일로 갈아탄 뒤 끈기 있게 돌아온다.

관련 노트: DevTools 디버깅, C 디버깅 도구, 개발자의 마음가짐, 친절한 엔지니어링, 소프트웨어 복잡성

원본 기록1

댓글

GitHub 계정으로 댓글을 남길 수 있어요.