2016년 2월 21일 일요일

TDD(Test-Driven Development)란?

TDD(Test-Driven Development)는 현재 소프트웨어를 개발하는데 있어서 전세계적으로 가장 즐겨 사용하는 개발 방법론으로 자리잡고 있다. 미국의 한 리서치 기관에서 조사한 결과에 따르면 소프트웨어 회사에서 약 77.5% 이상이 TDD 개발방법론을 선호하고 적용하고 있다고 이야기 하고 있다. 이에 비추어 볼 때 아직 국내에서는 도입이 많이 늦기는 했지만 세계적인 데이터를 통틀어 볼 때 보다 높은 퀄리티의 소프트웨어를 만드는데 있어서 필수적인 과정이 분명하다. 

국내에서는 소프트웨어의 테스트라는 것은 일반적으로 어느 정도 규모 있는 소프트웨어 회사들에 한해서만 QA팀이 존재하고 있고 그 팀을 통하여 테스트를 진행해 왔었기 때문에 TDD를 단순히 QA를 위한 혹은 유닛 테스팅 방법론으로 오해할 수 있다. 하지만 TDD는 개발자들을 위한 개발자들에 의한 개발 방법론이다. 개발자들이 보다 객체지향적인 코드를 생성해내는데 큰 일조를 하고 있을 뿐만 아니라 보다 튼튼한 소프트웨어 구조를 잡을 수 있게 도와준다. 

이번 장에서는 TDD가 무엇인지 현재의 개발방법론과 비교하면서 또 장단점을 통해 살펴봄으로써 보다 높은 퀄리티의 소프트웨어를 개발하는데 있어서 왜 TDD를 도입해야 되는지 설명하도록 하겠다.

1) TDD란 무엇인가?

먼저 TDD는 1999년도 XP(Extreme Programing)라는 애자일 기반의 개발 방법론이 자리 잡을 때 처음 소개가 되었다. 이 그룹에서는 프로그래밍 전에 테스트 코드를 먼저 작성하면 어떨까라고 생각하고 시도를 해봤는데 이 때 테스트 이후에 작성되는 코드의 퀄리티가 꽤 인상적이었기 때문에 TDD가 애자일 방법론에 도입되기 시작했다. 


TDD에 대해서 좀 더 쉽게 이해하기 위해서 먼저 “테스트 주도 개발(Test-Driven Development)” 라는 용어를 “테스트 먼저 개발(Test-First Development)”로 바꾸어 이해할 필요가 있다. 즉, 개발을 하기 전에 테스트 코드를 먼저 작성한다는 것이다. 아래 [그림1] 은 일반적인 개발 프로세스를 설명하고 있다.



[그림1] 기존의 개발 프로세스


프로그램을 개발하는데 있어서 익숙한 스텝들일 것이다. 필자 또한 지금 돌아보면 왜 TDD를 진작 소개되지 못했을까 라는 아쉬운 마음이 들 정도로 위와 같은 개발 프로세스를 무려 10년이상이나 유지해왔었다. 이 고전적인 개발 방법론의 문제는 눈에 보이는 것처럼 명확하다. 테스트를 통해서 원하는 결과가 나오지 않았을 때 처음 소프트웨어 디자인을 다시 수정해야 될 수도 있다는 것이다. 왜냐하면 코드를 작성하기 전에 “디자인”에 충분한 시간을 투자하면서 고려하지 못하기 때문이다. 그럼 TDD를 도입한 개발 프로세스는 어떨까? [그림2]를 살펴보자.





[그림2] Test-Driven Development 프로세스

TDD의 경우 테스트 코드를 작성한 뒤에 코드를 작성한다. 때문에 보다 정확한 프로그래밍 목적을 디자인 단계에서 반드시 미리 정의해야만 하고 또 무엇을 테스트해야 할지 미리 정의해야만 한다. 프로그래밍 경험이 있는 개발자라면 누구나 공감할 수 있는 것이 가끔 코드를 작성한 뒤에 테스트를 하면서 “맞아! 원래 이걸 의도한 것이 아니었는데” 하면서 깨닫고 다시 작성한 코드를 수정하는 경우가 많이 있다. 이것을 방지 할 수 있다는 것이 TDD의 하나의 큰 장점 중에 하나이기도 하다. 


