Chapter 1

화폐 예제 시작

  • 1.1 빨강-초록-리팩토링 리듬
  • 1.2 첫 번째 테스트와 하드코딩
  • 1.3 부작용 제거와 값 객체
  • 1.4 삼각측량으로 일반화하기
  • 1.5 테스트와 코드의 결합도
  • 1.6 복붙도 전략이다

TDD의 핵심은 딱 세 단계야. 실패하는 테스트를 쓰고, 어떤 죄악을 저질러서라도 통과시키고, 중복을 제거하지. 이 리듬을 짧은 주기로 반복하는 게 전부거든.

빨강-초록-리팩토링이 그 리듬이야. 켄트 벡은 다중 통화를 지원하는 보고서 시스템을 예제로 잡아. "$5 x 2 = $10"이라는 간단한 곱셈부터 시작하는데, 테스트를 먼저 쓰고, 컴파일도 안 되는 상태에서 Dollar 클래스를 만들고, times 메서드를 만들고, amount 필드를 만들지. 테스트를 통과시키기 위해 amount에 그냥 10을 하드코딩해. "이게 뭔 짓이냐"고 할 수 있는데, 이게 TDD의 첫 번째 교훈이야. 일단 초록 막대를 보는 게 중요하거든. 그 다음에 상수 10을 5 * 2로, 다시 amount * multiplier로 일반화하면 돼.

근데 dollar.times(2)를 호출하면 Dollar 객체 자체의 amount가 바뀌어버리는 부작용(side effect) 문제가 생겨. 같은 Dollar 객체로 times(2) 하고 나서 times(3) 하면 amount가 이미 변해 있어서 기대한 결과가 안 나오거든. 해결책은 times()가 새로운 Dollar 객체를 반환하게 만드는 거야. 원래 객체는 건드리지 않지. 여기서 중요한 건 테스트를 작성하다 보니 자연스럽게 더 나은 설계가 드러났다는 거야. 부작용 문제를 테스트가 먼저 잡아냈고, 그걸 고치는 과정에서 값 객체(Value Object) 패턴이 자연스럽게 등장했어. 설계를 미리 고민한 게 아니라, 테스트가 설계를 이끈 거지.

Dollar가 값 객체라면, 같은 금액을 가진 두 Dollar는 같아야 해. new Dollar(5)new Dollar(5)가 동등한지 비교할 수 있어야 한다는 뜻이야. **값 객체의 핵심 규칙은 "같은 값을 가지면 같은 객체"**라는 거거든. 그래서 equals() 메서드를 구현해야 하는데, 테스트를 먼저 쓰지. assertTrue(new Dollar(5).equals(new Dollar(5))). 가장 빠르게 통과시키는 방법은 그냥 return true를 반환하는 거야.

하나의 테스트만으로는 일반화할 근거가 부족하잖아. 그래서 **삼각측량(triangulation)**을 써. 두 번째 테스트를 추가해서 일반화를 강제하는 기법이야. assertFalse(new Dollar(5).equals(new Dollar(6))) 테스트를 추가하면, 더 이상 return true로는 통과 못 해. 이제 진짜로 amount를 비교하는 코드를 작성해야 하지.

equals()가 생겼으니까 테스트와 코드의 결합도를 줄일 수 있어. 이전까지 테스트에서 dollar.amount == 10 이런 식으로 amount 필드를 직접 확인했는데, 이러면 테스트가 구현 세부사항에 결합돼. amount 필드의 이름이 바뀌거나 접근 방식이 바뀌면 테스트도 깨지거든. dollar.equals(new Dollar(10))으로 바꾸면 테스트가 Dollar의 공개 인터페이스만 사용하게 되고, 내부 구현에서 자유로워져. equals()에 버그가 있으면 곱셈 테스트도 같이 틀릴 수 있는 위험이 있긴 한데, 켄트 벡은 이 정도 위험은 감수할 만하다고 해. 완벽한 테스트를 기다리다가는 아무것도 못 하니까.

할 일 목록에 "5CHF x 2 = 10CHF"가 있어. 이걸 어떻게 구현하냐면, 놀랍게도 켄트 벡은 Dollar 클래스를 통째로 복사해서 Franc 클래스를 만들어. 변수 이름만 바꾸고. "복붙이라니, 이게 무슨 짓이냐"라고 할 수 있는데, TDD에서는 이게 허용돼. 왜냐면 다음 단계에서 중복을 제거할 거니까. 빨강-초록-리팩토링에서 지금은 "초록"에 집중하는 단계야. 먼저 돌아가게 만들고, 그 다음에 깨끗하게 만드는 것. 이 순서를 뒤집지 마. 핵심은 중복을 방치하지 않겠다는 의지지, 복붙 자체가 나쁜 게 아니야.


정리

1장 읽고 기억할 거 세 가지:

  1. 빨강-초록-리팩토링이 TDD의 핵심 리듬이야. 실패하는 테스트 작성, 최소한의 코드로 통과, 중복 제거 순서를 짧은 주기로 반복하지
  2. 테스트가 설계를 이끌어. 부작용 문제를 테스트가 잡아냈고, 값 객체 패턴이 자연스럽게 등장했어. 삼각측량으로 하드코딩을 일반화로 밀어붙이고
  3. 일단 돌아가게 만들어. 하드코딩이든 복붙이든 상관없어. 초록 막대를 본 다음에 개선하면 돼. 중요한 건 중복을 방치하지 않겠다는 의지야