(이미지 협찬 yes24)

 

펭귄너구리 채수원님이 보내주신 TDD책을 어제 받았다. 지금까지 제법 많은 책을 우편을 통해서 받았지만 이 책만큼 기다렸던 것도 없었던 것 같다. 한동안 뜨겁던 TDD에 대한 열기가 막상 TDD를 적용하려고 했을 때 겪게 되는 막막함과 안티들의 큰 목소리 덕에 많이 식고 있는 느낌이었다. 디자인 패턴이니 SOLID는 하는 얘기만 들으면 온몸에 두드러기가 나고 환청이 들린다는 일련의 인간들은 TDD에도 역시 비슷한 이유로 비난을 퍼부어왔다. TDD만큼 닥치고-안티가 많은 것도 없다. 안티는 아닐지라도 TDD를 좀 더 나은 코드를 만들고 즐거운 개발을 하는데 사용할 수 있는 유용한 도구와 실천기술이 아니라 남들에게 우월감을 드러내고 잘난척하기 위해서 어설픈 지식으로 떠들어 대는데 사용했던 사람들도 사실은 TDD 슈도-안티군에 포함되야 할 것이다. 그러는 와중에 TDD에 대해서 오해하게 되고 거리감을 두게된 많은 개발자들이 있는 것을 보며 많이 안타까웠다.

안티에는 답도 없고 약도 없다. 그래서 신경 쓰지 않는다.

차라리 진지하게 TDD에 접근하려고 하지만 막연한 느낌과 무엇을 어떻게 해야 할지 알지 못해서 당황해 하는 사람들에게 좋은 안내를 해주고, 스스로 TDD와 테스트 코드 작성의 즐거움을 느끼게 해주는 것에 관심을 가지는 것이 나을 것이다. 그러기 위해서 몇가지 넘어야 할 장벽이 있는데, 바로 그 장벽을 낮춰주는 데 기여해줄 수 있는 것이 바로 이 책, "TDD 실천법과 도구"라고 생각한다.

펭귄너구리라는 아이디를 쓰는 채수원님은 내가 아는 가장 성실하고 진지한 엔지니어의 한 명이며 재치있고 유머감각 넘치는 이야기로 귀에 쏙쏙 들어오는 설명을 잘해주는 초특급 강사이기도 하다. 치열한 환경의 현장 개발자들에게 TDD를 가르치고 보급하려고 애쓰면서 가졌던 많은 고민과 생각을 풀어놓은 것이 바로 이 책이다. 그래서 이 책의 내용은 살아있고 싱싱하다. 그래서, 지난 몇년간 TDD를 사용하려고 애써왔던 나에게도 이 책은 참 소중하다. 매 페이지마다, 얼마나 많은 연구와 리서치를 했왔고 그것을 적용해보고 고민하는데 얼마나 많은 시간을 써왔는지를 느끼게 해주는 내용으로 가득하다.

이 책은 “TDD를 안하는 놈은 루저"라는 박탈감을 느끼게 해서 허둥지둥 TDD에 뛰어들어 고생과 삽질만 하고, 어디에 하소연도 못하면서 억지로 좋은 척, 아는 척 하게 만드는 그런 책이 아니다. 오히려 편안한 마음으로 TDD를 이해하게 해주고, 그동안 어설프게 TDD를 적용하다 받은 상처를 보듬어주고, 용기를 가지고 한발짝씩 TDD를 해보다가 어려움을 만나면 언제든 다가와 조력자가 되어 줄 수 있는 그런 책이다.

물론 이 책을 본다고 갑자기 TDD의 고수가 되는 것은 아니다. 김창준님이 추천사에도 썼듯이 TDD는 한번에 비급을 배워서 쉽게 마스터할 수 있는 것이 아니다. 오히려 충분한 시간을 들여서 고민하고 생각하고 많은 시도를 해보면서 차근차근 몸에 익히는 내공을 쌓는 훈련이 반드시 필요하다. 프로그래밍이라는 것이 원래 그렇듯이 TDD에도 정답이란 없고, 항상 더 나은 방법이 있을 것이라는 기대를 가지고 새로운 시각을 가지고 창의적인 접근을 하려는 노력이 동반되야 한다. 이 책에 소개한 내용이나 인용한 글들이 모두 정답이라는 생각을 가지기 보다는, 저자와 한판 붙어보자는 심정으로 책을 읽는 내내 가상의 토론을 즐기는 것도 좋을 것이다. 무엇보다도 꾸준히 작은 분량이라도 TDD를 해보는 습관을 들이는 것이 중요하다. 내가 작년초에 결심한 것 한가지는 TDD를 거창한 개발에만 사용하는 것이 아니라, 평소에 간단한 코드 하나를 만들 때도 사용하도록 습관을 들이자는 것이었다. 그 뒤로 HelloWorld 수준의 간단한 코드를 만들때도 항상 테스트를 먼저 만들어보려고 노력했다. 그리고 시간이 얼마 흐른뒤에 느낀 것은, 이전에는 TDD를 한다면 뭔가 힘을 잔뜩 주고 TDD를 해보고 말테다라는 긴장감 있었는데,  TDD를 코딩 습관으로 만들어버린 후로는 그냥 평범하고 자연스러운 것이 되어버렸다. 테스트를 따로 만든다가 아니라 테스트가 그냥 내가 당연히 만들어야 할 자연스러운 코드가 되어버린 것이다. JUnitMax가 테스트를 빌드과정의 하나로 만들어버린 것과 비슷한 느낌이다. TDD를 특별히 한다는 생각도 들지 않는다. 그냥 원래 코드는 그렇게 만드는 것이라는 습관이 들었고 그것이 편하고 자연스럽게 느껴지기 때문이다. 김창준님이 예전에 TDD를 제대로 하려면 최소한 6개월은 수련을 해야 한 기억이 (가물가물) 난다. TDD책을 보고 가끔 개발에 적용하는 시간이 아니라, 매일 빠짐없이 TDD를 좀 더 잘하기 위한 훈련의 시간을 30분에서 한시간이라도 잡고 그것을 6개월간 꾸준히 해야 한다는 얘기라고 생각한다.

이 책에 대해서 한가지 불만이 있다면 그것은 책이 너무 얇다는 것이다. 아이폰과 안드로이드, 트위터 따위가 장악해버린 출판시장에 비인기 종목인 TDD의 책이 나온 것만으로도 다행이라고 생각하지만 그래도 조금만 더 많은 얘기를, 좀 더 구체적으로 할 수 있는 지면이 허용되었더라면 좋았을 것을 이라는 아쉬움이 남는다.

