5. TDD
Test Driven Development는 매우 짧은 개발 사이클을 반복하는 소프트웨어 개발 프로세스 중 하나이다. 개발자는 먼저 요구사항을 검증하는 자동화된 테스트 케이스를 작성한다. 그런 후에, 그 테스트 케이스를 통과하기 위한 최소한의 코드를 생성한다. 마지막으로 작성한 코드를 표준에 맞도록 리팩토링한다.
[1] TDD Cycle
- 작은 테스트를 추가한다.
- 모든 테스트를 실행하고, 실패하는 것을 확인한다. 컴파일 되지 않을 수도 있다. 프로덕트 코드를 건드리지 않았으니 당연하다.
- 빨리 테스트가 성공하도록 코드를 개발한다. 어떤 죄악(함수가 무조건 특정 상수를 반환)을 저질러도 괜찮다. 빨리 테스트가 성공하도록 만들자.
- 모든 테스트를 실행하고, 성공하는 것을 확인한다.
- 리팩토링한다.
- 3번단계에서 죄악을 저질렀다면 이제 모든 케이스에서 성공하도록 여러 테스트 코드를 추가해보자.
- 테스트는 당연히 실패했고, 이를 성공시키도록 죄악을 치워보자.
- 기능이 완성되면서 테스트가 성공이된다. 하지만, 코드의 중복이 있다. 코드가 안 이쁠 수 있다. 괜찮다. 테스트코드가 성공하는 내에서 이쁜 코드를 만들어보자. 맘대로 바꿔도된다. 테스트만 성공하면 되니 리팩토링의 두려움도 사라진다.
- 개발 중 문뜩 "아 이거해야되는데?" 라는 생각이 든다. 이 때 바로 그 작업을 하지말고 메모장에 To-Do List를 추가하자. 이후에 하나하나 To-Do List를 제거하자. 이렇게 하는 이유는 현재 작업하는 부분에 집중하기 위해서다.
[2] TDD는 두려움을 관리한다.
- 여기서 말하는 두려움이란 지금 작성중인 로직이 정상적으로 동작하나?에 대한 의구심이다.
- 복잡한 구현 알고리즘 문제를 풀 때 생각해보자. 처음부터 끝까지 한번에 프로덕트 코드를 만들고, 한번에 테스트를 하는 경우는 드물다. 물론 똑똑한 개발자라면 가능하지만 적어도 본인은 아니다. 큰 기능을 작은 기능으로 쪼개고, 다양한 데이터를 넣어보면서 테스트를 수행한다. 버그가 나와도 기능을 쪼갰기 때문에 버그 포인트를 쉽게 찾을 수 있다. 즉, 단계를 나누고 디버깅을 통해 검증하면서 나아간다.
- TDD도 유사하다. TDD는 매 순간을 자동화된 테스트를 통해 확인받고 나아가는 개발 방법이다. 테스트는 테스트 코드가 될 수 있고, curl로 api를 호출할 수도 있고 자동화된 방법이라면 모든 괜찮다고 생각한다. 이전 단계의 기능을 마음 한켠에 신경쓰지 않고 '현재 단계' 로직만 집중하면된다. 개발 중 문뜩 이전 로직을 신경쓰거나 로직 오류가 발생할 때 이전 로직을 신경쓰지 않고 현재 로직에만 집중하면된다. 심리적으로 '이전 로직이 틀렸을까?' 요런 불편한 감정을 최소화한다.
- 만약 복잡한 프로덕트 코드를 한번에 짜고 테스트를 수행하는데 잘못된 점을 발견하면 어떨까? 아마 지금까지 힘들게 짠 프로덕트 코드를 다 수정해야한다. (수정하지 않더라도 정상적으로 동작하는지 머릿속으로 일일이 확인해야한다.) 아깝다. 하지만 TDD를 통해 이전에 점진적으로 검증받았다면, 이전에 개발한 로직은 신경쓰지 않아도된다.
- 마지막으로 리팩토링할 때 수월하다. 모든 케이스를 검증할 수 없겠지만 기존 테스트 코드가 있으니, 테스트를 만족하기만 한다면 마음 편히 리팩토링할 수 있다. 이건 테스트 코드의 장점이기도 하다.
[3] 현재 하는 일에 집중한다.
- 복잡한 기능을 한번에 짜기 힘들다. 따라서 작업을 분할하고 이를 합치는 방향으로 개발한다. 앞서 TDD는 각 단계마다 검증하면서 나아간다고 했다. 따라서 분할한 작업에서 오류가 나온다면 이전 단계의 오류는 신경쓰지 않고 현 단게만 생각하면된다.
- 앞서 To-Do List를 말했다. 작업 중 문뜬 여러 생각이 난다. 이거 고쳐야하고, 이거 추가해야하고 등등 여러가지다. 그런 것들은 필요한데에 메모하고, 원래 하던 작업에 집중한다. 본인은 막 컴퓨터처럼 스위칭이 자유롭지 않다. 원래 하던일만 잘하고 싶다.
[4] TDD에 대한 개인적인 생각
테스트 코드를 먼저짜나, 프로덕트 코드를 먼저짜나 그게 무슨 차이가 있지?
- 테스트 코드를 먼저 만들고, 프로덕트 코드를 만드나 순서를 바꾸는 거나 큰 차이는 없다고 생각한다. 다만, 테스트 코드를 먼저 생성한다면 자연스럽게 단계를 쪼갤 수 있고, 기능을 사용하는 관점에서 먼저 생각할 수 있다. 물론 객체지향 설계를 잘해서 적절히 코드의 책임을 분배하면 되겠지만, TDD를 통해 자연스럽게 기능을 쪼개기부터 시작할 수 있다.
TestCode가 많다면 무조건 좋을까?
- 테스트 코드가 많은건 edge case를 많이 잡아줄 수 있다는 측면에서 좋다. 하지만 프로덕트 코드보다 테스트 코드를 수정하는데 시간이 많이 걸릴 수도 있다.
- 결국 우리가 만든 로직의 결함을 잡아주기 위해 테스트 코드가 많으면 좋고, 그렇다고 유지보수할 때 테스트 코드에 너무 시간을 쓰기도 아깝다. 코드 한줄 바꿨는데 수 많은 테스트 코드를 고칠 수도 있다. 본인은 상황에 따라 테스트 코드를 추가하면된다고 생각한다. 즉, 테스트 커버리지를 높이기 위한 테스트는 굳이 필요 없다고 생각한다.
- 금융, 방산, 보안과 같이 절대 edge case가 나오면 안되는 도메인에서는 시간이 걸리더라도 엄격히 테스트 코드를 추가하는게 맞다고 생각한다.
- 핵심 로직이 담긴 부분은 나중에 유지보수시 실수로 로직이 깨지는걸 방지하고자 필수 로직에 대한 테스트 코드는 반드시 추가해야한다.
- 실제 서비스 중 예상치 못한 데이터 인입, 시나리오, 잘못된 함수 사용 등에 대한 테스트 코드는 추가하자.
- 관성적으로 테스트를 추가하는건 지양하고싶다. 유지보수가 너무 힘들다.
[5] 총평
TDD는 작은 과정을 조금씩 쌓아올려나가는 개발 방법론이다. 각 과정마다 테스트를 통해 확신을 얻고, 현재 작업하는 부분에만 신경쓴다. 이를 위해 적절한 분량의 단계를 나누고, TO-DO List를 활용한다.