본문 바로가기
이전글/2006

리팩토링 기술 업그레이드하기

by 물개선생 2006. 12. 6.

필자의 프로젝트 팀내 감금 사태로 인해 12월호 특집 기사에 2페이지가 부족하니 채워달라는 긴급 SOS 연락을 받고 급하게 작성해서 보낸 기사입니다. 옛날에 있던 회사 동료 분이랑 오랜만에 넷미팅과 구글토크를 이용해서 TDD 수련을 위한 짝프로그래밍 놀이를 했더니 이 글이 생각나서 올려봅니다.

테스트와 리팩토링
"리팩토링을 하고자 할때 견고한 테스트는 없어서는 안 될 필수조건이다.“

마틴 파울러는 리팩토링을 할 때 반드시 기억해야 할 기본 명제로 아래의 2가지 항목을 말했다.

(1) 리팩토링은 소프트웨어의 기능을 변경하지 않는다.
(2) 제대로 동작하지 않는 코드는 리팩토링하지 않는다.

이를 통해 기능을 추가하는 작업과 기능의 추가 없이 내부 구조를 개선하는 작업을 나누어 진행해야 함을 알 수 있다. 여기서 중요한 것은 이러한 기본 명제에 의해 파생되는 2가지 요구사항이다.

(1) 내가 추가한 기능이 제대로 동작한다는 것을 확인한 다음에야 리팩토링을 수행할 것인지에 대한 여부를 결정할 수 있다.
(2) 리팩토링을 한 이후에 소프트웨어는 리팩토링을 하기 전과 비교해서 기능 변경이 없어야 한다.

어떻게 추가한 기능이 개발자의 의도대로 바르게 동작함을 확인할 수 있을까? 어떻게 리팩토링 과정에서 기존에 잘 동작하던 기능들이 훼손되지 않았음을 보장할 수 있을까? 이 질문에 대한 답은 바로 테스트이다. 테스트는 리팩토링과 따로 떼어 생각할 수 없는 필수적인 행위인 것이다.


그럼에도 불구하고 리팩토링을 실천하고 있다고 주장하는 많은 개발자들 중에 테스트의 가치를 진심으로 인정하는 사람을 만나기는 쉽지 않다. 리팩토링 카탈로그에 소개된 리팩토링 기법들을 실천함으로써 “훌륭한 개발자는 사람이 이해할 수 있는 코드를 짠다”는 가치를 추구하고 있는 개발자라면, 일정 부족이나 기능추가 외에는 가치를 이해하지 못하는 관리자를 핑계로 테스트 개발을 소홀히 해서는 안된다. 테스트가 없는 리팩토링은 최소한의 전제 조건도 만족시키지 못하는 반쪽짜리에 불과하기 때문이다.

하지만 이미 구현을 끝내고 직접 실행시켜보는 방법으로 동작을 확인한 코드에 대해 테스트를 작성하다 보면 내가 왜 이 짓을 하고 있을까 하는 의구심이 들기 마련이다. 그래서 테스트를 개발한다 하더라도 형식적인 테스트에서 그치고 만다. 이러한 상황에서 벗어나기 위한 최선의 방법은 구현에 앞서 테스트를 먼저 개발하는 테스트 주도 개발(Test-Driven Development)을 도입하는 것이다. 테스트 주도 개발을 가끔 테스트 주도 리팩토링(Test-Driven Refactoring)이라고 부르는 이유는 이처럼 둘의 궁합이 잘 맞기 때문이다. 리팩토링에서 테스트는 강력한 버그 탐지기의 역할을 한다. 이런 테스트는 개발을 진행하는 전 주기에 걸쳐서 자주 실행된다. 따라서 자동화된 빌드 도구를 활용해서 모든 테스트를 자동화하는 것이 권장된다. 테스트 주도 개발과 자동화된 테스트는 여러분이 작성한 코드에 대해 자신감을 불어넣고, 리팩토링이라는 도구를 마음껏 휘두를 수 있도록 도와주는 든든한 후원자가 될 것이다.

안타깝게도 나쁜 냄새 목록과 리팩토링 카탈로그를 달달 외운다고 해서 리팩토링을 숙달했다고 말하기 힘든 것처럼, 테스트 주도 개발도 원리와 기술을 익히기는 쉽지만 실전에서 적용하기 위해서는 오랜 시간의 훈련을 필요로 한다. 아직 테스트 주도 개발을 시도해보지 않았던 개발자라면 모든 것을 한꺼번에 이루어 내리라는 기대는 버리는 것이 좋다. 1일 1테스트 만들기, 토요일 오후를 테스트 작성 훈련에 할애하기와 같이 조금씩 자신의 테스트 관련 기술을 향상시키는 방법을 고민하고 실천하기를 권한다. 아래 그림에서 보듯 일일이 수작업으로 동작을 확인하던 시절과 비교하면, 자동화된 테스트 작성을 위해 투자한 시간을 분명히 보상받을 수 있을 것이다.


디자인 패턴과 리팩토링
“패턴은 우리가 있고 싶은 곳이고, 리팩토링은 그곳에 이르는 방법이다.”