하나 더 바라기는 이 책의 예제를 시연하는 동영상, 스크린캐스트가 공개되었으면 좋겠다. 나는 김창준님과 강규영님이, 그 무뚝뚝하고 어색한 목소리로 TDD를 진행하는 동영상을 우연히 본 것이 TDD에 관심을 가지게된 계기가 되었다. 이 책에 많은 그림과 코드가 잘 나와있긴 하지만 역시 TDD는 그 역동적인 과정을 눈으로 보는게 제맛이다. 수원님이 아니더라도 성실한 독자들 중에서 누군가 만들어 공개하지 않을까 기대도 해본다.

다음 주까지는 스프링 책을 마무리하는 최종 작업 때문에 바빠서 여유가 없겠지만, 그 후에 이 책의 내용을 차근 차근 정리해서 블로그에 올려볼 생각이다.

 

책을 주문하고 싶으면 여기. http://www.yes24.com/24/goods/3908398?scode=032&srank=1

저자의 책 소개를 보고 싶으면 저기. http://blog.doortts.com/128

Apr 222010

http://agile.egloos.com/5299932 에서 인상적인 것은 TLP.

조금 특이할만한 것으로 테스트 주도 개발(TDD)과 코딩 후 자동화된 단위 테스트 붙이기(TLP)를 구분해 놓았는데,  TLP는 테스트를 먼저 만드는 TDD와 달리, 코드가 만들어진 후에 그에 대한 자동화된 단위 테스트를 붙이는 것을 말합니다. 레거시 코드가 있는 경우 혹은 TDD를 하기에는 아직 수련이 충분하지 못한 경우 TLP를 하는 조직을 종종 봤고, 저 역시 맥락에 따라 TLP을 우선적으로 권하기도 하기 때문에 TLP를 따로 구분했습니다

코딩 후 자동화된 단위 테스트 붙이기(TLP), 지속적 통합(CI), 고객 참여(CP)가 성공과 관련이 깊습니다.

실천법 중에서 비교적 성공과 직결되는 것들이 존재한다. 그것은 고객 참여, 리팩토링, 코딩후 자동화 단위테스트 붙이기, 코드 공유 등이다.

TDD와 TLP를 구분해 놓았다는 것이 정말 맘에 든다. 단위테스트, 회귀테스트, 시스템테스트, 자동화 테스트, TDD 등을 마구 뭉뚱그려서 설명하고는 TDD 라고 얘기하는, 사실은 MTDD(뭉뚱그린 TDD)로 인해서 개발자들이 혼란과 오해에 시달리지 않게 하는 것은 중요한 것 같다.

최근에 요청 받은 한 인터뷰에서 나는 후배들에게 TDD를 소개하기는 하지만 권장하지는 않는다고 답변했다. 일단은 자신이 만든 코드에 대해서 자동화된 테스트 코드를 잘 작성하는 것이 중요하다고 생각한다. TDD는 스스로 자동화된 단위 테스트의 가치를 진심으로 느꼈을 때 시작해도 늦지 않을 듯.

그런면에서 별로 좋아하는 사람은 아니지만, TestNG를 만든 Cedric이 극렬 TDD 순수주의자인 밥 삼촌의 TDD 3원칙과 같은 글에  "테스트를 나중에 만드는 게 뭐가 어때서? 테스트를 잘 만드는 것이 중요한 게 아닌가?"라고 반박하는 글을 달곤 하는 것을 보면 쪼금 동감한다.

그러고 보니 생각나는데, 전에 블로그(blog.objectmentor.com/)에 TDD를 변호하는 글을 쓰면서, TDD로 만들어진 제품의 하나로 스프링 프레임워크를 들었는데, 미안하지만 스프링은 거의 대부분 테스트를 코딩 후에 만들면서 개발된 것이다.   따라서 밥 삼촌의 TDD 1원칙(테스트를 성공시키기 위해서가 아니라면 코드를 만들지 않는다)을 위반한 것이다. 따라서 스프링은 TLP라면 모를까 TDD로 개발한 사례로 들기는 부적당하다. 이는 스프링 소스코드의 테스트 코드를 봐도 충분히 알 수 있고, 유겐 휄러한테 직접 확인해본 것(만나자마자 이것부터 물어봐서 좀 미안하긴 했지만)이기도 하니 확실하다. 물론 로드 존슨은 일부 스프링 코드 개발은 TDD로 했다고 얘기한 적이 있으니 전혀 없는 것은 아니겠지만. 그래도 TDD로 개발된 제품 사례로 들기는 부적당하다. MTDD라면 모를까.

그런데 TLP는 무슨 약자인가? Test Last까지는 짐작이 가는데.. P는 뭐지. 구글 검색을 해봐도 나오지 않는데. "코딩 후 자동화된 단위 테스트 붙이기"라는 오해를 방지하기 위해 상당히 꼼꼼한 이름을 붙인 것을 보아서는 꼼꼼하기로 유명한 김창준님이 직접 만든 용어라는 의심이…

블로그에 종종 원색적인 글을 써서 블로고스피어와 트위터버스를 시끌벅적하게 만들어버리는 조카르마가 다시 한건 했다.

며칠전 영회가 "Uncle Bob이 열받았나봐"라고 하면서 알려준 글인 Echoes from the Stone Age를 읽어보았다. 처음 보고는 "관심을 좀 끊을만 하면 다시 등장하는 지겨운 TDD 논쟁이 또 시작된 것인가" 했는데, 발단이 된 글들을 쭉 찾아서 읽다보니 단순히 TDD/단위테스트에 관한 문제가 아니라 더 근본적인 문제에 대한 다른 시각을 가진 사람들의 생각이 충돌한 것이라는 느낌이 들었다.

시작은 조엘의 The Duct Tape Programmer라는 글이었다.  사실은 나도 며칠 전에 언급했던, 요즘 잘 나간다는 Coders at Work이라는 책에 관한 리뷰 내지는 홍보글이다. 그 책에 등장하는 인물 중 한명인 Jamie Zawinski이라는 전설적인 개발자에 관한 이야기를 하면서 평소 자신이 주장하려고 했던 "잘난척하려고 별 가치도 주지 못하는 고급기술 따위에 혹해서 시간 낭비하지 말고 땜빵질을 해가면서라도 그저 빠르게 제품을 출시하는 것이 가장 중요한 것이다. 평균적인 개발자들은 제대로 이해하고 소화하기 힘든 얘기들이나 떠들면서 잘난척 하는 인간들은 재수없다" 라는 얘기를 쭉 풀어나간 것이다.

