---
type: knowledge
domain: engineering
status: active
last-reviewed: 2026-07-06
---

# 디버깅 원리

> 한 줄 정의
> 증상에서 원인으로 **수렴**하는 체계적 전략. 추측 수정을 반복하는 것이 아니라 가설-검증 루프를 돈다. 버그를 찾는 행위는 [[QA 원리]], 이 문서는 찾은 뒤 원인을 좁히는 행위.

## 철칙: 재현 먼저, 수정은 그다음

> [!WARNING] 재현 없이 수정 없다
> 재현하지 못한 버그를 "고쳤다"는 주장은 검증 불가능하다. 재현 = 이해의 증거이자, 수정 후 "정말 고쳐졌는가"의 유일한 판정 도구다. 재현이 안 되면 재현 조건 탐색이 곧 디버깅이다.

## 용의자 1순위: 최근 변경

"어제까지 됐는데"의 답은 거의 항상 어제와 오늘 사이의 diff에 있다. 코드 변경, 배포, 의존성 업데이트, 설정 변경, 데이터 마이그레이션 — **변경 이력 조회가 스택 트레이스보다 먼저**일 때가 많다.

## 이분 탐색 3축 — 반씩 자른다

선형으로 훑지 말고 공간을 절반씩 소거한다:

| 축 | 질문 | 도구 |
|----|------|------|
| 시간 | 언제부터 깨졌나 | `git bisect`, 배포 이력, 로그 타임라인 |
| 공간 | 어느 레이어인가 | 프론트/API/DB 경계마다 값 확인 — 절반씩 소거 |
| 데이터 | 어떤 입력에서만 나나 | 입력을 최소 재현 케이스로 깎아낸다 |

## 가설-검증 루프 — 한 번에 하나만

1. 관찰을 적는다 (무엇이, 언제, 어떤 조건에서)
2. 가설을 세운다 — "X 때문이다"
3. 가설이 참이면 관측될 결과를 **먼저** 예측한다
4. 실험은 **변수 하나만** 바꾼다 — 두 개 바꾸면 고쳐져도 무엇이 고쳤는지 모른다. 배운 게 없는 수정은 재발한다.
5. 결과를 기록하고 가설을 기각/채택

## 에러 메시지는 끝까지, 첫 에러부터

- 스택 트레이스 첫 줄만 보고 뛰어들지 않는다 — 메시지 전문에 답이 있는 경우가 절반.
- 에러가 여러 개면 **시간상 첫 번째**가 진짜다. 나머지는 연쇄(cascade)일 가능성이 크다.
- 에러 메시지를 검색할 땐 프로젝트 고유 부분(변수명·경로)을 빼고 일반 부분만.

## "불가능하다"면 가정이 틀렸다

코드를 아무리 봐도 불가능해 보이면, 코드가 아니라 가정을 의심한다:

| 흔한 틀린 가정 | 실제 |
|--------------|------|
| 그 코드가 실행됐다 | 캐시된 빌드, 배포 안 된 코드, 다른 브랜치 |
| 같은 환경이다 | 로컬 ≠ 스테이징 ≠ 프로드 (env, 데이터, 버전) |
| 같은 데이터다 | 프로드에만 있는 더러운 데이터, NULL, 레거시 행 |
| 시계가 같다 | 서버-클라이언트-DB 타임존 불일치 |
| 한 명만 쓰고 있다 | 동시 요청, 레이스 컨디션 |

디버거를 붙이면 사라지는 버그(하이젠버그)는 거의 항상 타이밍·동시성 문제다 — 로그 기반으로 전환한다.

## 러버덕 — 설명이 절반을 푼다

이슈에 상황을 글로 정리하는 행위 자체가 디버깅이다. "재현 단계를 쓰다가 스스로 답을 찾는" 빈도는 경험적으로 매우 높다. 막히면 사람(또는 에이전트)에게 설명하라 — 설명 중 무의식적 가정이 드러난다.

## 2시간 룰 — 더 세게 말고 다르게

같은 접근으로 2시간 막히면 접근을 바꾼다: 다른 축으로 이분 탐색, 최소 재현 프로젝트 새로 만들기, 잠시 떠나기, 다른 사람 시선. 매몰 시간은 접근이 옳다는 증거가 아니다.

## 수정 후 3종 세트

1. **회귀 테스트 추가** — "왜 기존 테스트가 못 잡았나"에 답하는 테스트를 남긴다
2. **같은 패턴 수평 검색** — 이 버그의 패턴이 코드베이스 다른 곳에도 있는지 grep
3. **근본 원인 한 줄 기록** — 증상이 아니라 원인을 (5 whys 압축) → [[실패사례-기록법]]

## 에이전트 적용

- **조사 없는 수정 금지**: 에이전트에게 버그 수정을 맡길 때 "고쳐줘"가 아니라 "재현→가설→검증→수정" 순서를 계약으로 강제한다. 추측 수정 루프는 코드를 더럽히고 신뢰를 태운다.
- 에이전트가 반복하는 실수 패턴은 [[AI-실수패턴]]에 누적 — 디버깅 대상이 코드가 아니라 프롬프트일 때가 있다.

## 관련 문서

- [[QA 원리]] — 버그 발견 단계
- [[실패사례-기록법]] — 근본 원인의 영속 기록
- [[AI-실수패턴]] — 에이전트발 버그의 패턴
- [[백엔드 원리]] — 로깅·모니터링 설계
