Skip to main content

버그를 '고치는 일'은 코드 몇 줄을 바꾸는 작업처럼 보이지만, 실제로는 다시 안 고장 나게 만드는 루프를 완성하는 일입니다. 이 챕터에서는 Codex를 이용해 "증거 수집 → 최소 재현 → 원인 추적 → 최소 패치 → 회귀 테스트 추가 → 변경 요약"까지 한 번에 끝내는 표준 절차를 익힙니다. 이 절차의 핵심은 디버깅을 추측이 아니라 실험으로 다루는 태도입니다.1


1) 시작점: '실패 스토리'를 정확히 붙잡기

Codex에게 버그를 맡기기 전에, 사람이 해야 할 첫 단계는 실패를 재현 가능한 이야기로 정리하는 것입니다. 좋은 버그 리포트는 이후 모든 단계의 속도를 결정합니다.6

실패 스토리는 보통 다음 5가지로 구성됩니다.

  • 관측된 증상(Actual): 에러 메시지, 스택 트레이스, 잘못된 화면/출력, 스크린샷/녹화

  • 기대 동작(Expected): 정상이라면 무엇이 나와야 하는지

  • 환경(Environment): OS/런타임/브라우저/디바이스/빌드 번호, 설정 토글/피처 플래그

  • 재현 단계(Steps): 사람이 따라 하면 같은 문제가 나는 단계

  • 재현 빈도(Reproducibility): 항상/간헐적(예: 3/10)/한 번

특히 "스크린샷만 있고 로그가 없다"는 경우가 많은데, 스크린샷은 '무엇이 보였는지'를 보여주고, 로그는 '왜 그랬는지'를 추적할 실마리를 줍니다.7 Codex에게는 스크린샷보다 텍스트 로그/스택 트레이스/재현 단계가 훨씬 강력한 입력입니다.

Codex에 주는 첫 프롬프트 템플릿

아래 템플릿은 Codex가 섣불리 패치를 만들지 않고, 재현과 원인 추적부터 진행하도록 방향을 잡아줍니다.5

프롬프트

버그를 고치기 전에 다음 순서로 진행해줘.

  1. 재현 절차를 먼저 고정하고(가능하면 테스트/스크립트로),

  2. 재현이 확인되면 런타임 정보(로그/트레이스/변수 상태)를 추가로 수집해서,

  3. 근본 원인 가설을 세운 뒤(근거 포함),

  4. 실패하는 회귀 테스트를 먼저 추가하고,

  5. 최소 변경으로 수정한 다음,

  6. 전체 테스트를 돌려 회귀를 확인해줘.

입력 자료:

  • 에러 로그/스택 트레이스: …

  • 기대 동작: …

  • 실제 동작: …

  • 재현 단계: …

  • 환경: …

출력 형식:

  • 재현 방법(명령어 포함)

  • 추가로 필요한 정보 질문(있다면)

  • 가설 카드(원인/근거/배제한 가설)

  • 테스트 추가 커밋

  • 수정 커밋

  • 변경 요약 및 검증 결과


2) 최소 재현(MRE) 만들기: 문제를 작게 만들수록 빨라진다

재현이 안 되면 디버깅은 거의 멈춥니다. 재현은 단순한 '절차 기록'이 아니라, 문제를 통제 가능한 조건으로 가두는 작업입니다.6 그리고 그 재현은 가능하면 최소 재현 예제(MRE)로 줄여야 합니다.11

MRE의 목표는 "이 코드를 복사해 실행하면, 당신이 말한 그 에러가 난다"에 가까워지는 것입니다.12 여기에 Codex가 특히 강합니다. Codex는 레포 전체를 보며 재현에 필요 없는 의존성과 경로를 제거하고, 가장 짧은 실패 경로를 찾아 테스트 또는 스크립트로 고정하는 데 도움을 줍니다.

MRE를 잘 만드는 요령

원칙은 간단합니다. 없애도 되는 것을 계속 없애되, 버그는 남겨라입니다.1215

  • 입력 데이터를 줄입니다(예: 100만 건 중 2건만 남겨도 동일 실패라면 2건만).

  • 실행 단계를 줄입니다(버그를 유발하지 않는 클릭/요청/세팅은 제거).

  • 환경 변수를 고정합니다(버전, 플래그, 캐시, 랜덤 시드 등).

Stack Overflow의 가이드가 강조하듯, "최소"와 "재현 가능"은 함께 가야 합니다. 너무 줄여서 재현이 깨지면, 그건 '짧은 예제'이지 '최소 재현 예제'가 아닙니다.11

Codex에게 MRE를 맡기는 방식

실무에서는 다음 중 하나로 MRE를 고정하면 좋습니다.

  • 단위 테스트(실패를 가장 빨리 반복 가능)

  • 통합 테스트(실제 경로를 더 잘 반영)

  • 한 파일 스크립트(환경 문제가 섞였을 때 강력)

Codex에게는 이렇게 지시합니다.