문제는 처음에는 다중상속이니 C++템플릿이니 멀티쓰레딩 COM이니, CORBA니 하는 것들을 예로 들면서 duct tape programmer는 그렇게 폼나는 고급 기술을 가지고 오버엔지니어링 하느라 쓸모없이 시간과 정력을 낭비하지 않는다라고 잘 설명했는데, 갑자기 그렇게 "오버엔지니어링에 빠져있고 폼나는 기술을 가지고 아는 척 하지만 정작 제대로된 제품을 빨리 만들어내는 것은 못하는 사람들"의 특징으로 디자인패턴에 빠져있다는 것을 언급하고는 이어서 책에 나오는 Jamie Zawinski의 얘기를 인용하면서 이번엔 "단위테스트 따위는 필요없다. 말만 좋지, 그것은 즐기면서 슬슬 개발해도 되는 경우에나 필요한 것이지 제한된 시간에 빨리 제품을 출시해야 하는 실전에서는 별로 중요하지 않다. 고객이 단위테스트 없다고 불평하는 것 봤냐?"라는 식의 이야기를 하면서 슬그머니 이전에 한번 켄트 벡과 밥 마틴을 흥분시켰던 단위테스트 무용론을 끄집어 냈다.

대놓고 "단위테스트는 별 가치도 없고 개발시간만 축내는 것"이라고 비난했다가 켄트 벡과 밥 마틴을 화나게 했던 지난 번의 주장을 이번에는 책을 소개하는 척 하면서 다른 유명 개발자의 입을 빌어서 슬그머니 다시 끄집어 낸 것이다.

이번 글을 읽어보면 조엘이 정말 하고 싶은 얘기가 무엇인지 어렵지 않게 알 수 있다. 개발자란 결국 제때에 빠르게 제품을 내놓는 것이 가장 중요한 가치이고, 비록 duck tape programmer라고 불린다고 할지라도, 그렇게 해낼 수만 있다면 그것으로 충분하다는 것이다. 오히려 유행하는 이론과 기술에 휩쓸리지 않고 그렇게 할 수 있는 용기와 실력이 대단하다는 것이라는 얘기다.

조엘의 이런 사고방식은 stackoverflow.com에 올라온 IoC/DI에 관한 질문에 쓴 그의 답변에도 잘 드러나 있다. 자신은 IoC/DI 기술자체를 판단하고 싶지는 않다고 하면서 IoC/DI를 쓰는 사람은 정말 똑똑한 사람이거나 아니면 다른 사람들은 그들만큼 훌룡하지 않다는 것에 공감할 줄 모르는 사람이라고 비아냥거린다. 마틴 파울러의 화려한 DI에 관한 글을 읽고, 며칠씩 걸려서 200여페이지의 매뉴얼을 끙끙 공부하고서도 제대로 이해도 못한채로 어설프게 써야 하는 것을 왜 구지 써야 하는가 라는 얘기다. 그러면서 IoC/DI는 코드를 읽기 힘들고 하나의 기능을 파악하기 위해서 여러 곳을 뒤져봐야 하는 어려움만 주는 것이라고 믿는다고 한다. IoC/DI없이도 손쉽게 해결할 수 있는 문제를 괜히 어렵게 오버엔지니어링 한다는 주장이다.

결국 그 글은 -21점을 받아 답변의 최하위를 차지했는데, 재밌는 것은 어제 이 글을 봤을 때는 -24였다는 것. 그의 글에 반대하는 사람이 더 많기는 하지만 사실은 동감하는 사람도 제법 있다는 것을 알 수 있다.

 

그의 글과 이어지는 여러 사람들의 이야기에 지속적으로 답변을 하고 있는 밥 마틴도 그랬듯이 나도 그의 글의 기본적인 아이디어에는 동의한다. 불필요한 오버엔지니어링, 실제적인 가치는 주지 못하고 개발을 더디게만 만드는 단지 유행하는 기술이나 이론을 무작정 따르지 말고 제때에 고객에게 좋은 제품을 만들어서 전달하는 것이 가장 중요하다는 것은 사실 대부분의 개발자들이 다 동의할 수 있는 것이다. 그래서 사실은 다들 비슷한 목적을 가지고 있다. 그런데 그런 비슷한 얘기를 하면서도 그 방법에 대해서는 다들 제각각 다른 생각을 가지고 있다는 사실이 재밌다.

 

켄트 벡이나 밥 마틴을 비롯한 애자일 진영의 사람들도 모두 "제때에 가치(제품)를 고객에게 전달한다"는 것을 중요한 전체로 놓고 있다. 그리고 그러기 위해서는 이런 저런 방법 또는 원칙을 따라야 한다고 말한다. 예를 들면 TDD를 비롯한 개발자테스트, 단위테스트가 그런 한가지 방법이다. IoC/DI의 선구자인 스프링의 로드 존슨이 가장 강조한 것은 오버엔지니어링을 피하자는 것이다. 핵심에 집중하고 테스트 하기 좋고 빠르게 개발하면선도 품질이 뛰어나게 할 수 있는 단순한 개발을 위해서 IoC/DI가 필요하다는 것이다.

조엘과 같은 사람들은 같은 이야기를 하지만 그딴 것은 다 필요없다고 말한다. 오히려 테스트를 만드는 것은 개발시간을 더디게 하고, 남들 잘 못하는 것을 들고와서 잘난척 하기 좋아하는 사람들의 망상이라는 것이다. IoC/DI에 대해서도 마찬가지 얘기를 한다.

어떻게 같은 목표에 가치를 두고도 이렇게 다른 이야기를 할 수 있을까. 여당이든 야당이든, 시민단체든 모두 "우리는 서민을 위한다"라는 똑같은 주장을 하는 것과 별 다를바 없어 보이기도 한다.

 

물론 가만히 살펴보면 조엘과 같은 사람들의 주장에는 항상 헛점이 있다. 그들은 항상 왜곡되고 극단적인 형태로 비판대상을 몰고간 뒤에 비난을 퍼붓기를 좋아한다. 세상에 과도하게 적용하고 맹목적으로 추종해도 좋은 기술이 뭐가 있을까? 아무리 좋은 가치라도 맹신을 하는 것은 위험하다는 것은 초딩만 아니라면 다 아는 것 아닐까? 그럼에도 그런 함점에 빠지고, 핵심은 모르고 껍데기만 앵무새처럼 떠들고 다니는 사람들이 존재한다는 것을 부인하지는 못하겠다. 하지만 제대로 그 내용과 가치를 알아보지도 않고, 한번 안좋은 인상을 받았다고해서 무조건 비난을 퍼붓는 사람들도 이해하기 힘들다.