그렇다면 위의 테스트코드와 실제 구현까지 이루어지는 주기는 어떻게 산출될까? 아주 작은 유닛들 하나하나 즉, 메서드를 작성할 때 마다 저렇게 주기를 반복해야 되는 것일까? 일반적으로 애자일 개발 방법론 위에서 TDD를 적용한다면 저 주기는 당연히 하나의 유저 스토리를 기반으로 나누어지게 된다. 즉, 애자일 방법론에서는 업무(Task)가 존재하고 그 업무에서는 여러 개의 유저 스토리가 존재하게 된다. 예를 들면 “사용자가 버튼을 클릭할 경우에 새로운 일정을 추가하는 창을 열수 있다.” 라는 정의가 바로 유저스토리이다. 워터폴(Waterfall) 방법론에서 TDD를 적용한다고 하더라도 업무 단위대로 위의 주기를 적용해도 큰 무리는 없을 것이지만 보다 튼튼한 업무분석이 뒷받침 될수록 TDD의 이점을 가져올 수 있다는 것은 사실이다. 

2) TDD의 장점


그렇다면 TDD의 가장 큰 장점은 아마도 높은 퀄리티의 소프트웨어를 보장한다는 것이다. 그렇다면 높은 퀄리티의 소프트웨어는 어떻게 정의할 수 있을까? 먼저 기획을 떠나서 개발자의 역할만 놓고 본다면 절대 에러나 버그가 없어야 한다는 것이다. 두 번째로는 추가적인 요구사항이 있을 때 손쉽게 그 요구사항을 반영해줄 수 있어야 한다는 것이고 마지막으로 누가 그 코드를 봐도 손쉽게 이해하고 수정할 수 있어야 한다는 것이다. 바로 TDD는 정확하게 이 세가지 사항을 만족시켜 준다. 그럼 한가지씩 살펴보도록 하자.

- 보다 튼튼한 객체지향적인 코드 생산 가능

테스트 코드를 먼저 작성한다는 것은 하나하나의 기능들에 대해서 철저히 구조화 시켜 코드를 작성한다는 것을 뜻한다. 나도 모르게 디자인 패턴들을 하나하나 적용하고 인터페이스들을 이용해서 느슨한 결합을 실현시키는 자신을 발견하게 된다. 그 이유는 TDD가 코드의 재사용성을 보장해야만 가능하기 때문에 그렇다. 즉, 우리가 테스트 코드를 작성할 일이 없을 경우에 한 메서드 안에 여러 가지 기능이 혼합되어 이용해도 무방하다. 아니 좀 더 솔직하게 우리가 코드를 작성하면서 실제로 이 코드는 재사용이 되지 않는다라는 가정으로 작성하는 코드가 많지 않은가? 실제로 어떤 기능을 두세 번 호출하게 될 경우에서야 객체화하거나 메서드화 시키는 경우가 많다. 하지만 TDD는 “모든 코드”가 재사용성 기반으로 작성되어야 하기 때문에 보다 튼튼한 코드 생산이 이루어 지게 되는 것이다.

- 재설계 시간의 단축

앞에서 설명한 것처럼 테스트 코드를 먼저 작성하기 때문에 내가 지금 무엇을 해야 하는지 분명히 정의를 하고 시작하게 된다. 때로는 우리가 코드를 작성하면서 삼천포로 빠지는 경우가 많다. 내가 뭘 하려고 했었지? 하면서 코드 정체성의 혼란을 가끔 마주하면서 디자인을 다시 뜯어 고치고 아까운 코드 지울 수도 없고 그냥 주석으로 달아 두고 괜히 라인수만 차지하게 되는 경우를 필자 또한 수없이 경험했다. 하지만 TDD에 익숙해 지는 순간 이러한 경험은 이제 그저 추억 속으로 묻히게 된다. 테스트 코드를 작성하면서 인터페이스나 클래스의 구조들을 많이 수정하게 된다. 만약 테스트 코드가 아니라 실제 구현 코드를 작성하면서 이 작업을 할 경우에 구현하고 있는 코드들 또한 고쳐야 하는 문제를 유발하게 된다.

개인적인 경험에 비추어 보자면 실제로 초급 개발자와 중고급 개발자의 차이는 얼마만큼 예외 상황을 많이 알고 있느냐의 차이로 나누어 지기도 한다. 여기서 만약 먼저 테스트 시나리오들을 정의하게 되면 그만큼 필요한 예외 상황들을 먼저 선임들과 상의할 수 있다는 것이고, 초급 개발자들도 예외 상황들과 테스트 되어야 하는 가능성들을 먼저 조사하게 되는 것이다.


- 디버깅 시간의 단축

이것은 통합 테스팅이 아닌 유닛 테스팅을 하는 이점이기도 하다. 아래서 보다 정확한 논리를 설명할 것이지만 먼저 간단하게 설명하자면 우리는 각각의 모듈 별로 테스트를 자동화할 수 있는 코드가 없다면 특정 버그를 찾기 위해서 모든 레벨(레이어)의 코드들을 살펴봐야 한다. 예를 들어 사용자의 데이터가 잘못 나온다면 DB의 문제인지, 비즈니스 레이어의 문제인지 UI 단의 문제인지 실제 모든 레이어들을 전부다 디버깅할 필요 없이 자동화 된 유닛테스팅 결과로 우리는 손 쉽게 찾아 낼 수 있다는 것이다.