프롬프트

현재 버그를 재현하는 최소 단위 테스트(또는 한 파일 스크립트)를 만들어줘. 조건:

  • 재현 성공/실패가 결정적이어야 함(가능하면 시드 고정)

  • 실행 시간이 짧아야 함

  • 외부 의존(네트워크, 실제 DB 등)은 가능하면 목/픽스처로 대체

  • 재현에 불필요한 코드/데이터는 제거

결과물:

  • 실행 명령어

  • 새로 추가/수정한 파일 목록


3) 원인 추적: '패치'가 아니라 '근본 원인'을 겨냥한다

많은 AI 디버깅 실패는 "패치를 못 써서"가 아니라 너무 빨리 패치를 써서 발생합니다.5 에러가 던져진 지점(crash site)에 방어 코드를 추가하면 당장은 통과할 수 있지만, 다른 경로에서 같은 문제가 다시 터집니다. 그래서 이 루프는 반드시 "가설 → 실험(재현) → 증거 → 결론"으로 진행해야 합니다.1

(1) 가설 카드를 먼저 만든다

SWE-bench 기반 디버깅 방법론에서는, 코드 변경 전에 '가설 카드'를 작성하게 해서 섣부른 수정을 막습니다.5 이 방식은 Codex를 쓸 때도 매우 효과적입니다.

가설 카드에는 다음이 포함됩니다.5

  • 지지되는 가설(supported): 근본 원인 1개를 구체적으로

  • 근거(evidence): 로그/트레이스/변수 상태에서 "어떤 사실"이 이를 지지하는지

  • 배제한 가설(rejected): 그럴듯했지만 증거로 제외한 설명과 이유

Codex에게 "배제한 가설까지 써라"라고 요구하면, 그럴듯한 합리화로 땜질하는 확률이 크게 줄어듭니다.5

(2) 런타임 사실을 수집한다: 로그/트레이스/계측

코드만 보고 추론하면, 사람도 AI도 빈틈이 생깁니다. 그래서 디버깅은 런타임 정보를 수집하는 쪽으로 진화했습니다.4 Cursor의 Debug Mode가 먼저 가설을 세운 뒤 로그를 삽입해 런타임 데이터를 모으는 흐름을 택한 이유도 여기에 있습니다.4

Codex에게는 "어디에 어떤 로그를, 무엇을 확인하려고 넣는지"까지 포함해 계측을 부탁합니다. 이때 로그는 많을수록 좋지 않습니다. 상태가 '기대와 달라지기 시작하는 경계(boundary)'에만 넣어야 신호가 살아납니다.1

예를 들어 API 요청 실패라면 입력 파라미터, 인증/권한, 네트워크 응답, 파싱 결과처럼 상태 전이가 일어나는 지점이 경계입니다.

(3) 5 Whys로 '잘못된 값'의 출처를 끝까지 쫓는다

증상이 "여기서 None이 들어와서 터진다"처럼 보일 때, 가장 흔한 오답은 crash site에 null-check를 추가하는 것입니다.5 이 유형은 대개 상류(upstream)에서 잘못된 값이 만들어진 문제라서, 값이 어디서 잘못됐는지 5 Whys로 역추적해야 합니다.5

또한 '근본 원인 분석(RCA)' 관점에서 빠른 패치와 영구 해결책을 구분해 사고하면, 같은 유형의 장애가 반복되는 것을 막을 수 있습니다.3


4) 패치: 최소 변경 + 초점 유지 + 부작용 차단

원인이 확인되면, 수정은 작고 좁게 가져갑니다. 디버깅의 황금률은 한 번에 변수를 하나만 바꾸는 것입니다.1

(1) "초점 구역(focus zone)"을 정하고 벗어나지 않기

디버그 트레이스와 재현 경로로 "이번 버그가 실제로 지나간 함수/모듈"이 정해집니다. 패치의 첫 변경은 그 구역 안에 있어야 합니다.5 테스트가 우연히 통과한다고 해서 무관한 유틸이나 테스트 헬퍼를 건드리는 식의 '수정 표류(fix drift)'는 위험합니다.5

Codex에게는 이렇게 제한을 겁니다.

프롬프트

수정은 아래 focus zone 안에서 시작해줘.

  • 재현 경로(call chain): …

  • 핵심 파일/함수: …

focus zone 밖 파일을 수정해야 한다면,

  • 왜 인과적으로 필요한지(원인과의 연결)를 먼저 설명하고

  • 그 다음에만 수정해줘.

(2) 임시 계측은 제거하고, 의미 있는 관측만 남기기

원인 추적을 위해 넣은 로그는 해결 후 정리합니다. 다만 장애 재발 방지에 도움이 되는 구조화 로그/상관관계 ID 같은 관측성 개선은 남겨도 좋습니다.1


5) 회귀 테스트: '고쳤다'의 정의를 코드로 남긴다