물론 그런 비난의 대상이 되는 기술이나 이론의 특징은 "제대로 이해하지 않고는 제대로 쓰기 힘들다"는 단점이 있다. 내가 객체지향언어와 프로그래밍에 대해서 처음 공부한지 20년이 지났고, 그 이론과 언어가 나오고 발전한지는 훨씬 오래됐음에도 아직도 진정한 OO는 십수년 경력을 가진 개발자들 조차도 제대로 그 가치를 누리기 쉽지 않은 기술이다. 디자인패턴과 그 대표적인 패턴의 이름을 모르는 사람은 없지만, 여전히 패턴의 목적과 내용조차도 제대로 기억하고 적용할 줄 모르는 사람들이 대분이다. 개발자테스트가 또 TDD가 궁극적으로 생산성을 높여주고 품질을 뛰어나게 만들어준다는 점에 대해서는 많은 연구와 경험자들의 이야기를 통해서도 충분히 검증된 사실이지만 사실은 그것을 스스로 느낄 수 있는 개발자는 단위테스트라는 것을 만들어본 사람 중에서 극소수일 것이라는 게 그동안 현장에서 느낀 나의 생각이다.

보통 자신은 그것을 제대로 실전에서 꾸준히 적용하지는 않으면서 화려한 이론을 떠들고 다니고 아는 척 하기 좋아하는 사람들이 있는데, 그런 사람들에 의해서 전파된 이런 가치들은 결국 허무하고 피상적으로 느껴지기 쉽다. 자기 손으로 제대로 테스트를 만들어가면서 개발을 해본 경험도 없으면서, 그래서 현장의 개발자들이 어떤 고민을 가지게 될지를 상상하지도 못하면서도 "테스트와 TDD에 관한 뛰어난 강사"라는 인정을 받고 SI 현장에서 컨설팅을 하고 있는 사람도 보았다.

그런 이론과 가치를 극단적으로 과도하게 적용하려는 시도들도 사람들이 반감을 가지게 만드는 이유일 것이다. DB나 외부 파일, 리소스를 건드리거나 하나의 클래스 이상이 참여하는 것은 단위테스트가 아니라고 당당하게 아티클을 올리는 사람들이 그렇다. "TDD는 단지 디자인 기법이다"라고 당당하게 주장해서 켄트 벡을 짜증나게 만들었던 사람들이 그렇다.

결국 그런 피상적인 전파자들과 극단적인 적용, 또는 그 자체가 특정 기업과 개인의 비즈니스에 도움이 되는 것 외에는 정작 아무런 가치를 주지 못하는 이름만 폼나는 기술이 범람하는 탓에 사실은 좋은 가치를 가지는 것들도 도매금으로 같이 공격을 당하는 것이 아닌가 하는 생각도 든다.

 

아무튼 조엘의 글에서 Jamie Zawinski의 입을 빌어서 한 "단위테스트는 제 때에 제품을 출시하는데 도움이 안되는 기술"이라는 비난에 대해서 Clean Code 아저씨인 밥 마틴이 여러차례 테스트에 관해서 글을 올려가며 설명하느라 애쓰고 있다. 이쁜 손녀들도 여럿 있는 나이지만 그 열정만큼은 정말이지 대단하다.

하나하나 빠짐없이 읽어볼만한 좋은 글이다. 코멘트도 살펴보는 것도 재미있다. 물론 반쯤은 비난글이긴 하지만, 그래도 현장의 개발자들은 이런 이야기를 어떻게 받아들이는지 알 수 있을 것이다.

단위테스트에 관한 이슈의 핵심은 "단위테스트는 개발을 지연시키는가?"인듯 하다. TDD옹호자들의 공통적인 주장은 "시간이 지나면 생산성은 더 높게 올라갈 것이고 따라서 전체적인 개발시간은 더 단축될 것이다"이다. 그 이유는 코드의 품질을 높여주고 디버깅에 시간을 소모하지 않게 해주어 그만큼 안정적으로 새로운 기능을 추가하거나 기존 기능을 수정하는 작업을 빠르게 진행할 수 있기 때문이다. 이를 뒷받침해주는 연구들도 여럿 소개되고 있다.

그런데 사실 그런 연구의 결론만 달랑 보았지 구체적인 연구내용이나 기준은 별로 들어본게 없어서 조금 아쉽긴하다. 그러던 중에 최근에 Misko Hevery가 블로그에 자신이 테스트 작성을 해가면서 개발했을 때의 시간과 코드의 양에 대해서 측정한 것을 공개한 것을 보니 흥미롭다.

테스트와 애플리케이션 코드를 모두 해서 15,000라인쯤 되는 것을 개발하면서 시간과 코드의 양을 측정해본 것이다. 전체 코드에서 테스트가 차지하는 비율은 코드 라인수로 볼 때 40%였다. 그렇다면 그 40%에 달하는 테스트를 작성하는데 걸린 시간은 얼마일까? 비슷하게 40% 전후로 나올 것 같지만, 사실은 10%에 불과했다고 한다. 그 이유는 테스트 코드는 애플리케이션 코드에 비해서 각각이 독립적이고 내용이 명확하기 때문에 작성하기 쉽기 때문이라고 한다. 대체로 이상적인 테스트코드 대 애플리케이션 코드의 비율이 1:1 정도로 보았을 때 테스트 코드를 작성하기 때문에 추가되는 시간은 10%가 조금 넘을 뿐이다. 사실은 나머지 90%를 만드는 시간도 테스트를 안만들었을 때보다 훨씬 줄어들엇을 것이 분명하다.

테스트 코드를 안만들고 개발하는 것은 가능할지 몰라도 테스트 자체를 안할 수는 없다. 결국 수동으로 동작시켜가면서 테스트하고, 문제가 생기면 코드를 재차 살펴보고, 또는 디버거를 돌려가며 디버깅하거나, print문을 써서 콘솔에 값을 찍어보는 등의 테스트를 하면서 시간을 충분히 소모한다. 그러면에서 제대로 테스트코드를 만들어가면서 개발하는 것이 개발 시간을 단축시킨다는 것은 일반적으로 맞다.

