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

순서

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


I. 배경

복잡한 조건부 로직은 코드를 이해하기도 어렵게 만드는 가장 흔한 원흉이다.
그 이유는 "왜" 일어나는지를 제대로 표현해주지 못해서이다.

따라서 각 조건절을 명확한 이름의 함수로 추출하자.

 


II. 절차

1. 조건식과 그 조건식에 딸린 조건절 각각을 함수로 추출한다.

 


III. 예시


원본 코드

#include "gtest/gtest.h"

struct Plan {
  int summer_start;
  int summer_end;
  float summer_rate;
  float regular_rate;
  int regular_service_charge;
};

Plan plan = {601, 831, 1, 1.2, 800};

// 함수 내부의 조건문을 바꾸자
int GetCharge(int date, int quantity) {
  int charge = 0;
  if ((date >= plan.summer_start) && (date <= plan.summer_end)){charge = quantity * plan.summer_rate;
  } else {
  charge = quantity * plan.regular_rate + plan.regular_service_charge;}
  return charge;
}


TEST(DecomposeConditional, GetCharge_IsAfter531) {
  int quantity = 10000;
  int date = 531;
  ASSERT_EQ(12800, GetCharge(date, quantity));
}

TEST(DecomposeConditional, GetCharge_IsAfter601) {
  int quantity = 10000;
  int date = 601;
  ASSERT_EQ(10000, GetCharge(date, quantity));
}

TEST(DecomposeConditional, GetCharge_IsBefore831) {
  int quantity = 10000;
  int date = 831;
  ASSERT_EQ(10000, GetCharge(date, quantity));
}

TEST(DecomposeConditional, GetCharge_IsBefore901) {
  int quantity = 10000;
  int date = 901;
  ASSERT_EQ(12800, GetCharge(date, quantity));
}

 


1. 조건문 로직을 명확히 분해하기

// struct Plan 및 TEST코드 생략
#include "gtest/gtest.h"

struct Plan;
Plan plan = {601, 831, 1, 1.2, 800};

bool isSummer(int date) {  /* 1. 조건문 분해 */ 
  return ((date >= plan.summer_start) && (date <= plan.summer_end))
}

int GetCharge(int date, int quantity) {
  int charge = 0;
  if (isSummer(date)){  /* 1. isSummer()의 함수로 "왜" 일어나는지 말해줌 */
    charge = quantity * plan.summer_rate;
  } else {
  charge = quantity * plan.regular_rate + plan.regular_service_charge;}
  return charge;
}

 


2. 결과값의 로직도 함수로 추출한다.

// struct Plan 및 TEST코드 생략
#include "gtest/gtest.h"

struct Plan;
Plan plan = {601, 831, 1, 1.2, 800};

bool isSummer(int date) {  /* 1. 조건문 분해 */ 
  return ((date >= plan.summer_start) && (date <= plan.summer_end))
}

float getSummerCharge() {  /* 2. 조건 결과 로직 분리 */
  return quantity * plan.summer_rate;
}

float getRegularCharge() {  /* 2. 조건 결과 로직 분리 */
  return quantity * plan.regular_rate + plan.regular_service_charge;
}

int GetCharge(int date, int quantity) {
  int charge = 0;
  if (isSummer(date)){  /* 1. isSummer()의 함수로 "왜" 일어나는지 말해줌 */
    charge = getSummerCharge;  /* 2. 조건 결과 로직 분리 */
  } else {
    charge = getNormalCharge;  /* 2. 조건 결과 로직 분리 */
  }
  return charge;  /* charge 변수 안쓰고 if else에서 바로 return 가능 */
}

 


IV. 기타

무엇이든 명확한 이름의 함수 쪼개기가 가장 중요한 듯 하다.

+ Recent posts