Product Manager 관점에서 바라 본 TDD
이 세상에 변하지 않는 것은 없다.
변하지 않는 것이 있다면
“이 세상에 변하지 않는 것은 없다”라는 명제 뿐이다.(by 사회학자 다니엘 벨)
요즘 들어 개인적으로 가장 공감하는 말이다.
특히 소프트웨어 개발자이자 Product Manager로 IT업계에 종사하며 수행했던 여러 프로젝트 경험으로 인해 더더욱 위의 말에 공감하게 되는 것 같다.
대기업에 근무 중인 필자가 소속된 부서는 회사 전체의 Agile 개발문화 정착을 주도하고 있다. 이를 위해 2000년대 초반부터 Agile 관련 미국 회사들과의 협업으로 체득한 Agile 개발문화 기반 프로젝트 경험을 갖고 있는 직원들을 현 부서로 모아 개발문화 변화를 위한 기반을 마련하였다. 특히 3년 전 Agile 컨설팅으로 유명한 미국 P사와의 협업을 진행하며 Design Thinking과 Lean을 기존 경험들에 접목하였고, 이를 바탕으로 급변하는 시장 니즈에 맞는 제품을 빠르게 만들어 가는 방법들을 회사 상황에 맞게 커스터마이징하면서 확산하고 있다.
현재 필자는 Product Manager, 개발자로 활동하며 타 부서와의 협업을 통해 Product Manager, 개발자와 Pair로 업무를 수행하며 Agile 개발문화 전파를 진행하고 있다. 일부 프로젝트에서는 개발자로서 TDD를 경험하여 TDD가 개발자에게 어떻게 다가오는지에 대해 알 수 있었고, 또 다른 프로젝트들에서는 Product Manager로 제품 기획부터 런칭까지의 과정을 경험하며 TDD가 팀에 어떤 영향을 주는지에 대해 이해할 수 있었다. 이러한 경험을 바탕으로 TDD가 무엇인지, 그리고 Product Manager에게 있어 TDD는 어떤 의미를 갖는가에 대해 이야기 해 보고자 한다.
[TDD 정의]
현 소속 부서에서 가이드하고 있는 여러 Agile 개발 프랙티스 중 TDD라는 것이 있다.
TDD는 Test Driven Development의 약자로, 개발해야 할 기능에 대한 작은 스펙을 테스트 코드의 형태로 명세화하고 해당 명세를 충족시키기 위한 구현 코드를 개발해 나가는 개발 흐름을 의미한다.
즉, 개발 후 테스트하는 일반적인 흐름을 반대로 적용하여 개발하는 방식인 것이다.
[TDD 흐름]
Agile 방법론으로 진행되는 프로젝트는 일반적으로 제품의 특정 기능을 개발하기 위해 Product Manager가 User Story를 작성한다. User Story는 구현하고자 하는 기능이 무엇인지, 누구를 위한 것이고 왜 필요한지에 대한 내용이 담겨 있고 이와 함께 해당 기능으로 충족해야 할 스펙을 포함하고 있다. Acceptance Criteria라고 불리는 이 스펙들은 해당 사용자 스토리가 제대로 구현되었는가에 대한 기준점으로 활용된다.
개발자들이 특정 기능 개발에 착수할 때의 시작점이 바로 User Story이다. User Story에 적힌 내용으로 개발 내용에 대해 파악한 후, 어떤 식으로 개발할지에 대해 대략적인 밑그림을 머릿속으로 구상(설계)한다. 그리고 User Story에 적힌 첫 번째 스펙(Acceptance Criteria)을 충족하기 위한 테스트 코드를 작성한다. 구현 코드가 아닌 테스트 코드를 먼저 작성하여 문서로 작성된 스펙을 시스템화하는 것이다. 즉 구현될 내용에 대한 시스템화 된 검증체계를 기능 개발 전에 먼저 마련하는 것이다.
이렇게 테스트 코드만 작성된 시점에는 구현 코드가 없으므로 컴파일 오류가 발생한다. 테스트 코드 수행을 위해 컴파일 오류 해결을 위한 최소한의 구현 코드(클래스, 메소드 또는 멤버변수들의 껍데기)를 작성한다. 컴파일 오류가 사라지면 테스트 코드를 실행해본다. 빈 껍데기로 구성된 코드 이외에 로직으로 구현된 내용이 없으므로 테스트 코드는 실패(Fail)한다.
이제 테스트 코드 수행결과를 실패(Fail)에서 성공(Success)으로 바꿔가는 작업을 수행한다. 테스트 코드로 작성된 내용을 통과시키기 위한 구현 코드를 작성해간다. 테스트 코드 성공을 위한 최소한의 구현 코드를 작성하고 테스트 코드를 수행하여 성공메시지를 확인할 때까지 수행한다.
테스트 코드 수행으로 성공메시지를 확인하였다면 주어진 스펙에 대한 기능의 1차적 요건은 충족한 것이다. 하지만 여기서 멈추면 TDD를 수행한 것이라고 볼 수 없다.
왜냐하면 실패(Fail) — 성공(Success) — 리팩토링(Refactoring)의 흐름을 통해 “동작하는 클린 코드”를 얻는 것이 TDD의 궁극적인 목표이기 때문이다.
테스트 성공만을 위해 단순하게 작성했던 구현 코드를 리팩토링 하면서 클린 코드를 만들어간다. 상수로 표현된 요소들의 일반화, 중복 코드 정제 및 적절한 구조로 변경 등의 다양한 리팩토링을 통해 구조화되고 가독성 높은 소스 코드로 변화시킨다. 리팩토링을 진행하면서 코드상의 변화가 발생하게 되는데 이 과정에서 발생하는 개발자들의 심리적 부담감은 이미 확보된 테스트 코드가 해소해준다.
구현 코드의 리팩토링이 끝난 후 다음 TDD 사이클로 들어가기에 앞서 반드시 한 가지 더 진행해야 할 내용이 있다. 그것은 바로 테스트 코드의 리팩토링이다. 테스트 코드는 기능 동작에 직접적인 영향을 미치지 않지만 코드 형태로 작성되고 개발자에 의해 언제든 다시 읽혀지고 쓰여질 요소이다. 즉 테스트 코드 역시 구현 코드와 마찬가지로 리팩토링을 진행하여 클린 코드의 형태를 유지해 나가야 지속적으로 활용될 수 있다.
구현 코드와 테스트 코드에 대한 리팩토링이 끝나면 다음 구현 내용에 대한 테스트 코드 작성을 시작으로 다음 TDD 사이클로 진입한다.
[Product Manager와 TDD]
Product Manager에게 있어서 TDD는 어떤 의미를 갖을까?
개발자들에 의해 수행되는 TDD 흐름과 결과 코드를 놓고 본다면 다른 역할자들 입장에서는 TDD가 별다른 의미를 줄 수 없는 것처럼 보여질 수 있다. 오히려 테스트 코드 작성 및 TDD 흐름에 대한 러닝커브에만 집중하여 ‘불필요한 개발공수를 지속적으로 제품을 만드는데 투입해야 하는가’라는 이견을 제기하는 사람들도 있다. 하지만 필자의 경험을 비추어 볼 때 TDD가 ‘하면 좋지만 빠르게 개발하려면 굳이 안 해도 되는 것’으로 치부되기에는 너무 과소평가 받고 있다는 생각이 든다.
일단 TDD를 통해 얻게 되는 것을 다시 한 번 떠올려보자.
‘동작하는 클린 코드’ 그리고 ‘테스트 코드’
위와 같은 TDD의 결과물들은 개발자들에게 심리적 안정감을 준다. TDD로 개발된 코드는 작게 구조화되고 가독성 높게 구현되어 있어 언제든 쉽게 내용을 파악할 수 있다. 또한 테스트 코드가 마련되어 있어 기능이 어떻게 동작해야 하는가에 대한 스펙을 테스트 코드로 이해할 수 있고 실제 구동을 통해 수시로 검증해 볼 수 있다. 특정 기능을 변경하는 상황을 상상해 본다면 클린 코드와 테스트 코드가 어떤 역할을 하게 될 지 감을 잡을 수 있을 것이다. 이미 구현되어 있는 기능이라도 클린 코드를 기반으로 쉽게 파악하고 테스트 코드를 기반으로 주저없이 변경을 시도할 수 있다. 즉, 변경에 유연하게 대응할 수 있는 체계가 마련되는 것이다. 개발자의 입장에서 심리적 안전장치가 마련되어 있어 변경 요건 발생에 덜 민감해진다.
현실로 돌아와보자.
하루가 멀다하고 발생하는 변경요건들.
언제든 변경을 가할 수 있다는 것은 소프트웨어의 독특한 특성이자 매력이지만, 이러한 특성이 현실에선 그 무엇보다 큰 불안감으로 다가온다. 코드 변경으로 인해 발생할지 모르는 잠재 결함들을 떠 안은 채 오늘도 개발팀은 살얼음판 위를 걷는다. 신규로 만들어가는 제품들도, 유지보수 단계에 있는 제품들도 사용자들의 니즈 반영을 위해 쉬지 않고 변화해가려 하지만 현실은 발맞추어가지 못한다. 제품의 성공을 위한다면 제품을 만들어가는 개발팀 역시 이러한 변화에 발 맞추어 나갈 수 있는 환경적 뒷받침이 이뤄져야 한다.
“우리 팀이 만들어 가는 제품은 언제나 높은 품질을 유지하고, 필요할 때 언제든 부담없이 변경을 가할 수 있다!”
얼마나 행복하고 든든한 일인가?
급변하는 시장 상황에서 제품 개발의 전면에 서 있는 Product Manager에게 제품 기능을 빠르게 바꾸어 나갈 수 있는 환경적 뒷받침이 있다는 것만큼 믿음직스러운 환경은 없다.
개발자들로 부터 시작된 ‘동작하는 클린 코드’와 ‘테스트 코드’를 바탕으로 만들어진 ‘열려있는 변경 수용 분위기’는 고스란히 팀 구성원들에게 전해진다. ‘열려있는 변경 수용 분위기’는 디자이너에 의한 사용자 검증으로 기능 개선 사항을 찾아내고, Product Manager와 디자이너에 의해 구체화된 개선 내용을 개발자에 의해 구현되어 다시 사용자 검증을 받는 Lean 사이클의 기반이 된다.
곧 TDD가 주는 안정감을 기반으로 Product Manager는 시장 니즈에 맞는 제품의 점진적 발전을 이끌어 갈 수 있는 것이다. 이런 과정에서 제품이 개선되는 모습을 보면서, 그리고 사용자에 의한 긍정적인 피드백이 쌓여가면서 제품에 대한 팀원들의 Ownership 역시 높아져가는 모습을 목격하는 이점도 누리게 된다.
필자 역시 개발자들의 전유물로만 여겨졌던 TDD가 Product Manager에게 어떤 의미로 다가올지 직접 경험하기 전에는 미처 깨닫지 못했다. TDD는 개발 내용에 대해 품질을 높이는 일종의 수단일 뿐, 작업량만 늘어나고 효과는 적은 비효율적인 것으로 이야기 하는 사람들의 의견에 일부분 동의하기도 했었다. 하지만 TDD로 기능을 만들어가는 개발자들과 함께 일하며 변경에 열려있는 환경이 팀 전체에 어떤 변화를 가져오는지 경험하면서 지난 날 갖고 있던 TDD에 대한 생각을 되돌아 보게 되었다.
“세상은 계속 변한다. 점점 빠르게…”
급변하는 세상을 살아가며 제품을 만들어가는 입장에서 빠른 개발에만 집중하여 일단 만들고 다시 들여다 보기 두려운 제품을 만들어 하루하루 살얼음판을 걸을지, 아니면 초반 스피드는 다소 늦더라도 빠르게 변화에 대응해가며 안정적인 제품을 만들어 갈 것인지.
선택은 자유다.