이 글은 리팩터링 2판(마틴 파울러) 책을 참고하였습니다.

순서

I. 배경
II. 절차
III. 예시
IV. 기타


I. 배경

임시변수(Temp)를 질의함수(Query)로 바꾸는 이유는 궁극적으로
부자연스러운 의존 관계나 부수효과를 찾고 제거하는데에 있다.

함수 안에서 어떤 코드의 결과를 다시 참조하여 사용 할 목적으로 임시변수(Temp)
를 사용하기도 하는데, 이를 아예 함수로 만든다는 의미이다.

이 리팩토링은 클래스 안에서 적용할 때 효과가 가장 큰데,
클래스의 특성상 비슷한 변수들이 모여있고 이를 공통 메소드로 제공하기 때문이다.

변수는 한 번만 계산하고 그 뒤로는 읽기만 하는 것이 가장 최선인데
이와 반대되는 '옛날 주소' 처럼 스냅샷 용도로 쓰이는 변수에는 이 리팩토링을 사용하면 안된다.

 


II.절차

 

1. 변수가 사용되기 전에 확실히 결정되는지,
사용때 마다 계산로직이 매번 다른 결과를 갖는지 확인한다.

 

2. 읽기전용으로 만들 수 있는 변수는 읽기전용으로 만든다.

 

3. 1차 테스트 진행

 

4. 변수 대입문을 함수로 추출한다.

함수가 부수효과를 일으키지 않는지 확인해야한다.

 

5. 테스트 후 변수를 함수로 변경하여 임시 변수를 제거한다.

 


III. 예시


코드 원본

#include "gtest/gtest.h"

int quantity;
int price;

float GetPrice() {
    int base_price = quantity * price;
    float discount_factor = 0.98;
    if (base_price > 1000) {
    discount_factor -= 0.03;
    }
    return base_price * discount_factor;
}

TEST(ReplaceTempWithQuery, GetPrice_1000) {
  quantity = 1000;
  price = 1;
  ASSERT_FLOAT_EQ(980, GetPrice());
}

TEST(ReplaceTempWithQuery, GetPrice_1001) {
  quantity = 1001;
  price = 1;
  ASSERT_FLOAT_EQ(950.95, GetPrice());
}

 


1.  base_price를 함수로 만들기  (모든 temp 대체됨)

#include "gtest/gtest.h"

int quantity;
int price;

int getBasePrice() {  // 1. temp -> Query
    return quantity * price;
}

float GetPrice() {

    float discount_factor = 0.98;
    if (getBasePrice() > 1000) {  // 1. temp->query
    discount_factor -= 0.03;
    }
    return getBasePrice() * discount_factor;  // 1. temp->query
}

// Test 생략

 


2. discount_factor를 함수로 만들기

#include "gtest/gtest.h"

int quantity;
int price;

int getBasePrice() {  // 1. temp -> Query
    return quantity * price;
}

float getDiscountFactor() { // 2. temp ->Query
    float discount_factor = 0.98;
    if (getBasePrice() > 1000) {
    discount_factor -= 0.03;
    }
    return discount_factor;
}

float GetPrice() {  // 동작 함수가 매우 깔끔!
    return getBasePrice() * getDiscountFactor();  
}

// Test 생략

 


IV. 기타

결국 이 리팩토링 기법은 클래스에서 멤버변수를 제공하는 인터페이스를 잘 만들어야 한다는 내용같다.

또한 한 발짝 더 나아가 최종 리팩토링이 끝난 코드가 "좋은 코드"가 되는 이유는
리팩토링 된 후 새로 생긴 getBasePrice(), getDiscountFactor()에 대한 TEST코드를 추가로 진행 할 수 있기 때문이다.

코드를 깔끔하게 만들고싶다...

 

+ Recent posts