마틴 파울러가 저술한 리팩토링 서적은 나쁜 디자인을 좋은 디자인으로 바꿔주는 마법과 같은 기법들을 카탈로그 방식으로 잘 분류해서 정리해 주고 있다. 하지만 대부분 이름 변경이나 메소드 추출과 같은 저수준의 리팩토링을 다루고 있기 때문에, 풍부한 경험을 갖추지 못한 개발자들에게는 최선의 설계를 이끌어낼 수 있는 장치가 부족한 것도 사실이다. 이를 보완할 수 있도록 다양한 디자인 패턴이 존재하지만, 디자인 패턴에 집중하다 보면 지속적이고 발전적인 설계라는 리팩토링의 개념에서 벗어나기 쉽다. 패턴의 강력함에 빠져 간단하게 작성할 수 있는 코드를 괜히 복잡하게 만든다거나, 미래의 요구사항까지 모두 예측해서 미리부터 필요이상으로 과도한 설계를 하게 되는 경우가 있는 것이다.

리팩토링을 도입 하자니 패턴을 적용한 것과 같은 품질의 설계에 이르지 못하고, 패턴을 도입하자니 패턴 만능주의에 빠져 버리는 것이 두려운 개발자들을 위해 또 하나의 좋은 서적이 세상에 모습을 드러냈다. 그게 바로 “패턴을 활용한 리팩토링(Refactoring to Patterns)”이라는 책이다. 이 책은 리팩토링에서 소개한 저수준의 리팩토링 기법을 복합적으로 활용해서, 패턴 중심의 사전 설계를 했을 때와 같은 수준의 설계로 코드를 리팩토링 해 나가는 기법을 소개하고 있다. 동기->절차->예제로 구성된 각각의 복합 리팩토링 기법을 리팩토링 서적과 같은 카탈로그 방식으로 정리하고 있다는 것도 장점이다. 디자인 패턴과 리팩토링을 공부했지만 아직 그 두 가지 기술이 가지는 장점을 하나로 합칠 만큼의 내공을 갖추지 못했다면, “패턴을 활용한 리팩토링” 서적에 소개된 기법들을 훈련하고 적용해보기를 권한다.

프로젝트 팀의 리팩토링

팀 단위 개발을 진행할 때의 리팩토링은 몇 가지 주의할 점이 있다.

1. 리팩토링을 지원하는 툴이 표준 개발 환경에 포함되도록 하라.
툴의 도움없이 리팩토링을 수행하는 것은 지극히 위험하고 따분한 작업이다. 리팩토링을 수행하기 위해 필요한 최소한의 도구는 리팩토링 기능이 추가된 개발환경(예: 이클립스)과 최악의 경우 이전 상태로 되돌아 가기 위한 버전관리시스템(예: CVS)이다. 이러한 도구의 도움 없이 수작업으로 리팩토링 하는 것은 예상치 못한 버그를 만들어 낼 수 있으므로 피하는 것이 좋다.

2. 이름을 변경할 때는 반드시 코딩표준안을 참조하라.
이름 변경(Rename)은 단순하지만 가장 효과적인 리팩토링 방법이다. 개발자의 의도가 충분히 드러나도록 이름을 지어두는 것 만으로도 문제의 복잡성을 낮출 수 있다. 하지만 의미있는 이름에 대한 개발자의 생각이 서로 다르기 때문에, 자신이 선호하는 이름이 아니라고 해서 이름을 변경해 버리는 것은 팀 전체로 볼 때 오히려 혼란을 초래할 수 있다. 당신이 어떤 팀에 소속되어 일하고 있다면, 그 팀의 이름 작성 규칙을 반드시 숙지하고, 그 규칙이 허용하는 범위 안에서만 이름을 변경해야 한다.

3. 공개된 인터페이스를 변경할 경우 호환성 여부를 확인하라.
외부에서 참조하는 경우가 많고 버전까지 달라지는 경우라면 공개된 인터페이스에 대한 리팩토링을 신중하게 수행할 필요가 있다. 꼭 필요하다고 판단해서 메소드 명이나 파라미터를 변경했다면, 기존 시스템과의 호환성이 깨어지지 않도록 주의해야 한다. 호환성을 해치지 않기 위해서는 이전에 공개된 인터페이스와 그 구현을 미사용(Deprecated) 형태로 남겨둬야 하는데, 그런 API가 많아지면 유지보수가 힘들어진다. 따라서 공개 인터페이스는 이후의 확장이나 변경에 영향을 받지 않도록 초기 설계를 보다 신중하게 할 필요가 있다.

4. 마감일이 가까워 오면 리팩토링 시기를 미뤄라.
테스트 등을 통해 오류를 자동으로 검출해 낼 수 있다고 하더라도, 리팩토링으로 인해 발생한 오류를 수정할 시간이 필요해진다. 일주일 뒤에 중요한 보고회가 예정되어 있거나, 시스템 마감일이 가까워진 시점에서 리팩토링을 수행하는 것은 무모한 판단일 수 있다. 이럴 경우는 미진한 설계를 개선시키고자 하는 욕구를 잠시 억눌러 두고, 그 시간을 시스템 안정화를 위해 사용하는 것이 더 좋다.

5. 리팩토링을 포기하고 재작성하는 것이 옳을 때도 있다.
가끔 개발과 관련된 근거 문서도 없고, 어떤 것들이 제대로 동작하는 지를 확인할 수 있는 테스트 코드도 전혀 없고, 컴퓨터만이 겨우 해독해 낼 수 있는 특수한 스파게티 코드로 둘러싸여진 ‘괴물’과 같은 프로그램을 접할 때가 있다. 그런 코드를 리팩토링 하는 것은 설사 그것이 가능하다 하더라도 개발자란 직업을 포기하고 싶을 만큼의 강력한 스트레스를 유발하므로 피하는 것이 옳다. 그런 코드를 만나면 코드 작성자에게 전달되게끔 강력한 포스로 한바탕 욕을 퍼붙고 나서, 그로 인해 얻은 에너지를 토대로 처음부터 재작성할 결심을 굳히도록 하자.