나는 TDD라는 말을 우테코 프리코스를 준비하면서 처음 접했다.
테스트 주도 개발이라.... 왜 사용하는 건지도 모르겠고, 사람은 구현 목록을 보고 머릿속으로 생각을 하고 들어가야 하지 않나? 싶은 막연한 생각이 있었다.
테스트 코드에 대해 이해하려면 먼저 반대 용어를 살펴보는 것이 좋다.
💋 프로덕션 코드 VS 테스트 코드
- 프로덕션 코드: 프로그램 구현 담당, 사용자가 실제로 사용하는 코드
- 테스트 코드: 프로덕션 코드가 제대로 작동하는지 테스트하는 코드
💋 TDD = TFD(Test First Development) + 리팩토링
테스트를 먼저 작성하고, 리팩토링하는 방법이다.
단순히 순서가 먼저일까? 아직 이 방법을 사용해보지 않아서 어떻게 감을 잡아야 할지 좀 어렵게 느껴졌다.
💋 TDD의 과정
코치가 예를 들어준 방법을 통해서 조금 감을 잡을 수 있다.
1. 실패하는 테스트 코드를 작성한다. 이때 컴파일 에러도 실패다.
2. 컴파일 에러부터, 테스트 코드의 통과까지 빠르게 성공하는 프로덕션 코드를 작성한다.
조금 독특했다고 느껴졌던 점은, 굉장히 이 과정이 답답하게 느껴졌다는 것이다.
예를 들어서, 로또에서 사용될 숫자를 생성하는 클래스를 TDD 방식으로 작성한다고 생각해보자.
로또에서 발생할 수 있는 숫자는 1에서 45이다. 따라서 이외의 값은 예외 처리한다.
사람이고 뇌가 달려있다면 처음부터 0 이하 46 이상의 숫자를 예외 처리하는 코드를 작성하는게 어렵지 않을 것이다.
하지만 코치는 0과 46의 경우만 예외 처리 하고 있는 코드를 작성했다. 속 터졌다.
현재는 우리가 익숙한 도메인을 하고 있지만, 익숙하지 않아서 구체적 구현이 완벽하게 떠오르지 않을 때에 사용할 수 있는 방법이다. 정말 아장아장 하나의 케이스씩 생각하면서 도메인에 대해 파악할 수 있을 수도 있다. 익숙해지기 전까지는 baby step...
사이클을 도표로 요약해보면 이렇다
TDD란 프로그래밍 의사결정과 피드백 사이의 간극을 의식하고 제어하는 기술이다
라고 누군가 멋진 사람이 이야기했다고 한다. 아직은 이해가 잘 되지 않는다...
3. 프로덕션 코드를 리팩터링한다.
TDD 방식은 끊임없이 실패하는 코드를 작성하고, 최소한의 프로덕션 코드로 성공하게 하고, 그 뒤에 코드를 리팩터링하는 방식이다. 리팩터링하다가 실패하면 어떻게 해라는 의문이 들었지만, 리팩터링은 테스트 코드의 결과에 영향을 미치지 말아야 한다. 리팩터링은 동일한 기능 내에서 코드 퀄리티가 높아지는 것이므로, 만약에 리팩터링으로 인해 기능 자체에 변화가 있어서 성공하던 코드가 실패했다면 나의 리팩터링이 잘못된 것이 아닌지 의심해볼 필요가 있다.
💋 TDD를 하는 이유는...? 단위테스트 작성이랑 똑같은 거 아냐? 특별한 장점이 있어?
내가 생각했을 때, TDD와 단위 테스트를 작성한다의 가장 큰 차이는 테스트 코드의 작성 시점에 있다.
TDD는 테스트 코드부터, 단위 테스트는 프로덕션 코드부터 작성한다는 데에 큰 차이가 있다.
TDD를 했을 때에 더 좋은 점은 그래서 무엇일까?
현재 내가 내린 답변은, 실질적이고 회피하지 않는 테스트를 할 수 있다는 것이다.
단위 테스트를 작성하다 보면, 프로덕션 코드를 작성하는 동시에 main 메서드를 통해 테스트하기 때문에 단위 테스트에 대해 잊을 때가 정말 많다. 따라서 의식적으로 단위 테스트를 작성해야 한다.
하지만 단위 테스트를 작성하다 보면, 동시에 '아, 다음 기능도 구현해야 하는데 지금 테스트코드를 쓰고 있어야 하나?`라던가, `이 부분은 너무 테스트하기 어려운 것 같은데 그냥 슬쩍 넘어갈까?`하는 충동이 들 때가 정말 많다. 실제로도 로직의 정말 메인이 되는 부분을 테스트 하는 경우도 있지만, 부수적인 부분만을 꼼꼼히 테스트하는 경우도 많았다. 코드를 작성하면서 뇌에 여러 가지 다음 TODO에 대한 부하가 걸리는 경우가 많다는 의미이다. 이런 점에서 생각해보면, TDD는 1단계에서는 단위테스트만을, 2단계에서는 프로덕션 코드만을 그 후에는 리팩터링만을... 이렇게 한 번에 한 가지만을 생각하기 때문에 뇌에 부하가 적고 따라서 더 의식적으로 모든 코드를 통제하는 느낌이 드는 것 같다.
결과적으로 단위 테스트를 작성하는 방식은, 커버리지만 높고 사실 중요한 부분을 테스트하지 못하는 경우가 발생한다.
작성된 프로덕션에 대한 테스트를 의무적으로 추가하는 느낌이 들 때도 많다.
이런 점에서 TDD 방식은 좀 더 진정성 있게 프로그램의 동작을 테스트하는 방법인 것 같기도 하다.
💋 TDD를 할지 결정하는 기준
그렇다면 TDD가 이렇게 좋으니 만능일까?
프로그래밍에 만능, 절대적 규칙은 없다. 내가 코드를 작성해 보면서 어떤 경우에 TDD가 유용했는지, 어떤 경우에는 프로덕션 코드부터 작성하는 것보다 못한 결과가 나왔는지 경험적으로 생각하면서 나만의 기준을 세우는 것이 좋다.
우리 코치가 말해준 자신만의 기준은 아래와 같다. 한 사람의 의견일 뿐이지만 코치니깐 적어본다.
첫째, 프로그램의 input, output이 명확할 때
둘째, 프로그램에 대한 이해도가 부족해 구현 코드에 대한 상상이 되지 않을 때
셋째, 머릿속에 그려지더라도, 비즈니스의 핵심이라 문제가 터지면 큰 문제가 되는, 중요도가 높은 부분의 코드를 작성할 때
제한된 시간, 자원 안에서 얼만큼 할 것인지는 개발자의 선택이다. 따라서 나만의 기준을 만들어야 한다는 것이 또 결론이다.
💋 TDD 원칙
TDD는 보통의 프로그래머가 처음 사용하는 방식과 정 반대의 순서를 가지기 때문에 의식적으로 하지 않으면 나도 모르게 프로덕션 코드에 먼저 손을 대고 있기 쉽다.페어가 제어해주는 것이 편한 것 같다.
누군가의 페어가 된다면, TDD 차단기가 되어주자!
1. 실패하는 단위 테스트를 작성할 때까지 프로덕션 코드를 작성하지 않는다.
2. 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
3. 현재 실패하는 테스트를 통과할 정도로만 프로덕션 코드를 작성한다.
🤙 내가 TDD에 집착하는 이유???
첫째로는, 나는 사람이기 때문이다. 요구사항 추가, 변경 때문에 소스 코드를 수정하고 불안함에 살고싶지 않고, 특히나 돈이 걸려있으면 코드 건드리는게 고통스럽고 부담스럽다. 너무너무 불안하다. 심리적 안정감을 느끼려고 테스트 코드를 먼저 작성한다.
둘째로, 마찬가지로 내가 사람이기 때문에 한 번에 한 가지에만 집중할 수 있다.
한번에 테스트 코드 작성, 프로덕션 코드 작성, 리팩터링 모두 동시에 하기 어렵고, 동시에 하다보면 한 가지를 까먹기 쉽다.
마지막으로는, 재미있기 때문이다. 빠른 피드백을 받을 수 있어서 효율이 높아지고, 재미있다!
처음부터 완벽한 설계를 하려고 하지 말자. 점진적으로 설계는 개선해 나갈 수 있다.
다른 사람의 코드와 비교하면서 이 사람은 왜 이렇게까지 했지? 싶은 부분이 느껴질 때가 있다. 이해하기 어려운 코드도 많다. 대부분은 확장성을 고려한 코드인데, 코치는 좋게 말해서 확장성, 나쁘게 말하면 오버 엔지니어링(과도한 추가비용)이라고 한다. 오버 엔지니어링도 개발자가 경계해야 하는 것 중 하나이다.
변화에 빠르게 대응할 수 있는 코드를 작성하는 것에 노력하자!
'우아한테크코스5기' 카테고리의 다른 글
[우테코] 좋은코드: 좋은 코드의 조건은 끝이 없지만 그중 몇가지... (0) | 2023.02.17 |
---|---|
[우테코] 웹 기초: HTML, CSS, JS를 사용해 자기소개 페이지 만들기 (0) | 2023.02.17 |
[우테코] 코드 품질: 좋은 코드는 어떤 코드일까? (0) | 2023.02.08 |
[우테코] 단위테스트: 좋은 단위테스트에 대한 고민... 단위테스트는 꼭 필요한 것일까? (0) | 2023.02.08 |
[우테코] 자바 쌩초보의 우아한테크코스 5기 최종 합격 후기 (11) | 2023.01.02 |