켄트 벡이 대답하길 2탄from 켄트 벡이 대답하기 2탄 : TDD 에서의 테스트 Q: TDD의 테스트는 두가지 목적이 있는 것 같다. 하나는 디자인 시의 가이드, 또 하나는 리팩토링 때의 회귀 테스트. 전자의 경우에 나온 테스트는 리팩토링의 안전성을 보장하기에는 성글어서 문제가 될 수 있다. 그렇다면 어떻게 해야 하나?
>>'디자인 시의 가이드'에서 디자인이 무엇인지 잘 모르겠네요. 테스트가 디자인을 할 때 가이드 역할을 한다는 것은 테스트가 알고리즘과 인터페이스를 찾아준다는 것으로 보입니다. 테스트를 만들면 그 테스트를 패스하기 위한 인터페이스와 알고리즘이 나올텐데 이 과정들이 유도되는 것을 '디자인시의 가이드'라고 한 것인가요? 결국 질문은 "리팩토링할 때 기존 테스트 코드(디자인 시의 가이드로 만들어진 테스트)가 리팩토링을 보장해 주지 못한다. 어떻게 해야 하는가?"라는 의미로 읽었습니다.A : "켄트 말하길, 디자인, 테스트의 분리가 이상하다. 단계(phase)를 만들어 넣는 것 같다. 나는 중요한 테스트라면 처음 테스트를 만들 때 다 한다. 나중에 깨질 것 같은, 불안한 부분이 있을 때 뒤로 미루지 않는다. 그러나 리팩토링할 때 뭔가 새는 부분을 찾았다면 나는 새로운 것을 배운 것이다."
각각의 말들에 대해서 고민을 하게 되다.
'디자인, 테스트의 분리가 이상하다. 무언가 단계를 만들어 넣는 것 같다.' TDD 를 진행하는 중에 최종 코드 상으로는 그 둘이 구분되지 않는다. 다만, 이 코드를 작성하는 과정 중에 사고의 분리가 있거나 없거나 하는 것으로 이 단계가 구분된다.
개인적인 경험으로는, '디자인 과정 중에 나온 테스트' 의 경우 디자인을 우선시 하기 위해서 테스트 코드에의 넣는 입력 대비 아웃풋을 간략히 하고, 구현을 진행한다. 구현 중 Fake it 을 하더라도, 최종적으로 Real Implementation 을 진행한다. 이 경우를 생각하면
1. 코드 구현 상으로는 Real Implementation 으로, 이미 완성된 결과물이 나온다. (코드를 작성할 때 당시 생각할 수 있는 선 내에서)
2. 그럼에도 불구하고, 처음에의 테스트 코드 수가 그대로 유지되는 경우가 많다. 테스트 작성은 비용이 들면서도, 이 비용 자체는 실제 구현을 위한 직접비용이라기 보다는 간접비용에 더 가까우므로, 추가 테스트를 잘 작성하지 않으려고 한다.
여기서 2번째 부분, TDD 초심자와 TDD 에 익숙한 사람 둘 다 실수 할 가능성이 높은 상황일 것 같다. 아마 대부분의 개발자의 경우 2번에서 테스트의 수가 멈춰버릴 것이다. 그리고 TDD 에 익숙하다고 생각하는 사람들은 '이 부분은 안전해' 하면서 테스트를 추가 작성하지 않고 Test Step 을 깨고 Real Implementation Step 으로 진행할 경우들이 있을 것이다. 그리고 Real Expert 는 추후 요구사항이 늘어날 때, 2번 파트와 관련하여 관련되는 객체들을 다시 찾고, 아는 만큼의 예외들에 대한 테스트들을 추가적으로 작성할 것이다.
* 오히려 'Fake it - real implementation' 혹은 'triangulation - real implementation' step 으로 TDD 를 진행하는 사람의 경우 2번에서의 실수를 방지할 것 같다는 생각할 것 같다.
'중요한 테스트라면 처음 테스트를 만들 때 다 한다. 나중에 깨질 것 같은, 불안한 부분이 있을 때 뒤로 미루지 않는다.' - '아는 만큼의 Courage를 가지고 TDD를 진행한다.' 라고 해석할 수 있을까. 이에 대해서 고민되는 점은, '현재 프로그램 중 불안한 부분이 있긴 한데, 이에 대해서 테스트로 작성할 지식이 없다면? 어떻게 서술해야 할지 모르겠다면? 그럼에도 리팩토링은 진행해야 될 것 같은데.. ' Courage 와 Fear 간의 대립이 시작된다.
>> 저는 '중요한 테스트'란 '문제에 대해서 자신이 아는 만큼의 해답'이라고 이해했습니다. 이 문제를 풀기 위해서는 이 테스트만 통과하면 된다는 것이죠. '불안한 부분이 있을 때 뒤로 미루지 않는다.'라는 것은 '문제에 대해서 이해하지 못한 부분과 해답을 찾지 못한 부분이 있다면 이 부분을 찾기 위한 과정을 먼저한다."라고 이해했습니다. 그리고 그에 대한 대답이 다음에 이어진다.
'리팩토링할 때 뭔가 새는 부분을 찾았다면 나는 새로운 것을 배운 것이다.' Courage 를 가지고 리팩토링 스텝까지 진행을 했음에도 불구하고, 실제 리팩 전-후가 잘못되는 경우는 사람인 이상 누구나 있을 수 있다. 그 경우가 발생했을 때는 보통 사람들은 '아.. 이런. 리팩토링은 많이 위험하구나' 하며 Discourage 되고, 몇몇 사람들의 경우 좀 더 간단하고 쉽게(거기에 시니컬 함을 덧붙여) 'TDD 나 Refactoring 은 여기까지가 한계구나. 사람인 이상 리팩하다 실수 밥먹듯 할텐데. 이렇게 위험한 것을 어떻게 써?'
>> 리팩토링할 때 새는 부분을 찾았다는 것은 자신이 문제를 이해하지 못한 부분이 있었다는 것이고, 오히려 좋은 것이 아닌가요? 그전에 리팩토링을 하면서 이런 새는 부분을 찾을 수 있었나요? '리팩 전-후가 잘못되는 경우'가 무슨 말인지 모르겠습니다. 리팩토링을 했는데 통과했던 테스트를 통과하지 못하게 되는 경우가 있나요? '리팩토링은 많이 위험하구나', 'TDD 나 Refactoring 은 여기까지가 한계구나.' 이렇게 생각하는 사람이 있다는 것도 전혀 와닿지가 않습니다. 아마 '리팩 전-후가 잘못되는 경우'가 무슨 말인지를 몰라서 그런듯 보입니다만 어떤 관련이 있는지 모르겠습니다. >> 문득 'tdd에서의 리팩토링은 tdd를 위한 리팩토링으로 일반 리팩토링과 목적과 방법이 조금 다르다'라는 생각이 들었습니다. tdd의 리팩토링은 어디까지나 다음 이터레이션을 위한 중복의 제거가 목적이라고 생각합니다. 전에 이터레이션이 반복되면서 이전 테스트를 수정해야 하는 경우가 있다. 이럴때 어떻게 해야하는가?라는 질문에 그것은 testcase에 중복이 있어서 그렇다라는 답이 생각납니다. tdd에서의 리팩토링 스텝은 일반 리팩토링의 목적을 모두 가지고 행해질 수도 있지만, 다음 이터레이션을 보다 원활하도록 도와주는 역할이라고 생각합니다. 그리고 켄트 백은 간단히 '그때마다, 나는 새로운 것을 배운 것이다' 라고 이야기한다.
----
답을 듣는 중에 다음과 같은 목소리가 들려온다. 'Fear를 구체화하여 Test 화 하라고 했는데. 책을 찾아보거나, 다른 사람들과 대화를 하거나. 실험을 하거나, 더 공부를 하거나. 왜 그러한 시도들을 해보지 않는가?'
>> Fear가 무엇인지를 잘 모르겠습니다. 무엇에 대한 Fear인가요?>> 1002님이 생각하신 것에 대해서 궁금한 점들이 있어서 트랙백을 달았습니다. 글을 쓰면서 정리한 제 생각은 다음과 같습니다. tdd에서의 리팩토링은 일반 리팩토링과 성격이 다르다. 그런데 1002님의 의문점들은 tdd의 리팩토링을 일반 리팩토링과 마찬가지로 적용하려다보니 tdd의 test가 그것을 충족하지 못한다라고 느꼈고 이를 어떻게 해야 하는가라는 질문으로 이해했습니다. 제가 생각하는 것은 tdd의 리팩토링은 훨씬 좁은 범위로 tdd를 도와주기 위한 것입니다. 따라서 많은 리팩토링이 될 필요도 없을 것입니다. tdd의 test가 보장해주지 못하는 리팩토링은 할 필요가 없다고 생각합니다.