여기서 말하는 리팩터링은 파울러의 방대한 카탈로그 전체가 아니라, TDD의 초록 막대 위에서 자주 쓰는 몇 가지다. 전제가 하나 있다 — 리팩터링은 테스트가 초록일 때만 한다. 초록이 지켜 주지 않으면 그건 리팩터링이 아니라 그냥 코드 수정이고 위험하다.
두 코드를 닮게 만든 뒤 합친다
차이점 일치시키기. 비슷하지만 조금 다른 두 코드 조각을 합치기 전에, 먼저 둘을 점점 더 닮게 고쳐 차이를 좁힌다. 구조가 똑같아지는 순간 하나로 합치는 것은 자명해진다. 16장에서 Dollar와 Franc를 닮게 만들어 상위 Money로 합친 그 과정이다. 중복 제거의 실전 절차이기도 하다.
// 합치기 전 — 두 메서드를 먼저 똑같은 모양으로 정렬한다
Money times(int m) { return new Dollar(amount * m); } // →
Money times(int m) { return new Money(amount * m, "USD"); }
// 구조가 같아지면 상위로 끌어올려 하나로 합친다판단 기준: 두 조각을 합치기 어렵다면 아직 충분히 닮지 않은 것 — 합치기 전에 차이부터 좁힌다. 함정: 닮게 만들기를 건너뛰고 곧장 합치면, 미묘한 차이가 조건 분기로 스며들어 합친 코드가 더 지저분해진다.
변화를 한 곳에 가둔다
변화 격리하기. 코드의 한 부분만 바꾸고 싶은데 변경이 여러 곳으로 번지면, 먼저 그 부분을 별도 메서드·객체로 격리해 변경 지점을 하나로 좁힌다. 큰 변경을 시작하기 전의 준비 작업이다. 바꿔야 할 것과 그대로 둘 것 사이에 경계를 긋는다.
데이터 이주시키기. 표현 방식을 바꿀 때(예: 내부 필드의 타입 변경), 한 번에 갈아엎지 않고 두 표현을 잠시 공존시킨다. 새 표현을 추가하고, 읽는 쪽을 하나씩 옮기고, 마지막에 옛 표현을 지운다. 각 단계마다 테스트가 초록을 유지하니 안전하다.
판단 기준: 변경이 세 곳 이상으로 번질 조짐이면, 바로 고치지 말고 변화 격리부터 한다. 함정: 데이터 이주 중 두 표현을 공존시킨 채 커밋을 오래 미루면 “임시” 이중 표현이 눌러앉는다 — 이주는 짧게 끝내고 옛것을 반드시 지운다.
메서드를 다루는 기본기
메서드 추출. 길고 복잡한 코드 조각을 잘 명명된 메서드로 뽑아낸다. 이름이 의도를 설명해 주석이 필요 없어진다. 리팩터링의 가장 기본이자 가장 자주 쓰는 동작이다.
메서드 인라인. 반대로, 이제는 이름값을 못 하는 짧은 위임 메서드는 본문을 호출부에 되돌려 넣어 간접 계층을 없앤다. 추출과 인라인은 상황에 따라 양방향으로 오간다 — 지금 어느 쪽이 더 읽기 쉬운가가 기준이다.
# 추출 — 조건식을 의도를 말하는 메서드로
def is_overdue(self):
return self.due_date < today() # if self.due_date < today() 를 대체메서드 추출은 리팩터링 카탈로그에서 가장 자주 쓰이는 동작이고, 나머지 리팩터링 다수의 전처리 단계이기도 하다. 변화 격리도, 메서드 옮기기도 대개 “먼저 추출해서 이름을 붙인 뒤” 옮기거나 격리한다. 이름 붙이기가 사고의 첫걸음이다.
인터페이스 추출. 한 클래스의 여러 구현을 두고 싶을 때, 공통으로 쓰는 메서드들을 인터페이스로 뽑는다. 27장의 모의 객체·사칭 사기꾼이 실제 객체와 나란히 설 자리를 이 인터페이스가 만들어 준다. 자바처럼 정적 타입 언어에서 대역을 끼우는 전제 작업이다.
메서드 옮기기. 어떤 메서드가 자기 클래스보다 다른 클래스의 데이터를 더 많이 쓴다면, 그 데이터가 있는 쪽으로 옮긴다. 기능 편애(feature envy)라 불리는 냄새에 대한 처방으로, 데이터와 그 데이터를 쓰는 행동을 한 곳에 모은다.
판단 기준: 메서드가 남의 필드를 자기 필드보다 더 자주 만지면 옮길 신호다. 함정: 인터페이스 추출을 남발해 구현이 하나뿐인 인터페이스를 곳곳에 만들면, 대역이 필요 없는 곳까지 간접 계층만 늘어난다 — 두 번째 구현이 실제로 필요할 때 뽑는다.
정리
- 이 리팩터링들은 전부 “초록을 유지한 채 작은 걸음으로”라는 공통 규율 위에 있다. 각 걸음 뒤 테스트를 돌려 초록을 확인한다.
- 차이점 일치·변화 격리·데이터 이주는 큰 변경을 작은 안전한 걸음들로 쪼개는 전략이고, 메서드 추출·인라인·옮기기·인터페이스 추출은 그 걸음을 이루는 손동작이다.
- 리팩터링의 목적지는 대개 30장의 디자인 패턴이다 — 중복을 지우다 보면 값 객체·템플릿 메서드·컴포지트에 도달한다. 패턴을 알면 어디로 가야 할지가 먼저 보인다.
- 앞부(16장)와 앞 장(27장)에서 지나온 지점들이 여기서 이름을 얻는다.
다음장으로 32장