위험 요소: 프로젝트 가시성의 부재
사람이 직접 의사소통 메커니즘을 수행할 때는, 프로젝트의 정보를 적절한 시기에 올바른 사람에게 전달하려면 조정을 많이 해야 합니다. 옆 자리에 앉은 개발자에게 다가가 최신 소스 코드를 공유 드라이브에 올려놨다고 말하면 좀더 효율적이긴 하겠지만, 그래도 여전히 그리 썩 좋지는 않습니다. 이 정보를 알아야 할 개발자가 더 있는데, 그 사람들이 휴식을 취하고 있거나 어딘가 가버린 상황이라면 어떨까요? 서버가 다운됐다면 그 사실을 어떻게 알리나요? 어떤 사람은 사람이 직접 이메일을 보내서 이러한 위험 요소를 경감시킬 수 있다고 생각합니다. 하지만 이런 방식으로는 정보가 올바른 사람에게 제때 전달되리라 믿기 힘듭니다. 이메일을 보내야 할 여러분이 이해당사자들에게 이메일을 보내는 걸 잊어먹을 수도 있고, 바로 그 시점에 이메일을 확인할 수 없는 상황에 처한 사람이 있을 수도 있습니다.
시나리오: “제가 남긴 메모 보셨나요?”
이 같은 위험 요소는 다양한 시나리오가 있습니다. 한 사례만 살펴보죠.
에블린(관리자): 노아, 무슨 일을 하고 있어요?
노아(테스터): 테스트를 하려는데 최신 빌드가 QA 팀으로 배포되길 기다리고 있습니다.
에블린: 최신 빌드가 이틀 전에 테스트 서버에 배포됐는데요. 못 들었어요?
노아: 네. 며칠 동안 회사에 없었거든요.
해결책
이런 위험 요소를 완화하기 위해 우리는 CruiseControl CI 서버를 설치하고 설정하여 빌드가 실패하면 관련자들에게 이메일을 보내는 자동화 메커니즘을 도입했습니다. 그와 더불어 SMS 통지 기능을 추가하여 이메일을 볼 수 없는 경우엔 휴대폰으로 문자 메시지를 받을 수 있게 했습니다. 서버의 가용 여부를 주기적으로 확인하는 자동화된 에이전트도 설치했습니다. 예제를 보고 싶거나 더 많은 정보를 얻고 싶다면 9장을 참고하세요.
시나리오: 소프트웨어를 시각화할 역량의 부재
새 기능을 만들고 기존 소프트웨어를 수정하는 프로젝트가 있었습니다. 하지만 우리에겐 큰 그림을 보여줄 역공학 도구가 없었습니다. 클래스들과 그 관계 모델을 볼 수가 없었죠. 만약 참조할 만한 최신 클래스 다이어그램이 있었더라면, 우리는 중복되는 행동이나 잘못된 구조를 더 쉽게 파악했을 테고, 그럼으로써 효과적이지 않은 결정을 덜 했을 것입니다.
마일리(개발자): 안녕하세요. 프로젝트에 참가하게 됐는데 설계를 검토해보고 싶습니다. 제가 볼 만한 UML 같은 다이어그램이 있을까요?
앨리(개발자): 으. 여기선 UML을 그리지 않아요. 마일리가 할 일은 코드를 읽는 것뿐이에요. 코드를 읽지 못하면 여기 있을 수 없을 거에요.
마일리: 알겠습니다. 그저 코드를 느릿느릿 헤집어보는 것보다 큰 그림을 보고 아키텍처 전체를 파악했으면 하고 바랐을 뿐입니다. 저는 그림을 더 좋아하거든요.
해결책
설계 결함이 발생하는 시점과 그것을 해결하는 시점 사이의 간격을 줄이려고 우리는 CI 시스템을 사용해 설계 다이어그램을 생성했습니다. Doxygen이라 하는 자동화된 코드 문서화 도구를 CI 시스템에서 돌렸습니다. Doxygen은 소스 코드를 문서화하고 소프트웨어를 모델링하는 UML 다이어그램을 만듭니다. Doxygen을 CI 시스템의 일부로써 돌리기 때문에, 버전 관리 저장소에 가장 근래에 체크인된 소프트웨어를 기반 삼아 항상 최신으로 유지됩니다.
CI 시스템에 이런 기능을 넣긴 했지만, 우리는 신참 개발자를 위해 핵심 컴포넌트와 인터페이스를 파악한 다음 한두 쪽짜리 간단한 문서를 만들어 소프트웨어 아키텍처를 설명하기로 했습니다.
위험 요소: 저품질의 소프트웨어
눈에 보이는 결함이 있는가 하면 잠재적인 결함도 있습니다. 소프트웨어를 잘 설계하지 못했거나 프로젝트 표준을 따르지 않았거나, 소프트웨어가 복잡해서 유지보수하기 힘들면 잠재적인 결함이 있는 겁니다. 이를 두고 코드 냄새 또는 설계 냄새라고 부르곤 합니다. 냄새란 ‘무언가 잘못됐다는 징후’를 뜻합니다.[^1] 저품질의 소프트웨어는 그저 지연된(소프트웨어 인도 후에) 프로젝트 비용일 뿐이라 생각하는 사람이 있습니다. 저품질의 소프트웨어를 지연된 프로젝트 비용으로 치부할 수는 있지만, 소프트웨어를 사용자에게 전달하기 전에 여러 가지 문제가 일어나게 됩니다. 지나치게 복잡한 코드, 아키텍처를 따르지 않는 코드, 그리고 중복 코드 모두 소프트웨어의 결함으로 이어집니다. 이런 코드 냄새와 설계 냄새가 결함이 되기 전에 찾아내면 엄청난 시간과 돈을 절약할 수 있고, 그에 따라 품질 좋은 소프트웨어가 만들어집니다. 이 절에서 이와 관련된 시나리오 몇 개를 검토해보겠습니다.
모든 소스 코드를 매일 손수 검토하는 방법 말고는 소프트웨어가 얼마나 유지보수하기 좋은지 알 방법이 없었던 프로젝트가 있었습니다. 개발 중인 소프트웨어의 품질 동향을 파악할 수 없었습니다. 프로젝트 구성원 다수가 소프트웨어의 내부 품질을 고칠 시간이 없다고 느꼈고 어디서부터 시작해야 할지 몰랐습니다. 별로 상의해본 적도 없고 따르지도 않는 코딩 표준 문서를 만들어놓은 프로젝트가 있습니다.
아예 표준이란 게 없는 프로젝트도 있죠. 몇몇 프로젝트에선 소프트웨어의 엔트로피가 명확합니다. 왜냐하면 소프트웨어를 깨먹을까 무서워 변경하질 못하기 때문입니다.
시나리오: 코딩 표준 준수
코딩 표준을 준수하는 것과 관련된 전형적인 대화를 보여드리겠습니다.
브라이언(개발자): 린지씨, 당신이 짠 코드는 읽기 어렵더라구요. 지난 주에 일을 시작할 때 30쪽짜리 코딩 표준 문서를 읽었나요?
린지(개발자): 지난 번 직장에서 했던 대로 하고 있습니다. 제가 작성한 코드는 약간 복잡해서 따라잡기 어려울지도 모르겠네요.
브라이언: 다른 사람이 건들지 못할 코드를 짠다고 똑똑해지는 건 아니잖아요. 자신을 덜 중요한 사람으로 만들 뿐이죠. 코드를 검토하고 업데이트하느라 시간을 더 잡아먹고 있어요. 빠른 시일 내에 코딩 표준 문서를 검토해주면 좋겠네요. 우선 지침에 따라 일전에 짜놓은 코드부터 다시 고치고 나서 새 코드를 작성해줬으면 합니다.
해결책
우리는 30쪽짜리 표준 문서를 작성하는 대신, 한쪽 짜리 어노테이션Annotation 달린 클래스를 만들어 코딩 표준을 모두 담게 했습니다.[^2] 우리는 CruiseControl이 빌드 스크립트를 돌릴 때 자동화된 검사 도구가 코딩 표준을 강요하도록 만들었습니다. 주로 자바 프로젝트를 다뤘기 때문에 Checkstyle[^3]과 PMD[^4]를 써서 정해놓은 표준에 부합하지 않는 코드가 하나라도 있으면 보고하게 해놓았습니다. Checkstyle과 PMD가 이런 정보를 HTML 보고서 형식으로 내보내게 하여, 이것을 다시 CruiseControl CI 서버와 통합시켰습니다. 이 이후의 프로젝트에선 코딩 표준을 조금이라도 위반하면 빌드를 통과하지 못하게 해놨습니다.
시나리오: 설계 지침 준수
의도한 설계를 따르지 않는 소스 코드는 유지 보수하기 더 어렵습니다. 프로젝트를 시작할 땐 아주 우아한 소프트웨어 아키텍처를 수립해놓았지만, 프로젝트가 끝날 무렵엔 ‘커다란 진흙덩이Big Ball of Mud’[^5]가 되어 버린 일이 없었습니까? 어쩌면 아키텍트가 전체 시스템을 UML 모델링 도구로 설계해놓고 “이 참조 아키텍처를 따르시오”라고 말했을지 모르죠. 극단적으로 말했을 수도 있지만, 언제나 그렇듯 양 극단의 중간쯤인 경우가 많습니다.
의도한 아키텍처와 실제 아키텍처 간의 불일치는 문제의 소지가 있습니다. 예를 들어 “데이터 계층은 절대로 비즈니스 계층과 ‘대화’를 나눠선 안 된다.”라는 설계 지침이 있다고 해보죠. 아마도 그 아키텍트는 UML 모델링 도구를 써서 이러한 아키텍처를 소스 코드로 변환시켰을 겁니다. 하지만 시간이 흐르자, 코드가 변했고 아키텍처는 의도했던 설계와는 어긋나게 됐습니다. 예를 들어, 신참 개발자가 프로젝트에 참가하게 되었고 비즈니스 계층에서 유용한 메소드들을 몇 개 찾아내서 데이터 계층에서 호출했다고 해보죠. 이는 프로젝트 아키텍처를 위반한 것입니다. 이런 일이 일어나지 않으리란 보장이 어디 있겠습니까?
진(아키텍트): 아키텍처를 따르고들 계신가요? 컨트롤러 중 하나에서 문제를 발견했는데, 여러분 중 한 사람이 데이터 계층에서 곧바로 컴포넌트를 호출하게 했더군요.
마크와 찰리(개발자): (당혹스런 표정)
진: 제가 그 모든 UML 다이어그램을 만든 이유는 모든 사람이 정해진 소프트웨어 아키텍처를 따르게 하기 위해서였습니다. 여러분은 몇 달 동안 잘 지켰던 정해진 규약을 따르지 않고 있어요.
찰리: 프로젝트 시작할 땐 UML 다이어그램을 살펴봤습니다. 하지만 그 이후로 아키텍처가 몇 차례 바뀌었고 따라가기 힘들더라구요.
해결책
자동화된 검사 도구를 넣어서 프로젝트 아키텍처 표준을 준수하는지 평가하세요. 이를테면 컨트롤러 클래스는 절대 데이터 접근 객체를 직접 호출해선 안 된다, 라는 규칙을 넣을 수 있습니다. JDepend[^6]나 NDepend 같은 의존성 분석 도구를 사용할 수도 있습니다. 통합 빌드를 할 때마다 이런 도구가 실행되게 할 수 있습니다.
시나리오: 중복 코드
중복 코드는 코드를 유지보수하기 더 어렵게 만들고 비용을 증가시킵니다. 복사해 붙여넣기Copy & Paste한 코드는 우리가 지켜본 사실상 모든 프로젝트에 위험이 되었습니다. 실제로 아주 유명한 소프트웨어 개발 키트와 도구 중에 25%가 넘는 코드가 중복되는 것이 많이 있습니다. 우리는 한 회사에서 소프트웨어 개발 프로젝트를 모두 분석했었는데, 평균적으로 중복 코드가 45%나 된다는 걸 발견했습니다. 유지 보수해야 할 비슷한 코드가 무더기로 있으면 문제가 될 수 있습니다. 예를 들어, 여러 하위시스템에 비슷한 코드가 5개나 있는 시스템이 있었습니다. 이제 현재 로그인한 사용자의 인증을 검사하는 코드가 있다고 해보겠습니다. 개발자가 하나의 메소드를 작성하지 않고 사용자를 인증할 때 필요한 코드를 사방에서 복사해 붙여넣기로 합니다. 개발자들이 공통 유틸리티를 쓰지 않고 자기만의 논리를 만들기로 할 때도 코드 중복의 또 다른 형태를 보게 됩니다. 문자 그대로 복사해 붙여넣는 것은 아니지만 코드 중복과 똑같은 효과를 만들어낸다는 점은 같습니다.
메리(개발자): User 객체 콜렉션을 어떻게 순회하면 되는지 아세요?
아담(개발자): 아, 제가 지난 주에 그런 코드를 짰어요. User 패키지에서 찾아보면 될 거예요.
메리: 정말요? 거기서 코드를 복사해 사용하면 되겠네요. 고마워요.
이런 식으로 코드 중복은 계속됩니다. 중복이 많아지고 있는지 줄어들고 있는지 그리고 어디서 중복이 발생하는지 알지 못하면, 여러분이 직면하게 될 문제가 무엇인지, 어디를 리팩토링해야 할지 파악하기 힘듭니다.
해결책
코드 중복을 해결하려면 먼저 문제부터 평가해야 합니다. PMD의 CPD[^7]나 Simian[^8]이란 정적 분석 도구와 같은 자동화된 검사 도구를 추가해서 중복된 소스 코드를 보고하게 할 수 있습니다. 우리는 이런 검사 도구를 빌드 프로세스에 포함시켰는데,그 덕분에 언제라도 검사를 돌릴 수 있었습니다. 이런 도구를 사용함으로써 대부분의 중복이 벌어진 코드 영역을 찾아냈고, 그런 코드를 컴포넌트로 만들어 일반화했습니다. 이런 접근 방법을 채택함으로써 코드 중복을 항시 감시하고 시스템 내의 중복 코드를 줄일 수 있었습니다.
전형적인 시나리오대로라면, 똑같거나 비슷한 코드를 가진 클래스를 여러 개 발견하게 됩니다. 중복 코드를 줄이려면 다음과 같은 절차를 따르세요.
- Simian이나 PMD의 CPD 같은 코드 중복 분석기로 코드를 분석하세요. 분석도구를 빌드 스크립트에 넣으세요.
- 코드를 리팩토링[^9]하여 하나의 메소드나 하나의 컴포넌트로 만들고, 그 코드가 있었던 클래스가 리팩토링한 코드를 호출하게끔 만들어 중복 코드를 줄이세요.
- 코드 중복 검사기를 CI 시스템에 집어넣어 코드 중복 검사를 지속적으로 돌리세요. 이렇게 하면 시간이 지나도 코드 중복을 감지해낼 역량이 생깁니다.
7장에서는 어떤 검사를 돌려야 하는지, 얼마나 자주 돌려야 하는지, 그리고 언제 적용해야 하는지에 대해 자세히 알아보겠습니다.
[^1]: http://en.wikipedia.org/wiki/Code_smell을 참고하세요.
[^2]: William C. Wake가 작성한 한쪽짜리 자바 코딩 규약(Java Coding Conventions on One)이 http://www.xp123.com/xplor/xp0002f/codingstd.gif에 있으니 살펴보세요.
[^3]: Checkstyle은 정적 분석 도구인데 소스 코드를 평가하고 정해놓은 코딩 표준에서 벗어나는 게 있으면 보고합니다. Checkstyle은 http://checkstyle.sourceforge.net/에 있습니다.
[^4]: PMD는 메트릭 도구인데 소스 코드에 사용하지 않는 변수, 사용하지 않는 import, 또는 지나치게 복잡한 코드와 같이 비정상적인 부분이 있으면 보고합니다. PMD는 http://pmd.sourceforge.net/에 있습니다.
[^5]: “진짜 아키텍처를 분간할 수 없는…… 시스템을 말한다.” 출처: http://en.wikipedia.org/wiki/Big_ball_of_mud
[^6]: JDepend는 소스 코드의 아키텍처와 설계를 확인하는 도구입니다. JDepend는 http://www.clarkware.com/software/JDepend.html에서 구할 수 있습니다.
[^7]: CPD는 PMD 메트릭 도구에 포함된 유틸리티인데 소스 코드를 복사해 붙여넣은 곳을 보고합니다. CPD는 http://pmd. sourceforge.net/에 있습니다.
[^8]: Simian(Similarity Analyser, 유사도 분석기)은 C#, 자바, 루비를 비롯해 다양한 언어를 지원합니다. Simaian은 www.redhillconsulting.com.au/products/simian/에서 다운로드 받을 수 있습니다.
[^9]: “리팩토링은 코드 내부를 바뀌어 내부 구조를 개선하는 것을 말한다.“ 출처는 Bill Venners가 쓴 “마틴 파울러와 리팩토링하기: 마틴 파울러와의 대화, 첫 번째”(Refactoring with Martin Fowler: A Conversation with Martin Fowler, Part I)이고 www.artima.com/intv/refactor.html에 있습니다.