2013년 10월 19일 토요일

기술적 부채에 대처하는 자세 Ver2.0

 기술적 부채Technical Debt라는 말을 들어 본 적이 있는가? 1992년 Ward Cunningham이 비 기술자들에게 문제를 전달하기 위해 사용하기 시작한 단어로,  간단히 말해 꼭 해 두지 않아도 또는 프로젝트가 끝날 때 까지(심지어는 끝나고 나서도) 티가 잘 나지 않는 작업들을 지칭한다.

 일반적으로 잘 알려진 기술적 부채로는 악취 나는 코드, 테스트 커버리지, 적절하지 못한 객체 모델링과 같은 작업들이 있다.

기술적 부채를 둘러싼 순환구조

 Ward Cunningham이 부채라는 표현을 쓴 이유는 복리이자가 발생하기 때문으로 이 문제를 제대로 다루기 위해서는 문제를 순환구조로서 파악하지 않으면 안된다.

기술적 부채의 악순환

기술적 자산의 선순환


 기술적 부채가 지닌 대표적인 특징은 빌린 사람과 갚는 사람이 일치 하지 않는다는 점인데, 빌린 사람은 최초 개발자에 해당하고 갚아야 하는 사람은 표면적으로는 유지 보수 개발자이고 본질적으로는 시스템 소유자(프로젝트 오너)라 볼 수 있다. 기술 부채는 소프트웨어를 사용하는 앤드유저에게는 직접적인 가치를 제공하지 않기때문에 관리업무에서 흔히 소외되는 요소중 하나로, 좀 더 직설적으로 이야기 하자면 코드 가독성을 높이기 위해 고객에게 릴리즈 일정을 조정해 달라고 할 수 없다는 뜻이다.

 금융 부채와 마찬가지로 적절하게 컨트롤 되기만 한다면 기술적 부채가 꼭 나쁘기만 한 것은 아니다. 적절한 기술적 부채의  운용은 프로젝트 진행에 상당한 융통성을 가져다 주기 때문이다. 채무를 예로 들자면 단기 상환채무를 장기 상환채무로 옮긴다던가 보다 많은 이자가 발생하는 부채를 적은 이자가 발생하는 부채로 옮기는 것과 같은것이다.

 하지만 이자는 어딘가에 몰아넣고 잊어버릴 수 있는것이 아니다. 시간과 함께 착실히 증가하게 되며 이를 제대로 인지하고 관리해 두지 않는 다면 프로젝트나 비지니스를 망치는 심각한 문제로 커 질 수도 있다. 이 점 때문에 기술적 부채는 이상과 현실 사이에서 영원히 고통 받는 프로젝트 매니저들에게 중요한 숙제거리이다.

누락된 자동화 테스트 

 제때에 작성해 두지 않은, 또는 부실하게 작성되어 실행 패턴에 대한 커버리지가 부족한 자동화 테스트는 대표적인 기술 부채이다. 멀쩡하게 동작 하는 것 처럼 보였던 코드들은 지름신 에게 휘둘린 후 애써 모른 척한 신용카드 청구서처럼 때가 되면 어김 없이 당신을 찾아와 비용 지불을 요구할 것이다.  버그의 처리 비용은 생성 후에 얼마나 빠른 시간 내에 처리 되느냐에 따라 달려 있다는 것은 이미 여러 연구에 의해 밝혀진 사실이다.

 이에 반해 테스트 케이스를 작성하는 과정 자체는 테스트 대상이 되는 실행 코드에 대한 통찰력을 늘리는 데에도 많은 도움을 준다. 이것은 채무의 반대되는 의미로 기술 자산이라 불러도 좋을듯 하다. 

 자동화 테스트는 젠킨스와 같은 CI툴과 만나 더욱더 놀라운 시너지 효과를 낸다. 프로젝트의 누군가가 새로운 소스를 커밋 한다면 CI서버는 이를 감지하여 자동화 테스트를 실행하고 그 결과 최단 시간에 새로운 코드가 발생 시킬 수 있는 문제점들을 알려준다.

 자동화된 테스트 코드의 가장 큰 장점은 코드가 사양 변경에 매우 견고해 진다는 점 이다. 제대로 작성된 테스트 코드를 가지고 있다면 추가되는 사양 변경에 대해 두려움 없이 작업을 할 수 있을것이다. 테스트 결과는 수정한 내용이 다른 코드들에 부작용 없이 잘 움직인다는 것을 보증해 줄 것이며 만약 예상치 못한 문제가 생기더라도 즉각 CI를 통해 이를 인지 하여 대처 할 수 있을 것이다.

 성실하게 작성된 테스트 코드들은 부채가 아닌 착실하게 신뢰성이라는 이자를 불려가며 당신의 코드를 더욱더 가치있게 만들어 줄 것이다.
