TDD as Small Deliberate Steps — AI 시대 garbage 누적의 차단막
Kent Beck Test-Driven Development By Example (2002) + Matt 강연의 "rate of feedback is your speed limit". 한 step에 한 행동, 매 step마다 verify. 큰 task는 garbage 누적의 root. overview의 🔄 Process 축. AI 시대에 가장 직접적 가치 — AI agent의 garbage 누적을 test로 차단. named-ownership의 success criteria가 정확히 test로 implementation.
한 줄
작은 step + 매 step마다 verify. 한 step = 한 행동 = 한 test. Beck의 1세대 TDD가 Matt의 *"rate of feedback is your speed limit"*로 AI 시대에 부활. AI agent의 specs → code 1차ok → 2차worse → 3차garbage 누적 패턴을 매 step의 test fail이 차단. Anthropic이 prompt에 *"It is unacceptable to remove or edit tests"*를 박은 이유가 정확히 여기.
⚛️ 철학
원칙의 왜. 더 깊은 root와의 연결.
Beck 1세대 TDD
Kent Beck Test-Driven Development By Example (2002)의 원전 명제:
Red → Green → Refactor 사이클을 작은 step으로 반복.
- Red: 실패하는 test를 먼저 작성
- Green: test가 통과하는 가장 단순한 코드
- Refactor: 동작 유지하며 design 개선
핵심 명제:
한 step = 한 행동 = 한 test. 이 단위가 너무 커지면 부패가 누적된다.
Matt 강연의 AI 시대 표현
sources/key-articles-summary#2. mattpocock/skills — README 핵심|mattpocock/skills README에서 Beck 명제 인용:
"Always take small, deliberate steps. The rate of feedback is your speed limit. Never take on a task that's too big."
→ ***"Rate of feedback이 너의 speed limit"***이 핵심. 작은 step + 빠른 feedback = 빠른 속도 (역설). 큰 step + 느린 feedback = garbage 누적 + 결국 더 느려짐.
Specs → code 자동 generation의 garbage 누적
research/stateless-llm-sdk/software-fundamentals-thesis|Matt thesis 명제 다시:
1차 ok → 2차 worse → 3차 garbage
이 누적 패턴의 mechanism:
- 1차: spec에서 코드 generate. 작동.
- 2차: spec 일부 변경 + 같은 코드를 다시 generate. 옛 코드의 약점이 새 코드에 누적.
- 3차: 또 변경. 누적된 약점 + 새 약점 → 동작 X.
TDD가 차단하는 정확한 자리 — 매 step의 test가 부패가 누적되기 전 발견. small + deliberate = 부패의 작은 단위 차단.
다른 root와의 연결
- named-ownership — Test가 success criteria의 가장 작은 단위. owner가 작성하는 verify_completion 함수가 곧 test
- ship-and-rollback-as-normal — 각 step이 ship-and-rollback의 가장 작은 단위. test fail = rollback signal
- reversibility — 각 step이 reversible. test fail 시 git revert
- strategic-vs-tactical-programming — test 작성이 strategic 활동, code 작성이 tactical
- information-leak-vs-abstraction — test가 leak 발견 도구. interface와 다른 행동을 test가 잡아냄
- tracer-bullets — 작은 end-to-end가 첫 test의 단위
🧱 추상적 작동 구조
Red-Green-Refactor cycle:
Big bang vs Small Steps
Rate of feedback과 속도의 역설
Big step + 느린 feedback:
step당 시간 길음 → 빠르게 보임
but: 매 step에서 *몇 일 후* 문제 발견 → debug 시간 폭발
→ *총 시간*이 길어짐
Small step + 빠른 feedback:
step당 시간 짧음 → 느리게 보임
but: 매 step에서 *즉시* 문제 발견 → debug 시간 0
→ *총 시간*이 짧아짐
→ Speed limit = rate of feedback. 빠르려면 느려 보이는 작은 step이 답.
Anthropic harnesses의 test 보호 prompt
"It is unacceptable to remove or edit tests because this could lead to missing or buggy functionality."
이 prompt가 강하게 박혀 있는 이유:
AI agent가 test fail에 직면 → 두 선택
(A) code를 고침 (정상 답)
(B) test를 고침/제거 (anti-pattern)
AI는 (B)에 빠지기 쉬움
- "test가 잘못됐나봐"
- "이 test는 무시해도 될 것 같아"
→ 결과: code는 fail인데 test는 통과 (false success)
→ Anthropic이 자체 production AI를 위해 도달한 답이 "test 보호". Beck의 1세대 TDD가 AI 시대 prompt 형태로 부활.
⚠️ 약점/한계
원칙의 적용 한계. 잘못 적용 시 함정.
1. Test 작성 비용
매 행동에 test 1개. 코드 양이 2배 증가. 작은 시도에는 over-engineering.
해결: Scale별 차등. 1회용 = test 없음. Production = 강제 TDD. 중간은 자율.
2. Test가 도메인 명세를 보호하지 않음
Test는 내가 정의한 행동을 verify. 옳은 행동을 정의했나는 별 문제. 잘못된 spec에 맞춘 test는 잘못된 행동을 correct하게 만듦.
해결: 도메인 expert와 함께 test 작성 (ubiquitous-language|UL 정합). Test name이 도메인 vocabulary로 — test_정원_초과시_대기열_등록.
3. UI / 실험 코드에 부적합
UI는 시각적 검증이 main. 실험 코드는 반복 사용 안 함. TDD 적용 비용 > 가치.
해결: 영역별 test 전략. UI = visual regression test (별 도구). 실험 = no test, just delete.
4. Testing-induced design damage
David Heinemeier Hansson (Rails 창시자)의 비판: TDD 강제가 test에 맞춘 design으로 왜곡. 진짜 좋은 design이 아니라 test 가능한 design. 추상화가 모킹 가능성에 끌려감.
해결: Refactor 단계의 자유도 보장. test가 design을 강제하지 않게. test가 변하지 않으면 design은 자유.
5. AI 시대 specific — AI가 test fail하면 test를 바꾸는 함정
Anthropic prompt가 박는 이유. AI agent의 자연 경향:
- "이 test는 잘못된 것 같다"
- "이 test를 무시하자"
- "이 test를 더 너그럽게 바꾸자"
해결: Test 변경 권한을 AI에게 주지 않기. test는 owner의 strategic 자산. AI는 code만 변경. v1.0의 권한 모델이 이 mechanism.
6. Mock 남용으로 실제와 test의 괴리
Test 통과를 위해 모든 의존을 mock. 결과: test는 통과, 실제는 fail (production에서 처음 발견).
해결: Integration test와 unit test의 균형. Test pyramid — unit (많음) + integration (중간) + E2E (적음). 모든 layer에서 검증.
7. Premature TDD
도메인 이해 전에 TDD 강제 → 잘못된 abstraction을 test로 굳힘. 6개월 후 refactor 비용 폭발.
해결: Tracer bullets (tracer-bullets)로 빠르게 탐색. 패턴 보이면 그때 TDD.
🔄 대안 흐름
이 원칙이 적용 안 되는 시나리오와 다른 답.
대안 1 — Test-after development
Code 먼저, test 나중. 빠르게 시도 + 검증. 실험적 코드에 정당.
→ TDD 정신과 부분 충돌. test가 design을 이끌지 않음. 단, 검증은 됨.
대안 2 — Property-based testing (QuickCheck)
예시 대신 속성으로 test. 모든 input에 대해 X 속성이 성립. 더 강한 verification.
→ TDD의 진화 형태. Haskell, Rust (proptest), Python (hypothesis)에서 강력. 학습 곡선 큼.
대안 3 — Type-driven development
Type system이 test의 일부 대체. 컴파일이 통과 = 일부 test 통과. Haskell, Idris, Rust에서 강함.
→ TDD와 합쳐서. Type으로 잡을 수 있는 건 type으로, 못 잡는 건 test로.
대안 4 — Behavior-driven development (BDD)
Test 대신 자연어 시나리오. Cucumber, Specflow. 도메인 expert 친화.
→ TDD의 도메인 측 표현. UL과 정합 강함.
대안 5 — Type-level proofs (Coq, Agda)
가장 강한 verification — 수학적 증명. 일반 software엔 over-engineering.
→ critical system (자율주행, 우주, 금융)에서만 정당. 학습 곡선 매우 큼.
💡 인사이트
AI 시대 왜 지금 부활하는가 + 학내 segment 의미.
1. AI agent의 garbage 누적 차단
research/stateless-llm-sdk/software-fundamentals-thesis|Matt thesis의 1차 ok → 3차 garbage 패턴이 AI 시대 가장 큰 risk. TDD가 그 risk의 직접 차단막:
AI agent + TDD 없음:
spec → code (1차) → spec 변경 → code 재생성 (2차) → ... → garbage (3차)
AI agent + TDD:
spec → test → code (1차, test 통과)
→ spec 변경 → test 변경 (사람이) → code 재생성 (2차, test 통과)
→ 매 step의 test가 garbage 차단
→ *TDD가 AI 시대의 garbage 누적 차단막. Beck 1세대 TDD가 AI 시대에 경제적 가치 폭발.
2. Test = AI agent의 success criteria 그 자체
def ralph_loop(task):
while True:
ai_agent.work(task)
if verify_completion(task): # ← 이 함수가 test
break
verify_completion = test. 사람이 언제 끝났는가를 test 형태로 정의. AI agent는 그 test 통과까지 작업.
→ TDD가 named-ownership의 success criteria의 기술적 implementation. Beck의 1세대 TDD가 AI agent loop의 종료 조건으로 진화.
3. Anthropic prompt의 강력한 박음
"It is unacceptable to remove or edit tests."
이 한 문장이 Anthropic harnesses의 가장 강력한 단일 mechanism. 왜 이렇게 강하게 박았는가:
- AI agent가 test 변경하는 함정에 빠지기 쉬움 (약점 5)
- 이 함정이 false success의 가장 큰 source
- 한 번 false success 발생하면 production에 잘못된 코드가 가버림
→ Beck 1세대 TDD가 Anthropic 공식 production prompt에 박혔다는 사실 자체가 AI 시대 부활의 가장 강력한 신호.
4. v1.0 design 직접 적용
| Layer | TDD 표현 |
|---|---|
SKILL.md frontmatter | success_criteria: pass test_X field |
| hooks layer | 각 step에서 test 자동 실행 (lifecycle event) |
| sandbox | test fail 시 자동 rollback |
| AI agent prompt | "테스트를 수정하지 마라. 코드를 수정하라" (Anthropic 패턴) |
| Marketplace skill | test 동반 강제. test 없는 skill = production 도달 X |
→ 모든 layer에 TDD mechanism이 박힘. v1.0의 garbage 누적 차단 default.
5. 학내 segment의 학습 곡선 압축
학생이 TDD를 어색해하는 이유:
- Test 작성 자체가 학습 부담
- 어떤 test를 써야 하나 판단 어려움
- Test fail에 대한 두려움
AI 시대에 이 곡선 압축:
- AI agent가 test 작성을 가속 — 학생은 test 의도만 명시
- Test fail에서 학습 — AI가 왜 fail했나 설명
- 작은 step의 빠른 피드백이 학습 자체
→ 학내 segment에서 TDD가 학습 곡선이 가장 큰 fundamentals이지만, AI 시대에 가장 빨리 압축됨. v1.0이 학생에게 가져다 주는 가속.
6. 연구실 segment — 재현 가능성의 mechanism
연구 코드의 재현 가능성 위기:
- 논문 발표 시점에는 작동
- 1년 후 누가 시도하면 작동 X
- 원인: 환경·dependency·data의 변화
TDD + named ownership:
- 재현 test를 함께 commit
- 1년 후 누가 다시 실행하면 test가 변화 발견
- 실패 원인이 명료
→ 연구실 segment에서 TDD가 reproducibility의 mechanism. v1.0이 연구 코드에도 가져다 줄 수 있는 가치.
7. Beck의 small deliberate steps가 AI 시대 표준 작업 단위
전통 개발: step 단위가 사람의 인지 한계로 정의. 보통 1시간1일.
AI 시대: step 단위가 AI agent의 작업 단위. 보통 1분10분.
작업 단위가 100배 작아짐 → small deliberate steps가 기본 mode가 됨. Beck의 명제가 기술 차원에서 default가 됨.
8. TDD = named ownership의 measurement
Owner가 작성하는 verify_completion 함수 = test. TDD = named ownership의 측정 도구. 두 원칙이 동전의 양면:
- Owner가 책임 정의 (named ownership)
- Test가 책임 측정 (TDD)
12% production cohort의 두 패턴이 이 짝.
9. AI 시대 TDD의 새 변형 — Test as conversation
전통 TDD: 사람이 test 작성 → code 작성. AI 시대: 사람이 자연어로 success criteria 표현 → AI가 test 작성 → AI가 code 작성.
사람: "수강신청이 정원 초과면 대기열 등록"
↓
AI: test_정원_초과시_대기열_등록 작성
↓
사람: 검토 + 승인
↓
AI: code 작성 → test 통과까지
→ AI 시대 TDD의 자연어 표현. v1.0이 학내 학생에게 test 작성 부담 없이 TDD 적용.
10. Refactor가 strategic 시간의 자리
TDD cycle의 Refactor 단계가 strategic-vs-tactical-programming|strategic 시간:
- Red: 행동 정의 (strategic)
- Green: tactical 실행 (AI 위임 가능)
- Refactor: design 개선 (strategic, 사람의 영역)
→ Beck의 1세대 cycle에 이미 strategic/tactical 분할이 박혀 있음. AI 시대에는 Refactor가 사람의 일상. Green은 AI에게. Refactor 시간이 100% 사람의 영역.
다음에 가야 할 자리
이 노트가 호출한 다른 원칙들 — 자연스러운 다음 노트:
- tracer-bullets — premature TDD 회피의 도구. 작은 end-to-end가 첫 test의 단위. 짝
- 14 원칙의 마지막 노트
→ 🔄 Process 축 마지막 tracer-bullets로 마무리하면 14 원칙 모두 완성.
관련
- overview
- named-ownership — test가 success criteria의 implementation. 짝
- ship-and-rollback-as-normal — 각 step이 ship-and-rollback의 가장 작은 단위
- reversibility — 각 step이 reversible
- strategic-vs-tactical-programming — Refactor가 strategic, Green이 tactical
- ubiquitous-language — test name이 도메인 vocabulary로
- research/stateless-llm-sdk/software-fundamentals-thesis|software-fundamentals-thesis — Matt thesis의 small deliberate steps
- sources/key-articles-summary|key-articles-summary — Matt 인용 + Anthropic prompt
- research/stateless-llm-sdk/design-principles|design-principles — 7 원칙의 운영 측 mechanism
Sources
직접 source
- Test-Driven Development By Example — Kent Beck (2002). 한국어판 《테스트 주도 개발》 (인사이트, 평이 좋음). 얇음 (~220p), 예제 위주
- Tidy First substack — Kent Beck (지속). 최근 사상
Matt 강연 (AI 시대 표현)
- Matt Pocock — Software Fundamentals YouTube — "rate of feedback is your speed limit"
- mattpocock/skills GitHub — README의 small deliberate steps 인용
Anthropic의 test 보호 prompt
- Anthropic — Effective Harnesses for Long-Running Agents — "It is unacceptable to remove or edit tests" 명시
대안 흐름
- Growing Object-Oriented Software, Guided by Tests (GOOS) — Freeman & Pryce (2009). TDD 심화
- QuickCheck: A Lightweight Tool for Random Testing of Haskell Programs — Claessen & Hughes (2000). Property-based testing
- Type-Driven Development with Idris — Edwin Brady (2017). Type-driven
- Specification by Example — Gojko Adzic (2011). BDD
TDD 비판 (약점 4)
- David Heinemeier Hansson — TDD is dead. Long live testing. (2014) https://dhh.dk/2014/tdd-is-dead-long-live-testing.html