1. 동작하는 소프트웨어만으로는 부족하다
애자일 매니페스토에서는 광범위한 문서보다 동작하는 소프트웨어를 강조한다. 동작하는 소프트웨어에 대해서 두 가지를 언급하고 있다.
(3) ‘동작하는 소프트웨어’를 자주, 몇 주나 2개월 단위로, 가능하면 짧은 주기로 전달한다.
(7) ‘동작하는 소프트웨어’는 진척도를 가늠하는 주된 기준이다.
이것은 훌륭한 원칙들이고 우리 모두 그렇게 해야 한다는 것에 백퍼센트 동의한다. 문제는 시간이 흐르면서 동작하는 소프트웨어에 대한 개념이 ‘고품질의 동작하는 소프트웨어’로 옮겨가고 있다는 것이다. 그럼에도 불구하고 애자일 프로젝트들이 수준 이하의 코드들이 많아지고 있다. 매일같이 부딪히는 엉망진창인 레거시 코드들도 분명 동작하는 소프트웨어의 범주에는 포함된다. 레거시 애플리케이션에 새로운 기능을 추가할 때마다 시간이 아주 오래 걸린다고 상상해보자. 손을 대는 것조차 무서운 코드도 상상해보자. 코드가 너무 민감하고 여기저기 얽혀 있어서 작은 수정을 하나 할 때마다 많은 테스트를 해야 한다. 그마저도 자동화가 되어 있지 않아 모든 것을 직접 손으로 하나하나 테스트해야 한다. 고객의 상용 시스템에 설치하고 인수 시험을 받아야 한다면 어떻게 될까? 고객에게 양해를 구하고 개발자가 직접 가서 상용 시스템을 상대로 손으로 테스트를 해볼 것인가? 이러한 소프트웨어도 동작하는 소프트웨어이기는 하다.
그러면 ‘동작하는 소프트웨어’의 의미는 무엇일까? 위에서 이야기한 소프트웨어도 동작하는 소프트웨어일까? 동작하는 소프트웨어로서 충분한 조건을 갖춘 것일까? 뭔가 하나를 수정하면 오랜 기간 빌드와 수동 테스트, 버그 수정을 거쳐야 한다는 것을 용납할 수 있나? 새로운 기능마다 그러한 일을 계속해서 반복해야 한다면? 이런 상황들은 품질에 대한 개념을 완전히 잃어 버렸거나 그냥 주어진 상황을 체념하고 받아들이는 것과 같다.
2. 정원 돌보기
코드는 기계장치라기보다는 유기물이다. 코드는 정원처럼 지속적인 유지보수가 필요하다. 1년 내내 정원이 아름다우려면 지속적인 돌봄이 필요하다. 토양을 손보고, 잡초를 뽑고, 정기적으로 물을 주고, 죽은 화초를 없애고, 새로운 화초를 심고, 화초들이 건강하게 잘 자라고 보기에 좋도록 가지치기를 해야 한다. 기본적이고 정기적인 유지보수만으로도 정원을 훌륭하게 가꿀 수 있다. 짧은 기간이라도 돌보기를 게을리하면 다시 아름답게 가꾸는 데 훨씬 더 많은 노력을 해야 한다. 오래 방치할수록 다시 보고 즐길 수 있는 상태로 되돌리는 데 더 많은 수고가 필요하다. 코드도 마찬가지다. 정기적으로 살피지 않으면 변화가 있을 때마다, 새 기능을 추가할 때마다 상태가 나빠진다. 잘못된 설계, 테스트 부족, 프로그래밍 언어나 도구의 미숙한 활용도 코드를 더 빨리 썩게 만든다. 점점 다른파트의 코드들도 오염되고 결국 유지보수에 드는 비용과 노력이 감당할 수 없을 만큼 커져 버린다.
3. 우리는 올바른 것을 하길 원한다
개발자들이 의도적으로 나쁜 코드를 작성하지 않는다. 다만 항상 왜 그렇게 될 수밖에 없었는지 핑곗거리를 찾는다. 오랫동안 소프트웨어 개발을 해오면서 개발자들이 시간에 대해 잘못된 개념을 가진 경우가 많다는 것을 깨달았다. 우리는 항상 업무와 일정의 압박 속에 있다는 생각을 가지고 있다. 언제나 급하게 일해야 한다고 느낀다. 비즈니스 팀이 일정에 관해 압박할 때도 있지만 스스로 쫓기는 경우가 대부분이다. 합리적인 사람들과 애자일 스타일로 일하고 있다면 진행 상황을 투명하게 공유하기 때문에 비즈니스 담당자들이 거꾸로 우리의 계획과 예측에 의존하게 된다. 어떤 일을 하는데 대략적으로 어느 정도의 시간이 필요하다고 이야기하면 비즈니스 담당자들이 있는 그대로 수용하는 것이다. 그런 상황에서조차도 우리는 일을 빨리 해야만 한다는 생각에 휩싸여 모든 일을 서두르기만 한다. 그러고는 일을 제대로 할 수 있는 시간이 없다고 이야기한다.
소프트웨어 개발자의 삶에 있어 압박은 피할 수 없다. 우리는 압박을 받는다고 느낄 때 중심을 잃고 고만고만해진다. 게으른 탓이 아니다. 더 빨리해야 한다고 느끼기 때문에 그렇게 한다. 비즈니스에서 필요로 하는 기능을 최대한 빨리 끝내는 것이 개발자로서 미덕이라고 느끼고 있다. 상황을 솔직하고 투명하게 밝히고 며칠 더 늦게 안정적인 솔루션을 전달하기보다 버그가 좀 있더라도 일정 안에 전달하는 편이 더 낫다고 느낀다. 빨리 하는 것과 허술한 것은 다르다. 우리의 결정이 어떤 의미이고 어떤 결과를 가져오는지 우리는 잘 이해하지 못할 때가 많다.
4. 단위 테스트 작성은 별개의 업무인가
개발 업무를 작은 단위의 업무들로 나눌 때 ‘단위 테스트 구현’을 별도의 작업 항목으로 정의하는 개발자들이 많다. 단위 테스트 구현에 정규적인 업무 시간을 따로 할당하려는 의도이다. 절대 그래서는 안 된다.
첫 번째로, 단위 테스트는 우리가 코드를 작성하는 방식에 이미 녹아있는 것이지 별도의 작업이 아니다. 테스트하지 않았다면 코드 작성을 완료했다고 할 수 없다. 단위 테스트는 코드가 제대로 구현되었는지 확인하는 가장 좋은 방법이다. 테스트 주도 개발을 접해보지 못한 보통의 개발자들은 주어진 요구사항에 맞춰 동작할 거라고 ‘기대만 하는’ 상태로 코드를 작성하고는 바로 다음 요구사항의 구현에 들어간다. 즉 제대로 된 테스트 없이 코딩을 마무리한다. 기능 구현이 완료되었다고 할 수 있으려면 반드시 테스트까지 되어야 한다. 단위 테스트를 작성하도록 팀 단위에서의 합의가 있었다면, 기능 구현 완료에는 단위 테스트의 구현 및 테스트 완료까지 포함되어야 한다.
두 번째로, 우리가 공식적인 작업 일정표에 무언가를 올려 놓는다는 것은 제품 오너가 그중 중요하지 않다고 생각하는 것을 삭제할 수 있는 권리를 준다는 것과 같다. 단위 테스트 구현을 별개의 작업으로서 일정표에 올려놓게 되면 거의 대부분 기능 구현 자체와 맞먹는 규모로 시간표를 차지하게 된다. 경험이 부족해서 단위 테스트의 가치를 이해하지 못하는 제품 오너에게는 그 시간이 낭비로 비춰질 수도 있다. 제품 오너 나름의 역할에 충실히 하려는 차원에서, 더 가치 있는 다른 작업을 하고 싶은 욕심이 생길 수도 있다. 자신의 역할에 최선을 다하려는 선한 의도라도 결정의 파급 효과를 제대로 이해하지 못한 채 단위 테스트 구현 작업을 없애버릴 가능성이 높다. 이러한 일이 일어나지 않도록 소프트웨어 품질에 책임을 지는 것은 우리 개발자들의 몫이다. 종국적으로 제품 오너가 원하는 것은 아무런 문제없이 의도대로 동작하는 시스템이고 그에 대한 책임은 우리에게 있다. 책임을 다하려면 단위 테스트뿐만 아니라 코드의 동작을 보증하기 위한 다른 복합적인 테스트들도 필요하다면 만들어야 한다. 제품 오너의 입장에서는 소프트웨어가 정상적으로 동작하는 한 개발자들이 세부적으로 어떤 일을 하든지 별 상관이 없다.
시간이 있어 개발자 스스로 자동화 테스트를 구현하지 않으려는 경우도 있다. 이러한 개발자는 테스트하지 않아서 발생할 수 있는 파급 효과를 무시한 채 스스로 “나는 테스트 코드를 작성할 시간이 없다”라고 단정한다. 자신의 작업 시간만 생각하고 전체 프로젝트에 관계된 다른 사람들이 시스템을 테스트하고 디버깅하느라 얼마나 많은 시간을 소모해야 하는지는 생각하지 않는 사람이다. 항상 프로젝트에 다른 사람들도 있다는 사실을 인식하고 전체 프로젝트에 미치는 영향을 감안하여 책임있게 행동해야 한다. 자신이 짠 코드는 어떻게 동작하는지 잘 알고 있고 문제가 없을 터이니 테스트 코드를 따로 안 만들어도 된다고 주장하는 개발자는 대단히 자기 중심적이고 이기적인 사람이다. 소프트웨어 프로젝트는 팀워크다. 특정 개발자를 한 사람을 위한 것이 아니다. 특정 개발자에게 쉽고 분명한 것이 팀내 다른 개발자에게는 난해하고 불분명할 수 있다. 시스템이 커짐에 따라 프로젝트에 관계된 모든 사람들이 개인의 작은 이기적 행동들 때문에 피해를 입게 된다.
5. 요약
몇 주나 몇 개월 이상 유지보수를 해야 하는 소프트웨어라면, 품질을 희생해서라도 빨리 끝낼 수 있다는 것은 어쩌면 환상이라고 생각한다. 많은 기업들이 자신의 소프트웨어에 인질로 잡혀 있다. 소프트웨어가 얼마나 빨리 변경 또는 개선될 수 있느냐에 따라 비즈니스의 민첩성이 드러난다. 소프트웨어의 품질이 좋지 않을수록 변경하기가 더 어려워진다. 기업이 사용하는 소프트웨어의 개선이나 변경이 느릴수록 시장 환경의 변화에 기업이 대응하는 속도도 떨어진다.
회사와 개발자들은 정기적으로 도끼날을 가는 시간이 낭비가 아니라는 사실을 이해해야 한다. 바로 그것이 시간을 절약하고 끊임없이 빨리 움직일 수 있는 최선의 방법이다.
6. 정리
그동안 개발을 하면서 테스트 코드에 대한 중요성을 잊고 개발을 한 적이 많았다. 글을 읽고 난 이후 나는 지난 날을 되새겨보며 개발에 대한 업무 흐름을 다시 한 번 곱씹어봤다. 정원을 가꾸는 것처럼 코드는 꾸준히 관리하는 게 맞다고 생각한다. 이 코드는 동작에 문제가 없으니까 나중에도 이 코드를 사용하면 되겠네 하는 생각으로 개발을 해서는 안 된다. 이러한 문제를 인식하려면 테스트 코드를 작성하는 습관을 평소에도 들여놓는 것이 중요하다. 그럼에도 테스트 코드를 작성하는 것이 회사 문화 전반에 깔려 있지 않거나, 테스트 코드 작성이 시간 낭비라고 생각하여 어떻게든 기능을 개발하는 것에만 집중하며 프로젝트를 진행하는 경우가 존재한다고 하니 이는 개발에 대한 비용 부담이 더 늘어나는 결과로 이어질 수밖에 없다고 생각한다.
항상 좋은 코드를 작성하기 위해 고민하는 것이 개발자의 숙명이 아닐까 싶다. 흥미를 가지고 프로젝트를 진행하는 것도 중요하지만 자신이 작성한 코드가 효율적인 코드인지, 다른 개발자들이 이해할 수 있는 코드인지를 파악하는 것도 매우 중요한 작업이다. 이슈 발생에 대한 가능성을 미연에 방지하려면 단위 테스트, TDD를 도입하며 코드를 작성하는 것이 훨씬 더 효율적으로 작업하는 것이 맞다고 본다.