버그 수정의 완료 조건은 "지금 재현이 안 된다"가 아니라, 실패가 테스트로 고정되어 있고, 수정 전에는 실패하며 수정 후에는 통과한다입니다.1 이것이 재발 방지의 최소 단위입니다.

(1) 순서가 중요하다: (실패하는 테스트) → (수정)

테스트를 나중에 쓰면, 수정이 진짜 원인을 고쳤는지 확인하기 어렵습니다. 반면 실패 테스트를 먼저 추가하면, Codex도 사람도 목표가 분명해집니다.

(2) 회귀 테스트 범위를 설계한다

회귀 테스트는 변경이 기존 기능을 깨지 않았는지 확인하기 위해, 변경과 영향 범위를 반영해 구성합니다.29 CI/CD에서는 커밋마다 자동으로 돌아가야 효과가 커집니다.29

또한 회귀 테스트는 "특정 버그가 고쳐졌는지 확인(retesting)"과 "다른 기능이 깨지지 않았는지 확인(regression testing)"을 구분해 사고하면 설계가 쉬워집니다.29


6) Codex로 굴리는 '버그 수정 루프' 실행 스크립트

아래는 실제로 Codex에 일을 위임할 때의 운영 순서입니다. (명령어는 환경에 맞게 조정하세요.)

6.1 1단계: 재현 태스크 만들기

Codex에게 다음 산출물을 한 번에 요구합니다.

  • 재현을 위한 최소 커맨드

  • 재현을 고정하는 테스트(또는 스크립트)

  • 재현 성공/실패 기준(무엇을 보면 실패인지)

재현이 마련되면, Codex가 같은 실패를 반복하며 실험을 수행할 수 있습니다.1

6.2 2단계: 원인 추적 태스크(계측 포함)

간헐적 버그거나 데이터/타이밍이 중요하면, 한 번의 실행으로는 증거가 부족할 수 있습니다. 이때는 런타임 로그를 강화하고 여러 번 반복 실행해 패턴을 잡습니다.10

이 과정에서 중요한 습관은 "변경 1개 → 재현 실행 1번 → 결과 기록"입니다.1

6.3 3단계: 테스트 추가 커밋 → 수정 커밋 → 검증

커밋을 둘로 쪼개면 리뷰가 쉬워집니다.

  • 커밋 A: test: add regression test for <bug> (수정 없이 테스트만)

  • 커밋 B: fix: <root cause> (makes test pass)

마지막으로 CI 기준의 회귀 테스트를 실행해 '부작용 없음'을 확인합니다.29


7) 최종 산출물: PR/이슈에 남길 '변경 요약' 템플릿

버그는 고쳐도, 맥락이 남지 않으면 같은 실수를 다시 합니다. 그래서 PR 본문(또는 이슈 코멘트)에 아래 5줄만 남겨도 팀의 기억이 생깁니다.2

  • 재현 방법: 명령어/테스트 이름, 재현 빈도

  • 근본 원인: 한 문장(어떤 조건에서 무엇이 잘못됐는지)

  • 수정 내용: 어떤 파일/로직을 어떻게 바꿨는지(최소 변경)

  • 회귀 테스트: 어떤 테스트가 실패를 고정하는지

  • 검증 결과: 로컬/CI, 추가로 확인한 시나리오


8) 이 루프가 'Codex 친화적'인 이유

Codex는 코드 작성 자체보다, 실험을 반복하고 증거를 축적하는 운영에서 가치가 커집니다. 디버깅을 "가설 → 재현 → 수정"으로 모델링하면 추측이 줄고,1 런타임 사실을 중심으로 판단하면 섣부른 패치가 줄어듭니다.5 마지막으로 회귀 테스트가 그 결과를 고정하면, 버그는 단발성 사건이 아니라 시스템의 안전장치로 전환됩니다.29

이 챕터의 루프를 팀의 기본 습관으로 만들면, Codex는 단순한 '코드 생성기'가 아니라 재발 방지 장치를 꾸준히 늘려주는 비동기 디버깅 파트너가 됩니다.

참고

1The Debugging Mindset: Hypothesize, Reproduce, Fix – Good Habits for Life

2Bug Report & Debugging Template

3How do we perform effective root-cause analysis instead of just patching?

4런타임 로그 기반 Agent · Cursor (Debug Mode)

5How We Hit 83.4% on SWE-bench Verified (Part 2): Finding the Root Cause and Generating the Fix

6Issue Reproduction: Why Reproducing Bugs Matter

7Steps to Reproduce Bugs Accurately in QA Testing

10Intermittent Bug Debugging: How to Reproduce and Deal With Bugs

11How to create a Minimal, Reproducible Example - Stack Overflow Help Center

12Why Should You Care About Minimal Reproducible Examples (and how to create one)

15Reproduce Bugs Quickly with Minimal Test Case Examples

29Regression Testing: What it is, why it matters, and how to automate it with CI/CD

책 목록

OpenAI Codex 활용법: IDE·CLI·클라우드에서 코딩 에이전트로 일하기

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기