본문 바로가기

Clean code

리팩토링 - 12장. 복합 리팩토링 ( 절차코드를 객체로 전환 )

코드 리뷰를 요즘 적극적으로 진행하면서 리팩토링 공부에 대한 필요성을 느꼈다. 팀원들이 가끔 너무 바빠서 리팩토링 할 시간이 없다고 하는데, 마틴 말대로 리팩토링은 기능을 추가하거나 버그를 수정하면서 조금씩 해야 된다고 생각한다. 

 

복합 리팩토링 파트는 함수명 재정의처럼 금방 되는건 아니지만, 아래와 같은 이유로 해당 리팩토링은 꼭 필요하다.

 

충분히 이해하지 못한 상태에서 설계를 결정하는 일이 누적되면 막 자란 물풀로 막힌 운하처럼 프로그램이 막혀버린다.
- 마틴 파울러 

절차 코드를 객체로 전환 ( Convert Procedural Design to Objects )

코드가 절차식으로 작성되어 있을 땐, 데이터 레코드를 객체로 바꾸고, 기능을 쪼개서 각각의 객체로 옮기자.

// Before - 절차지향적인 코드
class OrderCalculator {
  determinePrice (order) { }
  determineTaxes (order) { }
}
class Order { }
class OrderLine { }

// After - 객체로 전환된 코드
class Order {
  getPrice () { }
  getTaxes () { }
}
class OrderLine {
  getPrice () { }
  getTaxes () { }
}
  1. Order,OrderLine과 같은 데이터 객체에 읽기/쓰기 메서드만 있는 더미 데이터 객체로 바꾸자.
  2. 모든 절차코드 ( OrderCalculator ) 를 메서드 추출을 통해 기능을 잘게 쪼개고, 메서드 이동을 통해 데이터 객체로 이동시키자.
  3. 절차코드 클래스에서 모든 기능이 삭제될 때까지 계속하자.

상속 구조 정리 ( Tease Apart Inheritance )

하나의 상속 계층이 두 작업을 동시에 할 땐 상속 계층을 하나 더 만들어서 위임을 통해 다른 계층을 호출하자

// Before
class Deal { }
class ActiveDeal extends Deal { }
class PassiveDeal extends Deal { }
class TabularActiveDeal extends ActiveDeal { }
class TabularPassiveDeal extends PassiveDeal { }

// After
class Deal {
  constructor () {
    this.presentationStyle = new PresentationStyle()
  }
}
class ActiveDeal extends Deal { }
class PassiveDeal extends Deal { }

class PresentationStyle { }
class SinglePresentationDeal extends PresentationStyle { }
class TabularPresentationDeal extends PresentationStyle { }

클래스 이름에  Tabular, Passive 두가지 형용사가 들어간 것만 봐도 한 계층으로 두가지 기능을 수행하고 있는 것을 알 수 있다. 

계층 구조 추출 ( Extract Hierachy )

한 클래스에 기능이 너무 많고 일부분에라도 조건문이 많을 땐 각 조건에 해당하는 하위클래스를 작성해서 계층구조를 만들자.

// Before - 한 클래스에 조건문이 많은 코드
class BillingScheme { }

// After - 조건에 해당하는 하위 클래스로 작성한 코드
class BillingScheme { }
class BusinessBillingScheme extends BillingScheme { }
class ResidentialBillingScheme extends BillingScheme { }
class DisabilityBillingScheme extends BillingScheme { }