서비스가 지속되다 보면 기능 수정/추가가 반복되면서 코드 베이스가 점점 커지기 때문에, 종국에는 하나의 버튼을 추가하는데 한달이 걸리는 상황이 오는 경우가 있습니다. 개발 복잡도는 계속 끌어내리지 않으면 기하급수적으로 증가하게 되기 때문입니다. 이런 상황이 되면 서비스를 개발하는 것이 매우 어렵게 되는데, 그래서 애자일을 언급하는 글들에서 "지속가능한 개발", "주기적인 Refactoring"이 등장한다고 생각됩니다.
이상적인 프로세스
제가 생각하는 이상적인 개발 방법론은 다음과 같습니다.
1. 애자일 프로세스 안에서 모듈별 설계를 먼저 잡아 큰 그림을 그린다.
2. 각 모듈의 역할을 명확히(구체화) 한다.
3. 모듈별 설계들을 작은 작업 단위로 잘게 나눈다.
4. 작업 단위별 인터페이스"만" 만든 뒤, 그것을 커버하는 테스트 코드를 짠다.
5. 테스트 코드가 통과하는 최소한의 코드가 코드 리뷰를 신청할 수 있는 기준이 된다.
6. 코드 상의 오류나 설계상 미흡한 점들을 리뷰를 통해 함께 고쳐나간다.
요약하자면 "설계 -> 테스트 -> 개발 -> QA -> 배포" 가 순환하는 것입니다.
왜 테스트를 해야 하는가?
변경/추가된 코드가 예상치 못한 부분에서 문제를 일으킬 수 있습니다. 코드베이스가 커질 수록 이런 문제는 더 자주 발생하게 됩니다. 따라서 "기존 코드가 잘 동작하는지" 확인할 필요가 있습니다. 작업을 나눌 때는 각 작업에서 Definition of Done(완료 정의)와 Acceptance Criteria(인수 요건)을 명시하고, 그 두 요건을 충족하는 E2E test(QA가 작성), unit test(개발자가 작성) 해서 테스트도 통과하고 QA도 통과하면 머지되어 배포됩니다. 그렇게 해서 배포된 코드들은 테스트 코드들로 커버가 되어 있기 때문에 다른 코드가 돌아갈 때도 사이드 이펙트를 막아주는 역할들을 하게 됩니다.
유의할 점
이때 유의할 것은 unit test 같이 작은 단위로 테스트하는 것은 유지보수비용이 많이 들고 다들 귀찮아지기 시작하는 시점이 엄청 빠르게 오는 경우들이 많아서 지속적으로 유지하기가 힘들다는 것입니다.
따라서 한 종류의 테스트로 Coverage를 100%를 만들지는 않고, unit test로 커버할 부분, integration test로 커버할 부분, E2E test로 커버할 부분을 각각 커버하고 그 모든 테스트들이 소프트웨어 전반을 자동으로 테스트하도록 만드는 정도로 하기 위해 노력하는 것이 좋습니다.
TDD를 꼭 해야 하나요?
"TDD는 필요 없다" 라고 말씀하시는 분들이 있습니다. 그 말이 "테스트코드가 필요 없다" 라는 말은 아니라고 생각합니다. TDD는 전체 프로세스의 일부일 뿐입니다. TDD가 중심이 되는 것이 아닙니다.
익스트림 프로그래밍의 저자인 켄트 백이 한 워크숍에서 발표를 한 적이 있는데 핵심은 "어떤 순서든 어떤 프로세스로 진행하든 상관없다. 개발 방법론에서 제일 중요한 건 소프트웨어 복잡도 제어다" 였다고 생각합니다. "SOLID, DRY 전부 다 복잡도 제어를 위해서 나온 말이고, 기능 개발의 우선 순위는 투입 시간 대비 이익에 따라서 잡는다" 라고도 했었죠.
TDD는 쓰여진지 꽤 오래된 책입니다. 당시의 개발 환경을 반영하고 있기 때문에 개발 환경이 달라진 지금은 책에 나온 것을 그대로 받아들이기 보단, 현재 환경에 맞게 적절히 사용하는 것이 좋다고 생각합니다. TDD는 전체 프로세스의 일부일 뿐입니다. 테스트가 중심이 되어 개발을 하는 것이 아니라, "설계하고 개발할 때 '테스트'를 짜고 구현 코드를 짠다" 정도의 개념으로 작업해야 합니다.