- 애자일과의 시너지 효과

보다 정확하게 말하자면 BDD(Behavior-Driven Development)를 적용하는데 있어서 큰 시너지 효과가 있다. BDD는 행위(동작) 중심적인 방법으로 개발을 진행하는 방법론인데 개발자 디자이너 그리고 기획자 모두 사용자 입장으로 같은 목표로 가지기 위함이다. 예를 들어 회의를 할 때도 항상 개발자는 기술적인 관점으로 어떤 업무를 해석하는 경우가 것을 어느 정도 완화시켜 줄 수 있기 때문에 도입한다. 즉, TDD를 진행하면 항상 그 테스트 요소들이 사용자 관점으로 정의되고 진행되기 때문에 보다 튼튼한 개발 프로세스를 만들게 된다.

- 테스트 문서의 대체가능

주로 S.I 프로젝트를 진행하다 보면 어떤 요소들이 테스트 되었는지 테스트 정의서를 만들고는 한다. 이것은 단순 통합테스트 문서에 지나지 않는다. 즉, 내부적인 하나하나의 로직들이 어떻게 테스트 되었는지 제공할 수 없다. 하지만 TDD를 하게 될 경우에 테스팅을 자동화 시킴과 동시에 보다 정확한 테스트 근거를 산출할 수 있다.

- 추가 구현의 용이함

개발 뒤에 어떤 기능을 추가할 때 가장 우리를 번거롭게 하는 것이 이 기능이 기존의 코드들에 얼만큼 영향을 미치게 될지 모르기 때문에 다시 모든 코드들을 테스트 해야 되는 것이 큰 곤욕이다. 역시나 바로 뒷 부분에 살펴볼 내용이지만 유닛 테스트로 자동화 될 경우에 우리는 수동으로 모든 테스트를 다시 진행해야 되는 시간적인 낭비를 줄일 수 있다.

3) TDD의 단점


그렇다면 단점들은 무엇일까? 먼저 코드 생산성이 가장 꺼림직한 문제일 수 있다. 코드 퀄리티 보다는 빠른 결과물을 원하는 환경이라면 쉽게 도입이 어려울 수 있다. 왜냐하면 개발자들이 TDD 를 공부해야 하고 추가적으로 테스트 코드를 작성해야 하기 때문이다. 필자의 경험으로 처음에는 익숙해지기 위한 시간 때문에 1-2달은 적응시간이 걸린다. TDD가 최소한의 객체지향 프로그래밍을 요구하는 이상 보통 정도하는 1-2년 차 개발자라도 조금 어렵다는 생각이 들 수 있다. 때문에 객체지향에 올바른 이해를 가지고 있는 리드 개발자가 TDD 프로젝트를 리드해 갈 필요가 있다.

추가적으로 결국 미래를 봤을 때 투자한 시간을 충분히 벌 수 있는 잠재력이 충분하다 하더라도 결국 납기일이라는 몹쓸 데드라인이 잡히면 “글쎄,,” 라는 생각이 들 수 있다. 갑을병정 내려가는 프로젝트일수록 퀄리티 보다는 개발기간과 타이밍이 중요하기 마련이고 또한 소프트웨어에서 주인의식을 가지기 힘들 수 있기 때문이다.

마지막으로 개인적으로 체험한 경험적인 이슈가 있다면 TDD로 프로젝트를 진행하면서 테스트가 어려운 예외가 생길 수 있는데 그것 때문에 고민하는 순간이 찾아오게 된다. 뭐 이런 거다. 원칙을 깰 수는 없고 꼼수가 있기는 한데 그 꼼수를 위해서 구조를 바꾸자니 이건 아무래도 아닌 것 같고, 테스트는 말 그대로 테스트일뿐 실제 코드가 더 중요한 상황인데도 불구하고 테스트 원칙 때문에 쉽게 넘어가지 못하는 그런 경우다.

아무튼 이런 단점들이 있다고 하더라도 개발자의 커리어에 있어서는 반드시 TDD를 도입해야만 한다고 필자는 이야기 하고 싶다. 먼저 자신의 객체지향적인 코딩 능력을 향상시킬 수 있기 때문이다. 더욱이 S.I회사가 아닌 자력 소프트웨어를 만드는 경우에서는 더욱더 그렇다. 회사의 입장에서도 처음 TDD의 도입에 대한 실이 많아 보일 수는 있다 하더라도 TDD 도입을 통하여 보다 튼튼한 소프트웨어를 만들 수 있을뿐더러 향후에 관리에도 더 용이하게 된다.

*reference

  • http://www.hoons.net/Lecture/View/644

Share:

0 개의 댓글:

댓글 쓰기