Superpowers 플러그인 가이드 Part 3: 품질 보증 스킬 — TDD, Systematic Debugging, Verification, Code Review
이 글은 Claude Opus 4.7 을 이용해 초안이 작성되었으며, 이후 퇴고를 거쳤습니다.
1편 에서 Superpowers 의 개요와 설치를, 2편 에서 핵심 워크플로우를 다뤘습니다. 3편은 그 워크플로우 안에서 작동하면서 에이전트의 합리화와 빠져나갈 구멍을 차단 하는 품질 보증 스킬들을 자세히 들여다봅니다.
이 스킬들은 모두 “Iron Law” 라는 이름의 명문화된 규칙을 갖고 있다는 공통점이 있습니다. 그리고 각 스킬의 문서 안에는 “Red Flags” 표 가 들어 있어, 에이전트가 빠져나가려 할 때 흔히 하는 합리화의 패턴들을 그대로 박아두었습니다. 이게 결과적으로 모델의 행동을 바꿉니다.
Test-Driven Development — “테스트 없이 짠 코드는 삭제하라”#
test-driven-development 스킬은 Superpowers 의 가장 엄격한 스킬 중 하나입니다. 슬로건은 단순합니다.
Write the test first. Watch it fail. Write minimal code to pass.
핵심 원칙도 짧습니다.
If you didn’t watch the test fail, you don’t know if it tests the right thing.
Iron Law#
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
규칙이 무자비할 정도로 강한 이유는, 모델이 “이번 한 번만” 이라는 식으로 빠져나가는 경향이 있기 때문입니다. 그래서 이렇게까지 박혀 있습니다.
Write code before the test? Delete it. Start over.
- Don’t keep it as “reference”
- Don’t “adapt” it while writing tests
- Don’t look at it
- Delete means delete
“참고용으로라도 남기지 마라, 보지도 마라” 는 부분이 특히 인상적입니다. 모델이 자기가 짠 코드를 옆에 두면 결국 그 형태에 맞춰 테스트를 작성하게 되고, 그러면 “테스트가 잘못된 걸 잡아낸다” 는 TDD 의 본질이 깨지기 때문입니다.
RED-GREEN-REFACTOR 사이클#
flowchart LR
A[RED<br/>실패하는 테스트 작성] --> B{올바르게<br/>실패하는가?}
B -->|아니오| A
B -->|예| C[GREEN<br/>최소 구현]
C --> D{모든 테스트<br/>통과?}
D -->|아니오| C
D -->|예| E[REFACTOR<br/>정리]
E --> F{여전히<br/>green?}
F -->|아니오| E
F -->|예| G[다음 사이클]
G --> A
style A fill:#FFB6C1,color:#000000
style B fill:#FFD700,color:#000000
style C fill:#90EE90,color:#000000
style D fill:#FFD700,color:#000000
style E fill:#87CEEB,color:#000000
style F fill:#FFD700,color:#000000
style G fill:#DDA0DD,color:#000000
각 단계가 별도의 작업으로 분리되어 있다는 점이 중요합니다. “RED 와 GREEN 을 한 번에 처리” 하지 않습니다. 테스트를 작성하고 → 실행해서 실패를 눈으로 본 다음에야 → 구현으로 넘어갑니다. 이 분리가 2편 에서 본 “bite-sized task” 가 왜 5분 단위인지의 이유 중 하나입니다.
“테스트 작성이 어려울 때” 의 해석#
코드를 짜다 보면 “테스트 쓰기가 너무 어려운 케이스” 가 등장합니다. 그럴 때 보통의 에이전트는 “이건 테스트하기 어려운 영역이라” 며 TDD 를 건너뜁니다. Superpowers 의 스킬은 이를 다르게 해석합니다.
테스트하기 어렵다는 건, 그 코드의 설계가 잘못되었다는 신호다. 설계를 바꿀 기회로 받아들여라.
테스트하기 어려운 코드는 대개 다음 중 하나입니다.
- 책임이 너무 많이 얽혀 있다 (SRP 위반)
- 외부 의존성이 직접 박혀 있다 (의존성 주입 부재)
- 부수효과(side effect) 가 제어 불가능하다
이 신호를 잡아 설계를 바꾸는 것이 TDD 의 본래 의도라는 점을, 스킬 문서가 단호하게 못박습니다.
Systematic Debugging — “추측하지 말고 root cause 부터”#
systematic-debugging 스킬은 버그가 발견되거나 테스트가 실패할 때 자동으로 호출됩니다. Iron Law 는 다음과 같습니다.
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
에이전트가 가장 자주 빠지는 함정은 “이게 원인 같다” 는 추측에 기반한 패치 남발입니다. 한 번 패치해 보고 안 되면 다른 패치, 또 안 되면 또 다른 패치 — 이러는 동안 코드는 점점 누더기가 되고 진짜 원인은 더 멀어집니다.
4단계 프로세스#
각 단계는 다음 단계로 넘어가기 전에 반드시 완료 되어야 합니다.
Phase 1: Root Cause Investigation#
- 에러 메시지를 정독한다. 스택 트레이스 전체를 본다. 라인 번호, 파일 경로, 에러 코드를 기록한다.
- 일관되게 재현한다. 재현이 안 되면 다음 단계로 갈 수 없다.
- 차이점을 좁힌다. 언제부터 깨졌나? 어떤 환경에서 깨지나? 무엇이 다른가?
- 가설을 세운다. 단, 가설은 “fix 를 제안할 자격” 이 아니다. 가설을 검증할 증거를 모은다.
Phase 2: Hypothesis Validation#
가설을 검증하는 단계입니다. 로그 추가, 디버거 부착, 작은 실험. 가설이 맞는지 틀리는지 까지 확인합니다. 한 가설이 그럴듯해 보여도 다른 가설을 배제하지 않으면 위험합니다.
Phase 3: Fix Design#
이 시점에서야 비로소 수정안을 설계합니다. 다음을 고려합니다.
- 이 수정이 다른 부분에 영향을 주지 않는가?
- 비슷한 root cause 가 다른 곳에도 있는가? (defense-in-depth)
- 회귀 방지 테스트를 어떻게 추가할 것인가?
Phase 4: Fix Verification#
수정 적용 후, 다음을 검증합니다.
- 원래 증상이 재현되지 않는가?
- 회귀 테스트가 RED-GREEN 사이클을 정확히 보여주는가?
- 인접 영역의 테스트가 깨지지 않았는가?
“한 번 더 패치해 볼까” 합리화 차단#
스킬의 Red Flags 표에는 다음과 같은 항목들이 들어 있습니다.
| 합리화 | 실제로는 |
|---|---|
| “한 줄만 고치면 될 것 같은데” | 한 줄짜리 수정도 root cause 가 있다. 조사하라. |
| “시간이 없으니 일단 패치하고 나중에” | 추측 패치는 결과적으로 더 느리다. systematic 이 빠르다. |
| “이전 수정이 안 됐으니 다른 시도를” | 이전 수정이 왜 실패했는지부터 분석하라. |
| “이건 너무 단순한 버그라” | 단순해 보이는 버그도 root cause 가 있다. |
이 표가 박혀있기 때문에, 에이전트가 “이번엔 빨리 가자” 며 빠져나가려 해도 즉시 자기 합리화를 자각하고 다시 프로세스로 돌아옵니다.
Verification Before Completion — “증거 없이 통과 주장 금지”#
verification-before-completion 스킬은 에이전트가 “완료했습니다, 테스트 통과합니다” 라고 말하기 전에 이번 메시지에서 검증 명령을 실행했는지 를 강제합니다.
Iron Law#
NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE
“이번 메시지에서 검증 명령을 실행하지 않았다면, 통과한다고 주장할 수 없다.” 라는 의미입니다. 이전 메시지에서 통과했더라도, 그 이후에 코드를 한 줄이라도 수정했다면 다시 검증해야 합니다.
Gate Function#
스킬은 다음과 같은 “통과 함수” 를 강제합니다.
BEFORE claiming any status or expressing satisfaction:
1. IDENTIFY: 이 주장을 증명할 명령이 무엇인가?
2. RUN: 그 명령을 (신선하게, 전체) 실행한다.
3. READ: 전체 출력을 읽고, exit code 와 실패 수를 확인한다.
4. VERIFY: 출력이 주장을 뒷받침하는가?
- 아니면: 증거와 함께 실제 상태를 말한다.
- 맞으면: 증거와 함께 주장한다.
5. ONLY THEN: 주장한다.
흔한 실패 패턴#
스킬 안의 표가 정확합니다.
| 주장 | 필요한 증거 | 부족한 것 |
|---|---|---|
| 테스트 통과 | 테스트 명령 출력: 0 failures | 이전 실행, “통과할 것 같다” |
| 린터 깨끗 | 린터 출력: 0 errors | 부분 확인, 추정 |
| 빌드 성공 | 빌드 명령: exit 0 | 린터 통과, 로그가 괜찮아 보임 |
| 버그 수정됨 | 원래 증상 테스트: 통과 | 코드 변경됨, “수정됐겠지” |
| 회귀 테스트 작동 | RED-GREEN 사이클 검증됨 | 테스트가 한 번 통과함 |
| Agent 완료 | VCS diff 가 변경을 보여줌 | Agent 가 “성공” 보고 |
특히 마지막 줄이 중요합니다. “Agent 가 성공이라고 말했다” 는 증거가 아닙니다. 메인 에이전트는 subagent 의 보고를 그대로 믿지 않고, git diff 등으로 실제 변경을 확인해야 합니다.
Java/Go 백엔드에서의 적용#
Java 프로젝트라면 다음과 같은 명령을 매번 신선하게 실행해야 합니다.
./gradlew clean test
./gradlew build
Go 프로젝트라면:
go test -race ./...
go build ./...
go vet ./...
캐시된 결과나 부분 실행은 증거로 인정되지 않습니다. -race 같은 옵션도 한번 빼먹으면 race condition 버그가 끼어듭니다.
Code Review — Requesting & Receiving#
Superpowers 는 코드 리뷰를 워크플로우의 정규 단계로 편입시킵니다. requesting-code-review 와 receiving-code-review 두 스킬이 짝을 이룹니다.
Requesting Code Review#
언제 리뷰를 요청하는가?
Mandatory (필수):
- subagent-driven development 의 각 태스크 완료 후
- 주요 기능 구현 완료 후
- main 으로 merge 전
Optional but valuable (선택이지만 유익):
- 막혔을 때 (새로운 관점)
- 리팩토링 전 (베이스라인 체크)
- 복잡한 버그 수정 후
리뷰 요청 방식은 다음과 같습니다.
- Git SHA 를 얻는다.
BASE_SHA=$(git rev-parse HEAD~1) # or origin/main HEAD_SHA=$(git rev-parse HEAD) - Task tool 로 code reviewer subagent 를 dispatch 한다. 다음 정보를 정확히 채워 넣은 프롬프트로:
{DESCRIPTION}— 무엇을 만들었는지{PLAN_OR_REQUIREMENTS}— 무엇을 했어야 하는지{BASE_SHA}/{HEAD_SHA}— 리뷰 범위
- Reviewer subagent 는 메인 세션의 컨텍스트를 받지 않습니다. 정확히 위 정보만 가지고 독립적으로 리뷰합니다.
이 “독립성” 이 핵심입니다. 메인 에이전트가 “내가 어떻게 짰는지” 를 reviewer 에게 설명해버리면, reviewer 가 그 설명에 영향받아 “그렇게 짠 이유가 있겠지” 하고 넘어가 버립니다. 독립적 리뷰만이 진짜 이슈를 잡아냅니다.
Severity 기반 리포트#
Code reviewer 는 발견한 이슈를 severity 별로 분류해 보고합니다.
- Critical — merge 전에 반드시 수정해야 함 (보안 취약점, 데이터 손실 위험, 명백한 버그)
- High — 수정 권장 (성능 이슈, 견고성 부족)
- Medium — 개선 권장 (코드 품질, 가독성)
- Low — 참고용 (스타일, 네이밍 제안)
Critical 이슈가 있으면 다음 단계 진행이 차단됩니다.
Receiving Code Review#
리뷰를 받았을 때의 흐름도 스킬화되어 있습니다. receiving-code-review 는 다음을 강조합니다.
- 모든 코멘트를 평가하고 응답한다 (무시하지 않는다)
- “이건 내 의도였다” 라고 합리화하기 전에, 진짜로 reviewer 가 맞는 건 아닌지 검토한다
- 동의하지 않는 경우 명확한 근거와 함께 응답한다
- 동의한 경우 수정을 적용하고, 수정 후 다시 검증한다
실전 시나리오: 프로덕션 버그 잡기#
이 모든 스킬이 어떻게 어우러지는지, Java 백엔드 프로덕션 버그 시나리오로 살펴봅니다.
상황: Spring Boot 기반 API 서버에서 사용자 결제 트랜잭션이 가끔 중복으로 처리된다는 보고가 들어왔습니다. 일주일에 2~3건 발생합니다.
사용자: 결제 중복 처리 버그가 났어. 일주일에 2~3건 정도. 로그는 여기야 [...]
Phase 1: Root Cause Investigation (systematic-debugging 자동 호출)#
에이전트는 곧바로 패치 시도를 하지 않습니다. 대신:
- 로그를 정독합니다. 트랜잭션 ID, 타임스탬프, 요청 헤더를 모두 본다.
- 재현을 시도합니다. 로컬에서 동시 요청을 보내는 부하 테스트를 작성한다.
- 재현 성공. 동시 요청 시 약 1% 확률로 같은 결제가 두 번 처리됨.
- 차이점 분석.
PaymentService.process()내부에서 idempotency key 체크와 결제 실행 사이에 race window 가 존재. - 가설: 분산 락이나 DB unique constraint 가 누락되었을 것.
Phase 2: Hypothesis Validation#
에이전트는 다음을 확인합니다.
payments테이블의 인덱스 확인:idempotency_key에 UNIQUE 제약이 없음. 가설 일치.- 다른 가설(클라이언트 재시도 로직)도 점검 — 클라이언트 코드 확인 결과, 5초 timeout 후 재시도가 들어옴. 이게 race 와 결합해 중복을 일으킴.
Phase 3: Fix Design#
에이전트는 두 단계 방어를 제안합니다 (defense-in-depth).
- DB 레벨:
payments.idempotency_key에 UNIQUE 제약 추가 + 마이그레이션 - 애플리케이션 레벨:
PaymentService.process()의 idempotency 처리 로직을 SELECT FOR UPDATE 기반으로 변경
여기서 brainstorming 스킬이 한 번 더 트리거됩니다 — 마이그레이션은 dangerous 한 작업이라 사용자 승인이 필수입니다. 특히 운영 중인 테이블에 UNIQUE 제약을 추가할 때 기존 중복 행이 있으면 마이그레이션이 실패하므로, 그 처리 방안을 사용자와 합의해야 합니다.
Phase 4: Fix Verification & TDD#
test-driven-development 가 자연스럽게 호출됩니다.
- RED: 동시 요청 시 중복 결제를 재현하는 통합 테스트 작성, 실행 → 실패 확인.
- GREEN: SELECT FOR UPDATE 적용. 테스트 실행 → 통과 확인.
- REFACTOR: 중복된 idempotency 체크 로직 정리.
이 과정에서 verification-before-completion 이 매 단계 자동 호출되어, “테스트 통과합니다” 라는 보고 전에 실제 명령 실행을 강제합니다.
Code Review#
태스크가 완료되면 requesting-code-review 가 자동 호출됩니다. Code reviewer subagent 가 독립적으로 다음을 점검합니다.
- SELECT FOR UPDATE 가 deadlock 위험을 만들지 않는가?
- 트랜잭션 timeout 설정이 적절한가?
- UNIQUE 제약 마이그레이션이 운영 환경에서 안전한가?
- 회귀 테스트가 실제로 race 를 잡는가?
Critical 이슈가 발견되면 다음 단계로 못 갑니다. 모두 해소되면 finishing-a-development-branch 가 호출되어 PR 을 만듭니다.
이 스킬들이 모이면 만드는 효과#
각 스킬이 따로 보면 “그냥 좋은 관행” 처럼 보이지만, 함께 자동으로 작동하면 다음과 같은 효과가 나타납니다.
- “빠른 패치” 의 유혹 차단 — systematic-debugging 으로 인해 추측 패치 불가능
- “테스트 나중에” 의 유혹 차단 — TDD Iron Law 로 인해 코드 먼저 짤 수 없음
- “통과한 것 같아” 의 유혹 차단 — verification-before-completion 으로 인해 거짓 보고 불가
- “내가 짠 코드는 좋은 코드” 의 유혹 차단 — 독립 reviewer subagent 로 인해 자기 옹호 불가
이 네 가지가 합쳐지면 결과적으로 사람이 옆에서 감독하지 않아도 결과 품질이 일정 수준 이상을 유지 합니다. 이게 Superpowers 의 가치 명제의 핵심입니다.
다음 편 미리보기#
4편 에서는 마지막으로 명시적 호출 vs 자동 트리거 를 비교 분석합니다.
/superpowers:xxx형태로 직접 호출해야 하는 경우 (재호출 강제, 디버깅, skill 점검 등)- 자동 트리거에 맡겨도 되는 경우
- 자동 트리거가 작동하지 않을 때의 트러블슈팅
- CLAUDE.md/AGENTS.md 로 동작을 오버라이드하는 방법
- Java/Go 백엔드 개발 현장에서의 실용 팁과 한계
References#
- Superpowers 저장소: https://github.com/obra/superpowers
test-driven-development스킬: https://github.com/obra/superpowers/blob/main/skills/test-driven-development/SKILL.mdsystematic-debugging스킬: https://github.com/obra/superpowers/blob/main/skills/systematic-debugging/SKILL.mdverification-before-completion스킬: https://github.com/obra/superpowers/blob/main/skills/verification-before-completion/SKILL.mdrequesting-code-review스킬: https://github.com/obra/superpowers/blob/main/skills/requesting-code-review/SKILL.mdreceiving-code-review스킬: https://github.com/obra/superpowers/blob/main/skills/receiving-code-review/SKILL.md