systematic-debugging
작성자 obra어떤 수정도 하기 전에 반드시 근본 원인을 파고들도록 강제하는 4단계 디버깅 워크플로와, 플래키 테스트·검증·테스트 오염을 다루는 실질적인 도구들을 제공합니다.
개요
systematic-debugging이란?
systematic-debugging 스킬은 어떤 기술적 문제에도 적용할 수 있는, 구조화된 4단계 디버깅 프로세스입니다. 테스트 실패, 프로덕션 버그, 플래키 테스트, 성능 문제, 빌드 에러, 통합 실패 등 다양한 이슈에 사용할 수 있습니다.
"빠른 한 번의 수정"이나 첫 번째 에러 라인의 코드를 바로 고치려 하기보다는, 먼저 근본 원인을 찾아낸 뒤 지속 가능한 수정을 설계하고 검증하도록 강제합니다. 실제 코드베이스에서 추출한 실전 패턴과 스크립트가 함께 제공되며, TypeScript 기반 조건형 대기(helper)와 테스트 오염원을 찾는 Bash 스크립트를 포함합니다.
핵심 원칙과 철의 법칙
systematic-debugging의 핵심은 단순합니다.
-
핵심 원칙: 수정 전에 반드시 근본 원인을 찾는다. 증상만을 고치는 수정은 실패다.
-
철의 법칙 (Iron Law):
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
조사 단계가 끝나지 않았다면, 어떤 수정도 제안하거나 적용하지 않습니다. 시간 압박, 추측, "이번 한 번만" 같은 합리화를 막도록 설계되었습니다.
이 스킬이 필요한 사람
systematic-debugging은 다음과 같은 사람을 대상으로 합니다.
- 신뢰할 수 있고 재현 가능한 수정을 원하는 JavaScript/TypeScript 개발자
- 플래키 동작, 랜덤 타임아웃, 오염된 테스트 상태를 다루는 테스트·QA 엔지니어
- 간헐적인 빌드/통합 실패를 진단하는 CI/CD 및 도구 엔지니어
- 디버깅 작업에 공통의 엄격한 프로세스를 도입하고 싶은 테크 리드 및 코드 리뷰어
빠른 땜질보다는, 근본 원인 분석의 품질을 더 중시하는 팀에 특히 잘 맞습니다.
어떤 문제를 해결하나요?
다음과 같은 상황에서 systematic-debugging 스킬을 활용하세요.
- "수정" 후에도 계속 재발하는 테스트 실패를 조사해야 할 때
- 임의의 타임아웃이나 레이스 컨디션에 의존하는 플래키 테스트를 추적할 때
- 에러를 단순히 숨기지 말고 예상치 못한 동작의 원인을 이해해야 할 때
- 느리거나 타이밍에 민감한 흐름에서 성능 문제를 진단할 때
- CI나 부하 환경에서만 발생하는 빌드/통합 실패를 디버깅할 때
- 어떤 테스트가 상태를 오염시키거나 원치 않는 파일/디렉터리를 남기는지 찾아야 할 때
저장소에는 다음과 같은 자료도 포함되어 있습니다.
- TypeScript에서
setTimeout/sleep대신 견고한 조건 기반 대기를 구현하는condition-based-waiting.md,condition-based-waiting-example.ts - 여러 계층에서의 검증을 통해 특정 버그가 구조적으로 불가능해지도록 만드는
defense-in-depth.md - 원치 않는 파일이나 상태를 만들어내는 테스트를 찾는 Bash 헬퍼
find-polluter.sh - 에러를 호출 체인을 따라 추적해 진짜 기원을 찾는
root-cause-tracing.md
systematic-debugging이 잘 맞는 경우
systematic-debugging은 다음과 같은 상황에서 특히 효과적입니다.
- 시간 압박을 받고 있어, 추측 기반 수정을 하고 싶은 유혹이 들 때
- 여러 번 시도했는데도 같은 이슈가 계속 다시 나타날 때
- 자신 또는 팀을 위한 반복 가능한 디버깅 워크플로를 만들고 싶을 때
- 플래키 테스트 스위트를 안정화하거나 오염된 테스트 환경을 정리해야 할 때
다음과 같은 경우에는 덜 적합할 수 있습니다.
- 조사 없이 한 번만 빠르게 코드 생성이나 리팩터링을 하고 싶을 때
- 여기서 다루는 기술 영역 밖을 디버깅하는 경우 (예: 비기술적 프로세스 문제)
- 단계적인 프로세스를 따를 생각이 없고, 즉흥적인 실험을 선호할 때
목표가 "지금 빨리 막고, 나중에 다시 손본다"라면 이 프로세스는 다소 엄격하게 느껴질 수 있습니다. 반대로 "한 번에 제대로 고친다"가 목표라면, systematic-debugging은 그에 맞추어 설계되어 있습니다.
사용 방법
설치 및 설정
systematic-debugging 스킬을 호환되는 에이전트나 툴 환경에 설치하려면 다음 npx 명령을 사용합니다.
npx skills add https://github.com/obra/superpowers --skill systematic-debugging
이 명령은 obra/superpowers 리포지토리의 skills/systematic-debugging 아래에 있는 스킬 정의와 관련 문서·스크립트를 가져옵니다.
설치 후에는:
- 에이전트 또는 스킬 UI에서
systematic-debugging스킬을 엽니다. - 작업 공간이 프로젝트 리포지토리, 테스트 실행 명령, 로그에 접근할 수 있는지 확인합니다.
- 다음 번들 문서와 스크립트를 볼 수 있는지 확인합니다.
SKILL.mdcondition-based-waiting.mddefense-in-depth.mdroot-cause-tracing.mdfind-polluter.sh
알아두어야 할 파일과 구성 요소
설치 여부를 판단하거나 일상적으로 사용할 때 특히 중요한 파일은 다음과 같습니다.
SKILL.md– 전체 4단계 체계적 디버깅 프로세스, 규칙, 안티 패턴을 정의합니다. 이 스킬의 핵심입니다.condition-based-waiting.md– 테스트에서 임의의 타임아웃 대신 조건 기반 대기 방식으로 전환하는 방법을 설명합니다.condition-based-waiting-example.ts–ThreadManager와 이벤트 타입을 대상으로 조건 기반 대기를 구현하는waitForEvent같은 TypeScript 유틸리티를 제공합니다.defense-in-depth.md– 엔트리 포인트, 비즈니스 로직, 환경 가드, 로깅 등 여러 계층의 검증을 통해 특정 유형의 버그를 원천 차단하는 방법을 보여줍니다.find-polluter.sh– 어떤 경로(상태 오염)를 생성한 테스트 파일을 찾기 위해 테스트를 순차적으로 실행하는 Bash 스크립트입니다.root-cause-tracing.md– 스택 트레이스에서 시작해 버그를 원래 트리거 지점까지 추적한 뒤, defense-in-depth와 결합해 해결하는 과정을 다룹니다.CREATION-LOG.md– 이 프레임워크가 어떻게 추출·강화되었는지 설명하는 메타 로그로, 설계 의도를 이해하는 데는 유용하지만, 일상 사용에는 필수는 아닙니다.
JavaScript/TypeScript 개발자는 TypeScript 예제와 Bash 스크립트를 직접 프로젝트에 맞게 변형해 사용할 수 있습니다.
4단계 워크플로 실행하기
systematic-debugging 프로세스는 SKILL.md에 설명된 4개의 필수 단계로 구성되어 있습니다. 각 단계를 완료한 뒤에만 다음 단계로 넘어갈 수 있습니다.
1단계 – 근본 원인 조사
코드, 설정, 테스트를 수정하기 전에 다음을 수행합니다.
- 에러 메시지와 로그를 꼼꼼히 읽습니다.
- 스택 트레이스나 경고를 대충 넘기지 않습니다.
- 라인 번호, 파일 경로, 에러 코드를 기록합니다.
- 이슈를 안정적으로 재현합니다.
- 최소한의, 신뢰할 수 있는 재현 명령을 만듭니다.
- 필요한 입력값과 환경 요소를 기록합니다.
이 단계에서는 수정안을 제안하거나 구현하지 않습니다. 정확히 무엇이, 어디서, 어떤 조건에서 실패하는지 이해하는 것이 목표입니다.
2단계 – 패턴 분석
재현이 안정적으로 가능해졌다면:
- 입력, 설정, 환경 등 한 번에 한 요소씩 바꿔가며 결과가 어떻게 달라지는지 확인합니다.
- 정상 동작과 실패 동작이 갈리는 경계 조건을 찾습니다.
- 로그, 어서션, 임시 계측(instrumentation)을 활용해 실패 경로를 좁혀 나갑니다.
2단계가 끝날 즈음에는 단순한 에러 메시지를 넘어, 문제의 형태와 그것을 트리거하는 조건을 이해하고 있어야 합니다.
3단계 – 가설 수립과 설계
이제 가설을 세울 수 있습니다.
- 근본 원인이 무엇이라고 생각하는지 명확히 서술합니다. (데이터 플로우, 누락된 검증, 타이밍 문제, 잘못된 경로 등)
- 그 근본 원인을 해결할 단일하고 집중된 변경 사항을 설계합니다.
- 앞서 만든 재현 절차를 활용해 가설을 어떻게 검증할지 계획합니다.
가설이 틀린 것으로 드러나면, 새로운 추측성 수정을 덧붙이지 말고 다시 조사/분석 단계로 돌아갑니다.
4단계 – 구현과 검증
명확한 가설이 세워진 이후에만 코드나 설정을 수정합니다.
- 근본 원인을 직접 겨냥하는 최소한의 변경만 적용합니다.
- 최소 재현 절차를 실행한 뒤, 더 넓은 테스트 스위트를 돌립니다.
- 다음 문서를 참고해 보완합니다.
- 여러 계층에 검증을 추가하는
defense-in-depth.md - 진짜 근원을 수정하고 있는지 확인하는
root-cause-tracing.md
- 여러 계층에 검증을 추가하는
- 부하 환경, CI, 2단계에서 확인한 엣지 케이스 등에서도 수정이 견고하게 동작하는지 확인합니다.
수정이 기대한 대로 동작하지 않는다면, 변경을 더 쌓지 말고 앞선 단계로 돌아갑니다.
프로젝트에서 디버깅 유틸리티 사용하기
플래키 테스트를 위한 조건 기반 대기 (JavaScript/TypeScript)
setTimeout이나 sleep에 의존하는 플래키 테스트는 머신이 느리거나 빠르거나 부하가 걸린 상태에서 쉽게 깨집니다. condition-based-waiting.md와 condition-based-waiting-example.ts는 "시간 추측" 대신, 원하는 조건이 충족될 때까지 기다리는 패턴을 제시합니다.
일반적인 마이그레이션 예시는 다음과 같습니다.
// ❌ Before: guessing timing
await new Promise(r => setTimeout(r, 50));
const result = getResult();
expect(result).toBeDefined();
// ✅ After: waiting for condition
await waitFor(() => getResult() !== undefined);
const result = getResult();
expect(result).toBeDefined();
제공되는 condition-based-waiting-example.ts에는 다음과 같은 헬퍼가 포함되어 있습니다.
export function waitForEvent(
threadManager: ThreadManager,
threadId: string,
eventType: LaceEventType,
timeoutMs = 5000
): Promise<LaceEvent> { /* ... */ }
이 패턴을 자신의 테스트 인프라에 맞게 적용하려면:
- 유틸리티를 프로젝트의 테스트 헬퍼로 복사하거나 재구현합니다.
- 임의의
setTimeout/sleep호출을 조건 기반 대기로 교체합니다. - 테스트 스위트를 다시 실행해 플래키 현상이 줄어드는지 확인합니다.
이는 무작정 타임아웃을 늘리는 대신 근본 원인을 제거한다는 systematic-debugging의 목표를 직접적으로 지원합니다.
find-polluter.sh로 오염된 테스트 찾기
테스트가 불필요한 파일이나 디렉터리를 남기거나, 전역 상태를 오염시키는 경우 find-polluter.sh는 그 원인이 되는 테스트를 찾아내는 데 도움을 줍니다.
사용법 (프로젝트 루트에서, 인자를 상황에 맞게 조정):
./find-polluter.sh <file_or_dir_to_check> <test_pattern>
# Example
./find-polluter.sh '.git' 'src/**/*.test.ts'
이 스크립트는 다음을 수행합니다.
- 패턴에 매칭되는 테스트 파일을 찾습니다.
- 각 테스트를
npm test <file>로 하나씩 실행합니다. - 각 실행 후 대상 파일 또는 디렉터리가 존재하는지 확인합니다.
- 해당 경로를 처음 생성한 테스트를 찾아, 다시 실행하고 조사할 수 있는 명령과 함께 보고합니다.
이는 상태 오염을 재현하고 분리하는 안정적인 방법을 제공하므로, systematic-debugging의 1단계와 2단계에 자연스럽게 통합됩니다.
defense-in-depth 검증 적용하기
조사 과정에서 잘못된 데이터나 잘못된 가정을 원인으로 버그가 발생했다면, defense-in-depth.md는 여러 계층에 검증을 배치할 것을 권장합니다.
- 엔트리 포인트 검증 – API, CLI, UI 핸들러 등 경계 지점에서 명백히 잘못된 입력을 거부합니다.
- 비즈니스 로직 검증 – 특정 연산에 대해 데이터가 의미 있는지 확인합니다.
- 환경 가드 – 잘못된 환경이나 경로에서 위험한 작업이 수행되지 않도록 방지합니다.
- 진단용 로깅 – 문제가 새어 나왔을 때 유용한 맥락 정보를 남깁니다.
예를 들어, workingDirectory 인자를 검증하는 코드는 다음과 같습니다.
function createProject(name: string, workingDirectory: string) {
if (!workingDirectory || workingDirectory.trim() === '') {
throw new Error('workingDirectory cannot be empty');
}
if (!existsSync(workingDirectory)) {
throw new Error(`workingDirectory does not exist: ${workingDirectory}`);
}
if (!statSync(workingDirectory).isDirectory()) {
throw new Error(`workingDirectory is not a directory: ${workingDirectory}`);
}
// ... proceed
}
4단계에서 수정을 구현할 때 이런 패턴을 사용하면, 다른 코드 경로를 통해 동일한 버그가 다시 나타날 가능성을 크게 줄일 수 있습니다.
이 스킬을 쓰지 않아도 되는 경우
다음과 같은 경우에는 systematic-debugging을 건너뛰거나 나중으로 미루는 것이 나을 수 있습니다.
- 프로토타입을 만들고 있어, 버그와 일회성 코드를 의도적으로 감수하는 경우
- (개발 중 발견된 오타처럼) 문제가 사소하고 원인이 명확해, 엄격한 4단계 프로세스를 적용할 가치가 없을 때
- 조건 기반 대기 같은 개별 유틸리티만 필요하고, 전체 프로세스까지 도입할 필요가 없을 때
이런 경우에도 철의 법칙은 유용한 기준점이 됩니다. 추측성 수정을 몇 개나 쌓고 있는 자신을 발견한다면, 이제 systematic-debugging으로 전환할 때일 수 있습니다.
FAQ
systematic-debugging은 내 워크플로를 어떻게 바꾸나요?
에러 메시지를 보고 바로 코드를 고치는 대신, systematic-debugging은 구현에 들어가기 전에 조사, 패턴 분석, 가설 수립을 거치도록 요구합니다. 실제로는 다음과 같은 변화를 의미합니다.
- 코드를 건드리기 전에 신뢰할 수 있는 재현 절차를 확보합니다.
- 조건을 바꿔가며 문제 공간을 이해합니다.
- 검증된 각 가설마다 하나의 집중된 수정만 작성합니다.
그 결과, 롤백이 줄고 숨은 회귀 버그가 적어지며, 디버깅에 드는 시간이 더 예측 가능해집니다.
systematic-debugging 스킬은 어떻게 설치하나요?
npx skills 명령을 사용합니다.
npx skills add https://github.com/obra/superpowers --skill systematic-debugging
설치 후에는 에이전트나 스킬 디렉터리에서 스킬을 연 뒤, 전체 프로세스가 담긴 SKILL.md와 패턴·예제가 들어 있는 보조 markdown 파일들을 차례로 살펴보세요.
systematic-debugging은 JavaScript와 TypeScript 디버깅을 지원하나요?
네. 프레임워크 자체는 언어에 구애받지 않지만, 리포지토리에는 JavaScript/TypeScript에 초점을 맞춘 구체적인 유틸리티가 포함되어 있습니다.
- 테스트에서 조건 기반 대기를 구현하는
condition-based-waiting-example.ts - TypeScript 예제로 설명된
defense-in-depth.md와root-cause-tracing.md의 패턴들 - 기본적으로
npm test를 사용하며 일반적인 JS/TS 테스트 러너와 잘 맞는find-polluter.sh
이 유틸리티들은 프로젝트 구조와 도구 체인에 맞게 자유롭게 변형해서 사용할 수 있습니다.
플래키 테스트 자동화에도 systematic-debugging을 사용할 수 있나요?
네. 이 사용 사례는 systematic-debugging의 핵심 강점 중 하나입니다. 다음을 함께 활용하세요.
- 플래키 현상을 조사하고 이해하기 위한
SKILL.md의 4단계 프로세스 - 타이밍 추측을 조건 기반 대기로 바꾸는
condition-based-waiting.md와 TypeScript 예제 - 상태 오염이나 예상치 못한 파일 생성을 유발하는 테스트를 찾는
find-polluter.sh
이 도구들을 조합하면 불안정한 테스트를 안정적이고 결정적인 검증으로 전환할 수 있습니다.
systematic-debugging은 테스트에만 쓰나요, 프로덕션 버그에도 쓸 수 있나요?
이 프로세스는 모든 종류의 기술적 이슈에 적용할 수 있습니다.
- 테스트 실패 및 플래키 테스트
- 프로덕션 버그와 인시던트
- 성능 문제
- 빌드 및 통합 실패
예제와 유틸리티는 주로 테스트·개발 워크플로에 초점을 맞추고 있지만, 각 단계와 원칙은 프로덕션 시나리오도 포함하도록 명시적으로 설계되어 있습니다.
시간 압박이 심한데, 빠른 수정만 필요하면 어떻게 하나요?
이 스킬은 바로 그런 "빠른 한 번의 수정" 충동에 맞서기 위해 작성되었습니다. 다음과 같은 점을 강조합니다.
- 근본 원인 조사 없이 서두르면, 되돌리기와 재작업이 늘어납니다.
- 증상만을 고치는 수정은 종종 새로운 문제를 만들어냅니다.
실제 경험상, 긴급한 인시던트 상황에서도 1단계와 2단계를 거치는 데 몇 분 투자하는 편이 전체적으로 시간을 절약하는 경우가 많습니다.
네 단계 모두를 매번 꼭 따라야 하나요?
systematic-debugging의 의도는 단계를 건너뛰는 것이 예외가 되도록 하는 것입니다. (예를 들어, 작은 리팩터 중 실수를 바로 알아챈 경우처럼) 문제가 사소하고 완전히 이해된 상황에서는 단계를 압축할 수 있습니다. 하지만 다음과 같은 경우에는:
- 이슈가 반복적으로 재발한다면
- 왜 이런 일이 일어나는지 완전히 이해하지 못했다면
- 이전 수정이 실패한 적이 있다면
…네 단계 전체를 따를 것을 강력히 권장합니다.
root-cause tracing과 defense-in-depth는 어떤 관계인가요?
root-cause-tracing.md는 눈에 보이는 에러에서 시작해 호출 체인을 따라가며 버그의 원래 트리거 지점까지 추적하는 방법을 설명합니다. 이어서 defense-in-depth.md는 다음과 같은 방식으로 비슷한 버그를 예방하는 방법을 보여줍니다.
- 진짜 근원에서 문제를 수정합니다.
- 여러 계층에 검증을 추가합니다.
예를 들어, 잘못된 디렉터리에서 실행된 git init이 실패했다면, tracing을 통해 어느 함수가 잘못된 경로를 전달했는지 찾고, defense-in-depth로 잘못된 경로를 더 이른 단계에서 걸러내는 검증과 가드를 추가합니다.
리포에서 코드를 복사하지 않고도 이 스킬을 활용할 수 있나요?
네. systematic-debugging의 핵심 가치는 SKILL.md에 정의된 구조화된 디버깅 프로세스 자체입니다. 다음과 같이 사용할 수 있습니다.
- 자신의 환경에서 네 단계와 규칙을 그대로 따라갑니다.
- 조사와 분석 패턴을 어떤 언어·스택에든 적용합니다.
TypeScript와 Bash 헬퍼는 특히 JS/TS 및 유닉스 계열 환경에서 속도를 높여주는 선택적 도구일 뿐입니다.
systematic-debugging에 포함된 내용을 모두 보려면 어디서 확인하나요?
설치 후 obra/superpowers 리포지토리의 skills/systematic-debugging 아래에서 파일/리포지토리 뷰를 열어보세요. 특히 확인할 파일은 다음과 같습니다.
SKILL.mdcondition-based-waiting.mdcondition-based-waiting-example.tsdefense-in-depth.mdroot-cause-tracing.mdfind-polluter.sh
이 파일들을 통해 전체 systematic-debugging 워크플로와, 디버깅 및 테스트 안정화를 위한 구체적인 도구들을 모두 살펴볼 수 있습니다.
