나는 여러 회사의 채용공고들을 보는 것이 취미이다. 채용공고를 보면 그들이 어떤 개발자를 원하는지를 알 수 있고 이를 기반으로 내가 어떤 개발자로 성장해야 하는지에 대한 방향성을 잡아 갈 수 있다. 각 채용 공고안에는 거의 빠짐없이 포함되어있는 항목이 있다. 그것은 바로 '테스트 코드 작성경험'
테스트 주도 개발이라는 키워드는 개발자의 길로 뛰어든 초창기부터 접하였지만, 그것에 대한 필요성을 딱히 느끼지 못하였다. 이유는 단순했다. 귀찮고, 딱히 필요성을 느끼지 못해서.
내가 개발하는 것의 대부분은 REST API였고, 굳이 테스트 코드를 만들지 않아도 개발해서 서버를 띄우고 API 게이트웨이에 요청을 날려보고 음... 잘 되네 하고 넘어가면 되는 부분이었으니까.
그저 가끔 반복적으로 테스트하게 되는 부분에 대해서만 따로 스크립트를 관리하는 수준이었다. (사실 그마저도 제대로 관리를 하지 않아 재작성하게 되는 일이 부지기수였다)
하지만 서비스가 확장되면서 유지보수 해야되는 범위가 커지고, 여러 개발자들과 협업을 하게되며 그 필요성을 느끼게 되었다.
처음에는 기껏해야 두세개의 코드 파일만 보면 되는 수준이었기에 코드를 새로 작성하거나 수정했을 때 그것에 대한 사이드 이펙트를 예측하는 것이 어렵지 않았다. 하지만 볼륨이 커지고 나니 각 코드들은 복잡한 의존성을 자연히 가지게 되었고 코드를 작성했을 때 '이 코드가 제대로 돌아갈것이며, 사이드 이펙트가 발생하지 않을 것이다' 라는 것에 대한 확신이 옅어지기 시작했다. 그리고 옅어진 확신은 자연히 에러로 이어졌다. QA단에서 테스트 환경에 배포된 프로그램을 아무리 테스팅 한다고 해도 그것은 한계가 있었다.
또한 특정 라이브러리 혹은 언어의 새로운 기능이 출시되어 이를 사용하기 위해 버전업이 필요한 경우가 있어도 그에 대한 사이드 이펙트 예측이 불가하여 쉽사리 적용하기 힘든 경우도 다수 발생하였다.
만약 각 모듈에 대한 테스트 코드를 짜두었다면 어땟을까. 에러율이 0%로 떨어지지는 않을테지만 적어도 지금보다는 훨신 수정에 대한 두려움이 적었을 것이다.
여러 개발서적(테스트 주도개발, 클린코드) 에서 한결같이 나오는 이야기가 있다.
'가장 빠른 길은 제대로 된 길로 가는 것이다' 라는 내용이다. 일단 지금 당장 원하는 기능을 구현하기 위해 필요한 스텝을 무시하고 진행을 하게되면, 결국 다시 되돌아와서 점검해야한다. 그리고 그 비용은 제대로 된 스텝을 밟았을 때보다 훨씬 커진다.
개발은 크게 설계 > 구현 > 테스트 > 배포 의 단계로 이루어지는데 후자로 갈 수록 에러가 발생하였을 때의 처리 비용은 높아진다. 때문에 가능하다면 설계 혹은 구현단계에서 최대한 잘못된 것들을 식별하여 바로잡아야 하고 그것이 테스트코드를 작성해야 하는 가장 큰 이유 중 하나이기도 하다.
그럼 테스트 주도개발이란 무엇일까, 그냥 테스트코드를 열심히 작성하여 커버리지를 높이면 되는건가?
아니다. 테스트 주도 개발이라는 것은 말 그대로 테스트가 주도하는, 테스트가 우선시 되는 개발 방법을 말한다.
다시 말해서 서비스 코드를 먼저 작성하고 그에 대한 테스트 코드를 작성하는 것이 아닌, 테스트 코드를 먼저 작성하고 나서 서비스 코드를 작성하는 것이다.
평소에 나는 개발에 대한 요구사항이 나오면 이런 방식으로 개발을 해왔다.
1. 요구사항에 대한 대략적인 구현 방법을 머릿속으로 그린다.
2. 머릿속으로 그린 구현 방법을 코드로 옮긴다.
3. 막상 코드로 옮겨보니 부족한 부분이 있어 수정한다.
4. 이제 잘 될 것 같다, 실행시켜본다.
5. 에러가 난다, 수정한다.
6. 해당 문제는 해결되었으나 혹시나 해서 다른 입력값을 넣어봤더니 에러가 난다.
7. 수정하고 돌려보니 잘 돌아간다.
8. 테스트 환경에 배포하고 QA팀에 맡긴다.
이 때 아래와 같은 문제가 존재하였다.
추후 해당 코드를 수정하거나 기능을 추가할 때 6 - 7번 작업을 반복하게 된다.
테스트를 염두에 두지않고 작성한 코드다보니, 간단한 테스트도 하기가 어렵다.(하나의 클래스 혹은 함수에 너무 많은 입력변수가 존재한다거나, 내부 상태값 변경에 따른 수많은 케이스가 존재)
때문에 다양한 케이스에 대해 테스트 하기도 어렵다.
개발할 때의 컨디션이나 중요도 혹은 필요 개발 기간에 따라 테스트 정도가 달라진다.(바쁘거나 기한이 촉박하면 대충 하고 QA가 알아서 잘 해주겠지... 한다거나...)
가끔 정말 뜬금없는, 생각지도 못한 케이스에서 에러가 발생한다.
TDD를 적용하면, 다음과 같은 플로우로 개발하게 된다.
아직 실제 프로덕트 개발에서 적용해보지는 못하였고, TDD 서적에 있는 Java 언어 기반 객체지향 프로그래밍 방식으로 되어있는 예제를 JS기반 함수형 프로그래밍 방식으로 바꾸어 작성해보았는데 아래와 같은 장점들을 느낄 수 있었다.
테스트 코드를 먼저 작성하다보니, 자연히 함수나 클래스의 인터페이스를 먼저 구현하게 된다. 무작정 기능을 구현하는게 아니라 설계를 하게 되는 것이다.
한번 테스트 코드를 작성해놨으니, 추후에 수정하거나 할 때에도 별도의 테스트 케이스를 고민하거나 스크립트를 작성할 필요가 없다.
테스트를 염두에 두고 작성하다보니, 최대한 순수함수 위주의 구성으로 작성하게 된다.
컨디션이나 기한에 상관없이 언제나 동일한 품질의 코드를 작성하게 된다.(물론 계속 TDD를 따른다는 전제하에)
그렇게 나온 코드는 확실히 이전보다 훨씬 깔끔해 보인다.
마지막으로 이건 나만 그런지는 모르겠는데, 테스트가 통과될 때 마다 희열을 느끼게 된다.