TDD의 흥륭과 논쟁 — XP의 한 실천에서 독립된 기법으로
1999년, 켄트 벡(Kent Beck)은 XP를 구성하는 실천 중 하나로 「테스트 퍼스트」를 소개했다. 2002년 단독 저서 『Test-Driven Development: By Example』으로 TDD는 독립된 기법이 되었고, Red-Green-Refactor 사이클과 「동작하는 깨끗한 코드」라는 목표가 널리 퍼졌다. 그러나 classicist와 mockist라는 학파의 분열, 그리고 2014년 DHH의 도발적인 「TDD is dead」 문제 제기는 업계를 뒤흔든 대논쟁을 일으켰다. TDD의 이론적 확립부터 논쟁, 그리고 현재의 균형 잡힌 시각까지를 따라간다.
테스트 주도 개발(Test-Driven Development, TDD)은 「먼저 테스트를 작성하고, 이를 통과시키는 최소한의 코드를 작성한 뒤, 그 후에 정리한다」는 단순한 사이클을 핵심으로 하는 개발 기법이다.
1990년대 말 켄트 벡이 익스트림 프로그래밍(Extreme Programming, XP)의 한 실천으로 소개한 TDD는, 이윽고 XP라는 틀을 넘어 독립된 기법으로 널리 실천되기에 이른다. 하지만 그 보급 과정은 2014년의 「TDD는 죽었다」는 논쟁이 상징하듯, 늘 찬반양론을 동반해 왔다. 이 장에서는 TDD의 이론적 확립부터 학파의 분열, 2014년의 대논쟁, 그리고 현재의 차분한 시각에 이르는 흐름을 따라간다.
XP의 한 실천에서 독립된 기법으로
켄트 벡은 1999년 저서 『Extreme Programming Explained』에서 XP를 구성하는 12가지 실천 중 하나로 「테스트 퍼스트 프로그래밍(Test-First Programming)」을 꼽았다.
당초의 TDD는 페어 프로그래밍, 지속적 통합, 단순한 설계, 잦은 릴리스 등 나머지 11가지 실천과 결합해야 비로소 효과를 발휘하는, XP라는 개발 스타일 전체의 한 요소로 소개된 것이었다. 그것만 따로 논의되는 일은 아직 드물었다.
벡 자신은 「먼저 테스트를 쓴다」는 발상이 완전히 새로운 것이 아니라, 오래전부터 프로그래밍 현장에 산발적으로 존재하던 생각을 XP의 맥락 속에서 명확한 규율(discipline)로 재발견해 이름을 붙인 것이라고 자리매김한다. 그러나 체계화된 방법론으로 널리 알려지게 된 것은 분명 이 XP에서의 정식화 이후다.
이후 2002년, 벡이 단독 저서 『Test-Driven Development: By Example』(Addison-Wesley)을 출간하면서, TDD는 XP에서 독립된 하나의 기법으로 다뤄지게 되었다.
『Test-Driven Development: By Example』(2002)
이 책의 특징은 추상적인 원칙 설명에 그치지 않고, 두 가지 구체적인 소재를 통해 직접 손을 움직이며 TDD를 체험하게 하는 구성에 있다. 독자는 벡이 어느 타이밍에 어떤 테스트를 쓰고, 어떻게 최소한의 구현으로 통과시키고, 어디서 리팩터링하는지를 그 사고의 결 그대로 체험할 수 있다.
- 전반부에서는 여러 통화(달러와 프랑 등)를 다루는 「Money」 클래스의 구현을, TDD 사이클을 반복하며 조금씩 키워나간다
- 후반부에서는 파이썬용 간이 xUnit 계열 프레임워크 자체를 TDD로 조립해 나간다 — 「테스트 프레임워크를 테스트 주도로 만든다」는 메타적인 연습이다
이 책을 통해 벡이 전하고자 한 것은 단순히 「테스트를 먼저 쓴다」는 규칙이 아니라, 작은 단계를 밟으며 설계를 키워나가는 개발의 리듬 그 자체였다.
Red-Green-Refactor 사이클
TDD의 중심에 있는 것이 다음 세 단계로 이루어진 반복 사이클이다.
| 단계 | 내용 |
|---|---|
| Red(빨강) | 아직 구현하지 않은 기능에 대해, 실패하는 테스트를 먼저 작성한다 |
| Green(초록) | 그 테스트를 통과시키는 데 필요한 최소한의 코드를 작성한다. 설계의 아름다움은 뒤로 미뤄도 좋다 |
| Refactor(리팩터링) | 테스트가 통과하는 상태를 유지한 채, 코드의 중복이나 설계상의 왜곡을 정리한다 |
이 사이클을 가능한 한 작은 단위로 빠르게 반복하는 것이 중시된다. 하나의 사이클이 몇 분 이내에 끝나는 세밀한 보폭으로 나아감으로써, 「지금 어디까지 동작하는가」를 항상 파악하며 개발을 진행할 수 있다는 주장이다. 보폭이 너무 크면 테스트가 실패한 상태로 있는 시간이 길어져 문제의 소재를 찾기 어려워진다. 반대로 보폭을 작게 유지하면 언제든 「바로 앞의 Green 상태」로 되돌아갈 수 있다는 안심 속에서 개발을 진행할 수 있다.
「동작하는 깨끗한 코드」라는 목표
벡은 『Test-Driven Development: By Example』 서두 근처에서, TDD가 지향하는 목표를 「clean code that works(동작하는 깨끗한 코드)」라는 말로 요약한다. 벡 자신은 이 말을 자신의 창안이 아니라 동료 론 제프리스(Ron Jeffries)가 쓴 표현으로 명시적으로 인용·귀속하고 있다.
벡의 설명에 따르면 「동작하는 것」과 「깨끗한 것」은 종종 동시에 추구하면 서로 발목을 잡는 두 목표다. TDD의 Red-Green-Refactor 사이클은 이 긴장 관계를 시간적으로 분리함으로써 해소한다. 먼저 Green 단계에서는 「동작하는 것」에만 집중해, 지저분해도 좋으니 가장 짧은 경로로 테스트를 통과시킨다. 그런 다음, 테스트가 안전망으로 기능하는 리팩터링 단계에서 비로소 「깨끗한 것」에 착수한다. 「한 번에 하나의 목표만 좇는다」는 이 사고방식이 TDD의 실천상 핵심으로 여겨진다.
classicist 학파와 mockist 학파
TDD가 확산되면서 「테스트 대상이 의존하는 다른 객체를 어떻게 다룰 것인가」를 둘러싸고 크게 두 가지 유파가 형성되어 갔다.
마틴 파울러(Martin Fowler)는 2007년 에세이 「Mocks Aren’t Stubs」에서 이를 다음과 같이 정리했다.
- classicist(Detroit/Chicago 학파) — 켄트 벡을 비롯한 초기 TDD 실천자에 가까운 방식. 가능한 한 실제 객체를 사용해 테스트하고, 외부 시스템이나 데이터베이스처럼 「느리고」 「불안정한」 의존 대상만을 테스트 더블로 대체한다. 검증은 최종적인 상태(state)에 대해 이루어진다(state-based verification)
- mockist(London 학파) — 스티브 프리먼(Steve Freeman)과 냇 프라이스(Nat Pryce)가 2009년 저서 『Growing Object-Oriented Software, Guided by Tests』에서 체계화한 방식. 테스트 대상이 협력하는 상대를 거의 모두 목 오브젝트로 대체하고, 객체 간의 상호작용(interaction) 자체를 검증한다(interaction-based verification). 「바깥에서 안으로(outside-in)」 설계를 진행하는 개발 스타일과도 결부된다
이 두 학파의 차이는 단순한 취향의 문제에 그치지 않고, 「목을 다용하는 것이 좋은 설계를 이끄는가, 아니면 설계를 왜곡하는가」라는, 다음에 살펴볼 DHH 비판의 핵심 쟁점으로 직결된다.
DHH의 「TDD is dead. Long live testing.」(2014)
2014년, 루비 온 레일스의 창시자 데이비드 하이네마이어 한손(David Heinemeier Hansson, DHH)은 RailsConf 2014 기조연설과 이어진 블로그 글 「TDD is dead. Long live testing.」을 통해 TDD의 존재 방식에 강한 이의를 제기했다.
이 발언은 그때까지 비교적 평온하게 확산되고 있던 TDD 실천자 커뮤니티에 큰 파장을 일으켰고, 블로그·콘퍼런스·소셜 미디어에서 활발한 논쟁을 촉발했다. DHH 주장의 요점은 크게 다음 세 가지로 정리할 수 있다.
- 용어의 혼란 — 「TDD」와 「단위 테스트」가 종종 동일시되어 논의가 어긋난다
- 테스트 유발 설계 손상(test-induced design damage) — 「테스트하기 쉽게 하기 위해서」라는 이유만으로 과도한 의존성 주입이나 인터페이스 추상화를 끌어들여, 그 결과 코드베이스 전체의 가독성과 단순함이 훼손되는 사례가 있다는 비판. 특히 모든 의존 대상을 교체 가능하게 만드는 mockist류 TDD의 설계 요구를 겨냥한 것이었다
- Red-Green-Refactor가 자신에게는 맞지 않았다는 개인적 경험 — 항상 먼저 테스트를 쓴다는 엄격한 규율이 자신의 개발 스타일과는 맞지 않았다는 고백
DHH는 통합적이고 현실에 가까운 테스트에 더 가치를 두어야 한다고 주장했고, 「100퍼센트 단위 테스트 커버리지」 같은 교조적인 목표에 회의적인 입장을 취했다. 그의 비판은 특히 루비 온 레일스처럼 프레임워크에 강하게 의존하는 웹 애플리케이션 개발에서, 데이터베이스와 프레임워크 자체를 목으로 대체해서까지 「순수한 단위 테스트」를 고집하는 것의 실익에 대한 의문으로 표출되었다.
벡×파울러×DHH의 「Is TDD Dead?」 대담
이 논쟁을 계기로 켄트 벡·마틴 파울러·DHH 세 사람은 2014년, 6부로 구성된 구글 행아웃 형식의 대담 시리즈 「Is TDD Dead?」를 녹화해 martinfowler.com에 공개했다. 단순한 언쟁이 아니라, 각자의 경험에 기반한 개발관의 차이를 정성껏 조율하려는 건설적인 시도로 알려져 있다.
대담에서는 DHH가 제기한 세 가지 쟁점(용어의 혼란, 테스트 유발 설계 손상, Red-Green-Refactor에 대한 위화감)을 축으로, TDD가 효과적으로 작동하는 상황과 그렇지 않은 상황, 테스트 수준별로 적합한 검증 방식, 목을 사용할 위치 등이 논의되었다. 이 대담 시리즈는 「TDD냐 아니냐」라는 이분법이 아니라 「상황에 따라 어떤 테스트 전략을 선택할 것인가」라는 더 실천적인 질문으로 업계의 관심을 옮기는 계기가 되었다고 평가받는다.
흥미로운 점은 벡과 파울러가 DHH의 주장을 무조건 부정하지는 않았다는 것이다. 두 사람은 과도한 목 사용이 설계를 왜곡할 위험이 있다는 DHH의 지적 자체에는 일정한 이해를 보이면서도, 그것은 「TDD 자체의 결함」이 아니라 「mockist류 방식을 잘못 과도하게 적용했을 때의 폐해」라는 입장을 취했다. classicist류 TDD(상태 기반 검증을 중심에 두고, 목은 정말 필요한 상황에 한정하는)라면 DHH가 우려하는 설계의 왜곡은 일어나기 어렵다는 정리다.
TDD 효과에 관한 실증 연구
TDD가 실제로 소프트웨어의 품질이나 생산성에 어떤 영향을 미치는가에 대해서는 2000년대부터 많은 실증 연구가 이루어져 왔지만, 결론은 한결같지 않다.
- 마이크로소프트와 IBM의 개발팀을 대상으로 한 산업 사례 연구(나가판(Nagappan), 막시밀리앙(Maximilien), 바트(Bhat), 윌리엄스(Williams) 등의 보고, 2000년대 후반)에서는 TDD를 채택한 팀에서 릴리스 후 결함 밀도가 크게 낮아진 반면, 개발에 걸리는 시간은 15~35퍼센트 정도 늘어났다고 보고되었다
- 반면 학생을 피험자로 한 학술적 실험의 상당수는 TDD와 기존의 「구현 후에 테스트를 쓰는」 방식 사이에 유의미한 차이가 보이지 않거나, 연구에 따라 결과가 제각각이라는 보고도 많다
- 연구 간 결과가 갈리는 배경에는 피험자의 경력 연수, 테스트의 단위, TDD의 실천 정도 같은 교란 요인을 통제하기 어렵다는 지적이 있다
이러한 상황에서, 「TDD에는 절대적인 효과가 있다」고도 「TDD에는 효과가 없다」고도 단정할 수 없다는 것이 학술적으로 타당한 현재의 인식이다.
현재의 균형 잡힌 시각
2014년의 논쟁으로부터 10년 이상이 지난 지금, 업계의 대세는 다음과 같은 균형 잡힌 입장에 안착해 있다. 한때의 「TDD 원리주의냐 TDD 불필요론이냐」라는 양극화된 대립은 옅어지고, 상황에 따른 구분 사용이 당연한 것이 되었다.
- TDD는 만능의 은탄환도, 지켜야 할 교조도 아니며, 상황에 따라 구분해 쓰는 여러 기법 중 하나로 다뤄진다
- 「먼저 테스트를 쓰는 것」 자체보다, 「작고 검증 가능한 단위로 설계를 진행한다」는 TDD 이면의 사고방식이 더 본질적이라는 이해가 퍼지고 있다
- classicist류 TDD는 주류 팀에서 비교적 자연스럽게 받아들여지는 한편, mockist류 TDD는 의존성 주입을 다용하는 엔터프라이즈 계열 코드베이스 등에서 여전히 뿌리 깊은 지지를 얻고 있다
- 「테스트 퍼스트」냐 「테스트 애프터」냐 하는 의례적인 순서보다, 최종적으로 얻어지는 설계의 질과 회귀 안전성(regression safety)이라는 결과 쪽이 중시되게 되었다
TDD를 둘러싼 논쟁은 테스트라는 행위가 단순한 품질 보증의 수단이 아니라 설계 그 자체와 깊이 관련된 활동임을 업계 전체에 강하게 각인시킨 사건이었다. Red-Green-Refactor라는 단순한 사이클 안쪽에, 개발자가 얼마나 규율을 갖고 설계와 마주하는가라는 기술론을 넘어선 물음이 놓여 있음을 드러냈다는 점에서, TDD의 흥륭과 논쟁은 소프트웨어 테스트사에서 중요한 한 장을 이룬다.
이 글에서 다음 글로
TDD가 확산되는 과정에서 떠오른 또 하나의 문제가 「테스트」라는 말 자체가 일으키는 혼란이었다. 초보자는 「무엇을 테스트해야 하는가」 「이것을 테스트라 부를 수 있는가」라는 망설임에 종종 빠졌다. 다음 장에서는 이 어휘의 문제에 주목한 댄 노스(Dan North)가 「테스트」가 아니라 「행위(behaviour)」를 어휘의 중심에 둠으로써 탄생시킨 행위 주도 개발(BDD) 의 탄생을 따라간다.