실험주의와 TDD
- 5.1 물리학자 파인먼에게 배우는 '실험주의'
- 5.2 TDD에서 배우는 자동화 테스트
- 5.3 테스트는 새로운 지식을 끌어내는 원천
- 5.4 품질을 높이는 TDD 적용 사례 하나
TDD가 테스트 기법이라고? 아니야. Farley는 TDD를 과학적 실험 방법의 소프트웨어 버전으로 봐.
출발점은 물리학자 리처드 파인먼이야. 파인먼의 문제 해결법 — "문제를 정의하고, 열심히 생각하고, 답을 적어라." 농담 같지만, 핵심은 문제를 명확히 정의하는 것이 가장 중요하고 가장 어렵다는 거야. 문제를 잘못 정의하면 아무리 열심히 생각해도 잘못된 답을 얻지. 그리고 파인먼은 이런 말도 했어 — "자기 자신을 속이지 마라. 가장 속이기 쉬운 사람이 바로 자기 자신이다." 7장의 자기기만 경고와 직결되는 말이야.
이걸 소프트웨어에 적용하면? Red-Green-Refactor 사이클이야. Red — 실패하는 테스트를 먼저 쓴다. "이 기능은 이런 입력에 이런 출력을 내야 한다"는 가설을 코드로 표현하는 거야. 이 순간이 파인먼의 "문제를 정의하라"에 해당해. Green — 테스트를 통과하는 최소한의 코드를 작성한다. 가설을 충족시키는 실험이지. Refactor — 동작하는 코드를 더 깨끗하게 개선한다. 실험 결과를 반영하는 거야. 가설-실험-결론의 과학적 사이클이 그대로 코딩 프로세스가 된 거지.
근데 테스트의 가치가 버그 잡는 데만 있다고 생각하면 절반밖에 못 본 거야. 테스트는 지식을 생성하는 도구거든. "이 함수에 null이 들어오면 어떻게 해야 하지?" — 테스트를 안 쓰면 이 질문 자체를 안 해. 테스트를 쓰는 과정에서 코드의 의도와 경계 조건이 명확해지고, 설계에 대한 깊은 사고가 자연스럽게 일어나. 회귀 테스트는 "과거에 이 버그가 있었다"는 지식의 저장소고, 코드가 바뀔 때마다 자동으로 재검증돼. 문서는 오래되면 코드와 동기화가 깨지지만, 테스트는 깨지면 CI가 알려주니까 살아있는 문서 역할을 해.
실제 효과를 보면 더 명확해. TDD 없이 코드를 짜면, 나중에 테스트 붙이기 어려워지고, 변경이 두려워지고, 리팩토링을 안 하고, 코드가 더 복잡해지는 악순환이 시작돼. TDD로 시작하면 코드가 애초에 테스트 가능하게 설계되거든. 의존성을 주입하고, 인터페이스로 통신하고, 부수효과를 격리하는 — 결합도가 낮고 응집도가 높은 설계가 자연스럽게 유도돼. TDD가 만능은 아니야. 하지만 핵심 비즈니스 로직에 적용하는 가치는 매우 크고, "어렵다"는 건 안 하는 이유가 아니라 연습해야 하는 이유야.
정리
5장 읽고 기억할 거 세 가지:
- TDD는 테스트 기법이 아니라 과학적 실험 방법의 소프트웨어 버전이다. Red-Green-Refactor 사이클은 가설-실험-결론 사이클과 같아.
- 테스트는 버그를 잡는 도구가 아니라 지식을 생성하는 도구다. 테스트를 쓰면서 설계에 대한 깊은 사고가 일어나고, 경계 조건이 명확해지고, 코드의 의도가 문서화돼.
- 파인먼의 교훈 — "자기 자신을 속이지 마라." 가설을 세우고 검증하는 과학적 태도가 소프트웨어 엔지니어의 핵심 역량이야.