만약 프로젝트 일정중에 잠시잠시 여유시간이 생긴다면 언제나 자동화 테스트를 추가하고 또 추가하라. 언제나 녹색을 유지하는 테스트 결과 그래프는 당신의 작업을 더욱 즐겁게 만들어 줄 것이다.

리팩토링

 리펙토링은 특히 자동화 테스트와도 밀접한 관계를 지닌다. 요즘같이 좋은 툴이 리펙토링을 지원하는 시대에도 어쨌든 소스코드가 변경된다는것은 테스트가 필요함을 의미하기 때문이다.

리팩터링에 대해서는 아래의 글을 참고하길 바란다.



 여기서 한가지 짚고 넘어가고 싶은 것은 많은 사람들이 리팩토링을 단순히 소스코드를 보기 좋게 하여 가독성을 높이는 작업 쯤으로 인식하고 있는데 객체 지향 프로그래밍에서 리팩토링은 보다 심오한 의미를 지닌다.

 자바와 C#을 비롯한 많은 언어들을 객체 지향 프로그래밍이 대세가 되었다는 지금에도 실상 동작하는 코드의 내부를 들여다보면 트랜잭션 스크립트 패턴을 이용하는 경우가 거의 대부분이다. 하지만 진정한 객체 지향 프로그래밍을 위해서는 도메인 모델링 패턴이 반드시 필요 하며 이를 위해서는 반복 적인 객체 모델링 작업이 필수적이다.

 다만 도메인 모델 패턴은 플라톤의 이데아론에 비견될 정도로 한번에 완성된 모델을 제시하는 것이 쉽지 않기 때문에 모델 변경과 구현의 사이클을 지속적으로 행하는 반복적 정제가 거의 필수이자 최선의 개발방법으로 여겨진다.


도메인 모델 패턴에 대해서는 최범균님의 블로그에 상세히 소개되어 있다.


 리팩토링 작업은 기능 추가 및 개선 작업 과는 별도로 진행되는 특성이 있으므로 프로젝트를 원활히 돌리기 위해서는 고수준의 형상관리 능력을 요구 받는다. 즉, 메인 스트림의 개발을 멈추지 않으면서 브런치로 리팩토링을 진행하고 다시 이를 머지 하는 과정이 필수적이라고 할 수 있다.

결론

 프로젝트 내부에서 기술 채무는 빨리 제거 하는 것 만이 능사는 아니다. 서론에서 기술한 바와 같이 기술적 채무는 개발자가 게을러서 발생하는 것이 아니며, 스케줄 진행상 거의 필수 불가결하게 발생하게 되므로 적절하게 관리만 된다면 프로젝트 진행에 상당한 융통성을 가져다 줄 수 있다.  물론 처음부터 기술 부채가 발생하지 않도록 노력 하는 것은 중요하지만 사안에 따라서는 프로젝트 이해 관계자들의 승인 하에 과감한 이월(유지 보수 관리자에게 떠 넘기기)을 선택 하거나 아예 디폴트를 선언하는것도 한가지 방법이 될 것이다.  디폴트 선언(냄새나는 코드 무시하기)에 대해서는 Eric Evans가 제안한 전략적 설계가 좋은 지침이 될 것이다. 

 기술 부채는 금융 부채와 마찬가지로 한꺼번에 상환 하기 어려운 경우가 대부분이기 때문에 프로젝트 매니저는 스케줄 관리에 기술 부채 상환에 대한 부분을 반영하고 전략적으로 유지 되도록 관심을 기울여야 할 것이다. 작업 관리에 Trac이나 Redmine과 같은 이슈 트랙커를 사용하고 있다면 이러한 기술 부채를 다루기 위한 별도 카테고리를 만들어 관리하는 것도 좋은 방법이다.

 기술적 부채의 관리에 관한 보다 심도있는 논의는 InfoQ에 Sven Johann과 Eberhard Wolff가 개제한 Managing Technical Debt를 읽어볼 것을 추천한다.