하지만 왜 많은 사람들이 시도를 해봤으면서도 단위테스트 또는 TDD에 반감을 가지는 것일까? 그것은 대부분의 개발자들은 구글 개발자들에게 테스트와 TDD를 가르칠 수 있는 실력을 가진 Misko Hevery가 아니기 때문이다. 막상 테스트를 작성하려고 하면 막막하다. 테스트나 TDD책에 나온 예제들을 아무리 봐도 DB와 웹을 사용하는 일반적인 현장의 시스템은 어떻게 테스트를 만들어야 하는지 막막한게 정상이다. 테스트를 만드는 기술 자체도 어렵거니와 그것을 자신이 만드는 시스템에 최적화해서 적용하는데도 상당한 실력이 필요하다.

나는 그 갭이 상당히 크다고 생각된다. 그런면에서 여기 저기서 단위테스트가 좋다는 얘기는 듣고, TDD도 해야한다고 배웠고, 심지어 PM이나 매니저들이 맹목적으로 최소 테스트커버리지라도 갑자기 요구했을 때 힘겹게 그것을 시도 해보다가 내상을 입은 사람들도 제법될 것 같다.

예전에 알면서 왜 안할까 – TDD라는 글을 쓴적이 있다. 그때 했던 얘기는 "사람들이 TDD가 좋다고 말하면서도 사실은 마음 속에선 그게 좋다고 생각하지 않기 때문이다"라는 것이다. 정말 좋다고 생각하고 그것을 느꼈다면 하지 말라고 뜯어말려도 몰래 한다. 사람이 담배를 안끊는 이유는, 말로는 "담배가 건강에 해롭지"라고 하지만 정말 해롭다고 생각하지는 않기 때문인 것처럼 진심으로 그것이 필요하다는 것을, 좋다는 것을 모르기 때문에 안할 뿐이다. 물론 오래된 습관이나  환경적인 문제, 하려고 해도 막막해지는 점 등도 그런 것을 방해하는 이유겠지만.

 

얼마전 모 SI업체에서 아키텍트나 프레임워크 개발자들을 대상으로 교육을 한 적이 있다. 그때 한분이 이런 질문을 했다. "팀원들에게 테스트를 만들라고 설득하기가 힘들다. 어떻게 하면 좋냐"라는 것이다. 아무리 화려한 연구결과를 들이밀고 다양한 이론과 논리를 가지고 "테스트가 좋다"라고 설명해봤자 이해하지 못하는 경우가 대부분이다. 억지로 시킬 수는 있지만, 그러면 효과는 커녕 반감만 생긴다.

뭐라고 대답해야 할까 고민하다가 이렇게 이야기 해줬다. "TDD나 테스트를 만드는 것이 얼마나 좋은 것인지 경험시켜주세요". 무작정 모든 개발에 테스트를 적용해라고 강요하기 보다는 테스트를 만들면 피부로 그 장점을 느낄 수 있는 특징을 가진 그런 기능이나 클래스를 개발할 때를 잘 골라서 같이 해보는 것이다. 또는 비교하게 만드는 것이다. 그래서 "아 정말 좋네"라고 스스로 느낄 수 있다면 아마도 그 후로 테스트를 좀 더 진지하게 생각하고 써보려고 할 것이다. 오래전 한 프로젝트에서 나름 난이도가 높은 로직을 구현해야 하는 개발자 한명에게 "본격적인 복잡한 로직이 들어가는 것은 반드시 테스트를 만들어가면서 개발하라"고 지시한 적이 있다. 그리고 얼마 후에 그 개발자가 하는 말이 인상적이었다. "이 번에 적용을 해보고 나니까 테스트가 없었다면 이것을 어떻게 만들었을지 상상이 안된다. 이게 정말 좋은 것이구나~” 아마도 그런 경험이 몇번 쌓이면 자연스럽게 테스트부터 만들고 있는 스스로의 모습을 발견할 수 있게 되지 않을까 싶다.

물론 때로는 스스로 규율을 정해서 훈련할 필요도 있다. 나는 올해 초 목표에 "올해 만드는 모든 코드는 – 단지 HelloWorld라고 할지라도 TDD로 만든다"라는 것을 넣었다. 복잡한 시스템을 개발할 때는 나름 테스트를 열심히 만들어왔지만, 학습을 위해서 간단한 코드를 만들 때는 나도 모르게 코드부터 쓱쓱 만들고 대충 돌려보면서 안돌아가면 디버거나 코드와 씨름하고 있는 모습이 떠올라서, 이것을 습관화 하는 것이 중요하겠다는 생각을 했기 때문이다. 그럼 정말 100%를 그렇게 했을까? 물론 완벽하지는 못했다. 그래도 95%이상은 된 것 같다. 이전보다는 분명히 더 많이, 적어도 새로운 기술을 학습하거나 또는 자바 외의 다른 언어를 가지고 코드를 만들 때도 테스트를 항상 먼저 만드는 습관이 붙은 것은 사실이다. 그덕분에 그만큼 더 자주 그것이 좋다는 것을 느꼈고, 그래서 아마도 앞으로도 테스트를 먼전 만드는 것을 자연스럽게 선택할 것이라고 기대한다.

 

중얼중얼 오늘의 얘기는 여기서 대충 끝.

ROO RC1이 나왔다. RC1이라면 이름 그대로 출시후보(release candidate)가 아닌가. 별 문제가 없다면 그대로 정식 제품으로 출시해도 되는 수준이라는 것이다. 일부 버그픽스 정도만 남고 실제 구현할 기능은 완료했다는 뜻이기도 하다. A1이 나온게 얼마전 같은데 벌써 RC라니 놀랍기만 하다. 처음 ROO가 나왔을 때 한번 대충 분석해보고 한동안 손을 놓고 있다가 며칠전 RC1이 나왔다는 소식에 다시 ROO를 살펴보는 중이다. 그 사이에 제법 많이 기능도 추가되고 세련되진 듯 하다.

ROO에 대한 전반적인 생각에 대해서는 차차 얘기하기로 하고 오늘은 ROO가 가진 이슈 중의 하나인 Entity의 스태틱 메소드의 도입에 관해서 생각해보자.

 

스태틱 메소드는 스프링의 적이었다. 로드 존슨이 마르고 닳도록 스태틱 메소드는 사용하지 말자, 팩토리 메소드를 가진 싱글톤패턴은 나쁘다고 주장하고 다녔고, 그 대안으로 싱글톤 레지스트리/컨테이너가 관리하는 싱글톤 방식인 스프링을 들고 나왔다(스프링이 그것 때문에 나온 건 아니겠지만, 스프링의 기본 아이디어 중에서 이 싱글톤 레지스트리라는 것은 매우 중요하다).

