TDD와 관련된 오해 중 가장 심각한 것은 단위 테스팅과 TDD를 구별하지 못하는 것입니다. 그리고 또 다른 오해가 ‘좋은 디자인’과 ‘테스트하기 쉬운 디자인’의 관계에서도 발견됩니다. 좋은 디자인이 테스트하기 쉽다는 명제에 대한 반론은 찾아보기 어렵습니다. 저도 반례를 경험한 일이 없습니다. 따라서 테스트하기 어렵다면 디자인 문제를 의심해 볼 수 있고 이것은 TDD가 주는 나쁜 디자인에 대한 피드백으로 볼 수 있습니다. 게다가 이 피드백은 세부 구현 전에 제공되기 때문에 더 유익합니다. 하지만 안타깝게도 그 역은 성립하지 않습니다. 단순한 사례는 아주 쉽게 만들 수 있습니다.

int add(int x, int y) {
    return x * y;
}

add() 함수는 테스트하기 쉽습니다. 하지만 인터페이는 분명 잘 못 디자인되어 있습니다. 함수 이름으로 add보다 multiply가 훨씬 좋습니다. 또 다른 예로, 테스트하기 쉬운 평균 5줄의 순수함수(pure function) 1000개를 하나의 클래스에 담았다면 그 디자인의 좋고 나쁨을 테스트 용이성만으로 판단할 수 있을까요?

TDD를 하다보면 다자인 확신이 부족한 코드에 대해 테스트하기 쉽지만 나쁜 디자인을 선택하는 현실적인 사례를 종종 경험할 수 있습니다. 테스트 용이성에만 집중해 문제를 풀어내려 한다면 균형을 잃고 과도한 분해와 과도한 간접화의 실수를 저지르기도 합니다. 이것은 TDD의 문제라기 보다는 해당 문제에 대한 디자인 통찰력이 부족한 것입니다. 따라서 이 문제는 디자인으로 풀어야지 TDD로는 풀어낼 수 없습니다. TDD 반복주기의 마지막 단계인 리팩터링이 중요한 이유이기도 합니다. 단위 테스팅은 나쁜 디자인에 대한 신호는 주지만 좋은 디자인에 대한 신호는 주지 않습니다.

테스팅을 잘 하기 위해서는 이론과 경험 모든 측면에서 디자인 능력을 길러야합니다. 하지만 디자인을 잘 하기 위해 테스팅이나 TDD에 매달리는 것은 어리석은 짓입니다. 물론 우린 가끔 어리석은 짓을 저지르고 반성하는 과정에서 깨달음을 얻기도 합니다.

Long live design.