스태틱 메소드는 테스트의 적이다. 스태틱 메소드는 상속도 되지 않고, 따라서 다형성도 적용되지 않는다. 인스턴스 레벨에 붙는 Generics도 못쓴다(generic method는 물론 가능하지만..). 글로벌하게 접근이 가능할 뿐더러, 사용하는 클라이언트가 스태틱 메소드를 mocking할 수 없기 때문에 테스트 작성의 적이 되고 만다.

그래서 스프링의 서비스 추상화 방식등에서 사용한 것처럼 테스트 하기 힘든 스태틱 메소드 위주의 API들은 일종의 아답터패턴을 적용해서 클라이언트가 새로운 인터페이스를 통해서 사용하도록 만들어야 한다. 방법은 뭐 여러가지가 있는데 기본적인 아이디어는 결국 인스턴스 메소드를 통해서 스태틱 메소드로 접근하도록 포장(wrap)하는 것이다.  그래서 인터페이스를 사용하든, 상속을 사용하든지 해서 어쨌든 스태틱 메소드에 대한 접근을 mock object로 바꾸도록 만들어야 한다.

이게 스프링이 열심히 퍼뜨리고, 많은 개발자들이 인정하고 있는 기본적인 아이디어이다.

 

그런데 ROO가 배신을 했다.

ROO는 소위 4세대 RAD 프레임워크인 RoR,Grails,Django 처럼 단순화된 레이어를 따른다. RoR말고는 안써봐서 잘 모르겠지만, 아무튼 Ben Alex가 직접 설명한 거니깐 그렀겠지. ROO의 자바코드 레이어는 Controller – Entity가 전부이다. DDD스타일의 도메인 레이어가 들어간 반면에 기존의 전형적인 구조에 등장하는 DAO, Service등이 없어졌다. RoR처럼 active record 패턴을 적용했기 때문에 Entity는 그 스스로 자신에 대한 save, get, update 등의 기능을 가지고 있다. 물론 ROO는 ITD(inter-type declaration, 또는 introduction, mixin) 기법을 써서 같은 Entity에 포함될 것이지만 active record의 주요 기능은 모두 별도로 분리된 파일에 두고, aspectj를 이용해서 다이나믹하게 병합되는 방식을 사용한다. 방법은 좀 다르지만 RoR의 ActiveRecord 못지 않은 메타프로그래밍 기법을 적용하고 있다.

문제는 하나의 엔티티 오브젝트 수준에서가 아닌 도메인의 콜렉션에 접근해야 하는 경우이다. DDD 스타일로 가자면 소위 리포지토리라고 부르는 패턴을 적용한다. 물론 ROO는 트랜스패런트 퍼시스턴스 방식의 JPA를 기본으로 하고 있기 때문에 오리지날 리포지토리 개념과 미묘하게 충돌하는 점이 있다. 개빈 킹은 DDD의 리포지토리 개념/차이점/필요성을 이해못하겠다고 투덜거리기도 했다. 아무튼 복잡한 얘기는 이터니티님의 http://aeternum.egloos.com/1160846 에 잘 설명되어있다(훌륭한 글이지만 읽고나면 더 헷갈리게 될 것을 보장한다. 쫌 어렵다)

ROO의 배경이 됐던 오리지날 ROO(사실 지금의 ROO는 오래전부터 소개됐던 ROO와 전혀 다른 것이다. 같은 건 이름 뿐인데 이름도 바뀔지 모른다)에는 리포지토리라는 레이어를 두고 그 안에 finder를 구현하는 구조로 만들어져있었다. 역시 하이버네이트와 같은 투명한 퍼시스턴스 기술을 사용하기 때문에 리포지토리의 많은 필요성은 도메인 오브젝트 그 자체의 지능적인 로딩기술에 녹아들어가 버렸고, 남은 것은 애플리케이션 레벨에서 바로 엔티티를 찾는 파인더 뿐이다.

그런데 최신 ROO는 이 리포지토리 레이어를 아예 없애고 엔티티에 통합해버렸다. 액티브레코드 패턴을 따라서 인스턴스 레벨에서 퍼시스턴스 처리를 하는 것들은 인스턴스 메소드로 만들어ITD로 낑겨넣도록 했는데, 문제는 파인더 류들이다. 이게 별도의 리포지토리가 분리되 있지 않으면 안된다. 엔티티의 인스턴스 메소드에 파인더가 들어가있는 것은 웃긴 꼴이될 것이다. 검색을 하기 위해 새로운 엔티티 오브젝트를 만드는 것은 말도 안되는 것이니깐. 결국 리포지토리는 독립적인 오브젝트로 존재할 필요가 있다.

하지만 ROO는 독립적인 리포지토리를 두는 것은 하나의 부가적인 레이어를 두는 꼴이라고 생각했다.(실체가 있어야 하는 엔티티 입장에서는 리포지토리는 인터페이스이고 도메인 레이어이다라고 하는 것은 별 의미도 가치도 없는 이야기라고 하이버네이트 개발자들은 주장한다. 모든 것이 다 엔티티로만 존재하는 이상적인 ORM세계에선 그렇게 보일 수도 있다) 아무튼, ROO는 이걸 RoR처럼 스태틱 메소드로 만들기로 했다. 그래서 각종 finder메소드 류는 모든 스태틱 메소드이다.

만들어 보면 대충 다음과 같이 생겼다.

privileged aspect Rsvp_Roo_Entity {

public static long Rsvp.countRsvps() {   
    return (Long) entityManager().createQuery("select count(o) from Rsvp o").getSingleResult();       
}   

public static java.util.List<com.toby.domain.Rsvp> Rsvp.findAllRsvps() {   
    return entityManager().createQuery("select o from Rsvp o").getResultList();       
}   

public static com.toby.domain.Rsvp Rsvp.findRsvp(java.lang.Long id) {   
    if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Rsvp");       
    return entityManager().find(Rsvp.class, id);       
}   

public static java.util.List<com.toby.domain.Rsvp> Rsvp.findRsvpEntries(int firstResult, int maxResults) {   
    return entityManager().createQuery("select o from Rsvp o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();       
}   

 

벤 알렉스의 블로그 글을 읽어보면 나름 고민해서 결정한 것이었다고 한다. 그도 원래 4개의 레이어를 두는 전통적인 DDD모델에 도메인 레이어를 벗어나면 immutable한 오브젝트로만 존재하도록 하는 까다로운 스타일을 고집했던 사람이다. 그럼에도 그런 이상적인 모델이 최근 몇년간 등장해서 인기를 끌고 있는 RoR류의 경량급 접근방법에 비해서 너무 무겁고 부담스럽다는 생각을 가진듯 하다. 그래서 과감히 RoR과 마찬가지로 엔티티(액티브레코드) + 스태틱 finder를 두는 스타일을 택했다.

이제 컨트롤러에서 다음과 같이 사용한다.

public String RsvpController.updateForm(@PathVariable("id") Long id, ModelMap modelMap) {   
        if (id == null) throw new IllegalArgumentException("An Identifier is required");       
        modelMap.addAttribute("rsvp", com.toby.domain.Rsvp.findRsvp(id));       
        return "rsvp/update";       
    }  

public java.lang.String RsvpController.create(@org.springframework.web.bind.annotation.ModelAttribute("rsvp") com.toby.domain.Rsvp rsvp, org.springframework.validation.BindingResult result) {    
  …

    rsvp.persist();       
    return "redirect:/rsvp/" + rsvp.getId();       
}

 

이걸 처음 본 순간 나는 상당한 충격을 받았다.

두가지 문제가 떠올랏다.

하나는 트랜잭션 경계가 어디냐는 것이다. 또 그에 따라 비즈니스 로직은 어디로 들어가는가 이다. RoR처럼 컨트롤러 안에 트랜잭션 디마케이션 템플릿을 두고 처리할 것인가? 물론 엔티티 레벨의 로직은 엔티티에 담으면 되지만, 특정한 비즈니스 로직의 facade가 존재할 곳이 없어지면 결국 퍼시스턴스 경계와 일부 로직은 컨트롤러로 들어올 것이다. 아니라면 비즈니스 facade를 역시 스태틱 메소드로 구현해야 할지도 모르겠다. 현재 트랜잭션 경계는 엔티티의 메소드로 지정되어있다. 그나마 JPA의 CRUD 메소드들이나 그렇고, finder들은 아예 트랜잭션 설정이 없다. 벤 알렉스의 글을 보면 이메일 발송은 컨트롤러의 몫이 되었다. 과연 그것이 컨트롤러가 담당해야 할 일일까. 어짜피 두 레이어 뿐인데 적당히 아무데나? 아예 Seam처럼 Action 클래스 하나로 다 들어가는 건 어떨까?

두번째 문제는 바로 스태틱 메소드 그 자체의 문제다. (이게 사실 하고 싶은 얘기였으니 지금까지는 서론..) 로드 존슨과 스프링 지지자들이 그토록 부정했던 스태틱 메소드를 과감하게 사용한 것은 과연 어떻게 합리화 할 수 있을까? 일단 기본적인 의문에 대해선 대세를 따라 간단하게 가는거다라는 주장을 받아들이기로 하고. 다음 문제는 테스트는 어쩔 것인가 이다.

스태틱 메소드를 사용하는 테스트는 힘들다고 하지 않았나. 만약 컨트롤러에서 사용하는 finder가 아주 많은 양의 데이터를 복잡한 쿼리로 가져와야 하는 것이어서 이를 사용하는 컨트롤러의 로직을 테스트 하기가 아주 힘들다면? 또는 엔티티가 그 fidner를 사용해야 하는 로직을 가지고 있는데, 역시 finder가 매번 실행되는 것이 부담스럽다면 어째야 할까? 당연히 mock을 사용하면 되는 거다. 스텁방식으로 finder메소드 호출의 기대하는 결과값을 주도록 만들고, 인터렉션은 목의 검증기능을 이용해서 처리하도록 하면 된다. 그러나 스태틱 메소드이니 mock을 적용하는 것이 아예 불가능하다는 것이 문제다.

이건 테스트에 대해서 그토록 강조하고 강조해온 스프링으로서는 사실 치명적이다. 테스트를 못하는 스프링 서브 프레임워크가 만든 코드라니!!

 

당연하게도 로드 존슨이 먼저 이슈를 제기했다. 스태틱 파인더, 메소드의 목은 어쩔거냐고. 그리고 스스로 대안을 제시했다. 스태틱 메소드의 목을 가능하게 하는 ROO 플러그인을 직접 개발해서 제공했다. 요즘엔 거의 코드에는 손을 안대는 CEO지만, 시드니 지사를 방문한 틈을 타서 ROO플러그인 코딩을 했다고 케빈 님이 ROO핵심 개발자를 통해서 들었다고 한다. 그의 트위터를 보는 사람들은 얼마전 그가 ROO플러그인을 만들고 있다고 하는 얘기를 기억할 것이다. 뭔가 했는데 바로 이거다.

아무튼 그가 내놓은 해결책은 이렇다. 정말 ROO의 아이디어를 따라 스태틱 메소드가 필요하다면, 엔티티의 스태틱 메소드도 목으로 만들게 하면된다는 것이다. 방법은 aspectj를 이용한 AOP를 사용하는 것이다. 안되는게 없는 초강력 AOP인 aspectj를 이용해서 스태틱 메소드의 호출을 가로채서 대신 목 기능이 동작하도록 만드는 것이다. 단 세계의 클래스(정확히는 하나의 애노테이션과 두 개의 aspects) 로 이 것을 가능하게 하고, 아예 mock테스트가 만들어지도록 코드 생성 플러그인까지 제공했다. 역시 하나의 애노테이션과 두 개의 aspect로 구현한 @Configurable과 맞먹는다.

그가 만든 스태틱 메소드에 대한 mock적용 기법의 핵심은 AbstractMethodMockingControl.aj와 JUnitStaticEntityMockingControl.aj이다. 앞의 것은 목의 구현이고, 뒤의 것은 JUnit의 @Test와 함께 스태틱 메소드의 목 적용을 가능케 하는 애스팩트이다. 다음의 두개의 포인트컷이 정의되어있다.

protected pointcut mockStaticsTestMethod() : execution(@Test public * (@MockStaticEntityMethods *).*(..));

protected pointcut methodToMock() : execution(public static * (@Entity *).*(..));

이를 이용하면 @MockStaticEntityMethod가 붙은 JUnit테스트에서는 @Entity가 붙은 엔티티의 스태틱 메소드를 호출하는 것이 mock으로 동작하게 된다. 따라서 다음과 같은 테스트코드가 가능하다.

@MockStaticEntityMethods
public class RsvpTest {

    @Test
    public void testMethod() {
        int expectedCount = 13;
        Rsvp.countRsvps();
        expectReturn(expectedCount);
        playback();
        junit.framework.Assert.assertEquals(expectedCount, Rsvp.countRsvps());
    }
}

record/playback 방식의 전형적인 EasyMock스타일의 목 구현이 가능해진다. 첫번째 countRsvp()호출은 레코딩, 두번째 호출은 검증용 실제 구현이다. 이 예제는 일종의 스텁구현을 보여준 것인데, 아무튼 로드 존슨이 애용하던 EasyMock 방식과 유사하다.

이래서 결국 AspectJ의 도움으로 스태틱 메소드의 mocking이 가능해졌다.

 

대충 방향은 이렇게 결정된 듯하다. 스프링이라도 대세는 어쩔 수 없는 건가. 아니면 라이트웨이트 버전과 풀 엔터프라이즈 버전을 동시에 공략하려는 건가 모르겠지만..

 

그러나 로드 존슨이 만든 목 구현은 아주 복잡한 목 기법등은 사용할 수 없는 초보적 수준이다. 이렇게 구현하면 될 것이라는 것을 보여준 정도인듯. ROO의 ITD 적용 이후 AspectJ의 위력을 한번 더 본 것 같아서 한편으로 대단한 아이디어다 싶으면서도 뭔가 찜찜하긴 하다. 사실 스태틱의 목 적용이라는게, 이렇게 테스트 클래스 레벨에 통채로 걸리는 것도 좀 부담스럽다.

 

그러던 중에 스태틱 메소드 테스트를 위한 솔루션이 뭐가 있을까 살펴보다 PowerMock이라는 것을 알게됐다. EasyMock의 확장버전으로 출발해서 클래스로딩시 바이트코드 조작기법을 통해서 EasyMock의 모든 기능을 스태틱 메소드 테스트시에도 적용가능하게 만든 것이다. 로드 존슨이 만든 것과는 비교가 안될만큼 완벽한 목 지원 기능을 제공한다.

게다가 요즘 목계를 평정하고 있는 Mocikto 스타일도 구현을 하고 있다. 아직은 완벽하지는 않다지만 예제를 보니 감동이다. 조만간 가져다 써도 될 것 같다.

http://code.google.com/p/powermock/wiki/MockitoUsage

AspectJ나 PowerMock이나 결국 바이트코드 조작을 이용하는 것은 마찬가지이고. 현재까지 구현된 것으로는 PowerMock의 압승이다. 로드존슨이 어렵게 AspectJ로 구현하지 말고 차라리 이걸 적용했으면 더 낫지 않았을까 싶다. PowerMock ROO플러그인으로 하나 만들어서 ROO프로젝트에 제출해봐도 좋겠다. 아마 조만간 누군가 하겠지. ROO 때문에 Mockito 못쓴다고 투덜대는 Mockito 팬이 벌써 등장했을 정도니 말이다.

PowerMock은 좀 써보고, 괜찮으면 레거시 코드의 테스트에 한번 적용해봐도 좋겠다. 잘 사용하면 유용할 듯 하긴 한데, 이 거 있다고 스태틱 메소드 마구 쓰는 건 안좋겠지? PowerMock은 좀 적용해보고 다음에 한번 자세히 살펴보자.

 

스태틱메소드의 목 적용은 사실 매우 불편하다. 간단한 예제만 보면 그럴싸해보이지만, 각각 다른 목을 만들어서 DI시켜서 사용하는 패턴에 비해서 글로벌하게 한번에 한 세트밖에 적용이 안되고, 테스트 오브젝트별로 DI도 불가능하니 사용 시나리오에 상당한 제약을 받을 지도 모르겠다.

 

아무튼 스프링 프로젝트가 스태틱 메소드를 적극 사용하고,  로드 존슨이 이를 용인하고 스스로 대안을 만들어 내기도 하는 걸 보니… 정말 세상과 기술이란 계속 변하는 것이긴 하나보다. 이게 발전인지 뭔지는 잘 모르겠지만.

나는 아닌데…

아니긴 뭐가 아닌가.

개발자라면 누구나 다 코드를 써내려가기 전 머리 속에서 간단한 테스트가 휘리릭 만들어진다. 이런 조건을 가진 경우 이렇게 액션이 일어나면 이런 결과가 나오겠구나. 그리고 코드를 몇줄 써내려 가고, 코드를 눈으로 따라 보면서 역시 머리 속에서 테스트가 돌아간다. OK. 이러면 잘 돌아가겠다. 생각이 들면 다음 기능으로. 아니면, 이거 좀 이상한데, 여기서 잘못된 값이 나오겠다라고 생각하고 수정으로 들어간다.

매우 짧고, 매우 불안정하며, 실수하기 쉽고, 용량이 감당이 안되서 결국 엉망으로 테스트가 돌아가게 되서 그렇지, 모든 코딩과정에는 머리 속에서 함께 테스트가 일어나기 마련이다.

사람의 두뇌라는게 매우 빠르게 복잡한 사고를 할 수 있기는 하지만, 양이 늘어나면 감당이 안되고 병렬로 처리도 잘 안되고 오류도 잘 나기 마련이다. 그래서 그 머리 속에서 일어나는 그런 코드를 보면서 하는 인간지능 TDD를, 밖으로 끄집어 내서 코드로 만들어버리면, 실수도 안하고 아무리 길고 복잡해도 불평한번 없이 알아서 수행해주는 컴퓨터가 그 귀찮은 일을 대신 해주는 것이다. 그런 사이 개발자는 맘편히 다른 문제에 더 집중할 수 있고.

어짜피 테스트코드를 사용하는 TDD를 못하는 사람이라면, 머리 속으로도 비슷한 작업이 그다지 잘 돌아갈 것이라고 생각되지 않는다. 그나마 두뇌의 스트레스를 줄여주는 쪽으로 하는게 결국 결과가 낫지 않을까?

코딩이란 걸 시작한 이후로 쭉 해온 습관이라 그럭저럭 돌아가는 인간지능 TDD를, 별로 안만들어봐서 어색한 코드로 표현하는 불편이 있긴 하지만 자꾸 노력해서 인간-컴퓨터 협력 TDD로 바꾸면 인생이 편해질 거다. 켄트 벡의 얘기대로 "맘편하게 잠자리에 들 수 있다". 맘편하게 데이트에 나갈 수 있고, 맘편히 휴가를, 맘편하게 가족과 시간을…

 

책에 들어갈 TDD 내용 좀 쉽게 설명하려고 생각해 본건데.. 좀 억지스러운가?

영회한테 배운 제목 낚시 연습으로는 뭐 괜찮은 듯.

© 2017 Toby's Epril Suffusion theme by Sayontan Sinha