[Refactoring] 메서드 정리

메서드 정리

서문 요약

메서드 추출 (Extract Method)

어떤 코드를 그룹으로 묶어도 되겠다고 판달될 땐, 그 코드를 빼내어 목적을 잘 나타내는 직관적 이름의 메서드로 만들자.

def print_owing(amount):
    print_banner()
    
    # 세부 정보 출력
    print('{name}'.format(name))
    print('{amount}'.format(amount))
def print_owing(amount):
    print_banner()
    print_details(amount)
    
def print_details(amount):
    print('{name}'.format(name))
    print('{amount}'.format(amount))

동기

예제: 지역변수 사용 안 함

def print_owing():
    e = _orders.elements()
    outstanding = 0
    
    # 배너 출력
    print("***********************")
    print("*******고객 외상*********")
    print("***********************")
    
    # 외상액 계산
    ...
    
    # 세부 내역 출력
    ...
        
def print_owing():
    e = _orders.elements()
    outstanding = 0
    
    print_banner()
    
    # 외상액 계산
    ...
    
    # 세부 내역 출력
    ...
def print_banner():
    print("***********************")
    print("*******고객 외상*********")
    print("***********************")
        

예제: 지역변수 사용

def print_owing():
    e = _orders.elements()
    outstanding = 0
    
    print_banner()
    
    # 외상액 계산
    ...
    
    # 세부 내역 출력
    print("고객명: {name}".format(name))
    print("외상액: {outstanding}".format(outstanding))
    
def print_banner():
    print("***********************")
    print("*******고객 외상*********")
    print("***********************")
        
def print_owing(name):
    e = _orders.elements()
    outstanding = 0
    
    print_banner()
    
    # 외상액 계산
    ...
    
	print_details(name, outstanding)
    
    
def print_banner():
    print("***********************")
    print("*******고객 외상*********")
    print("***********************")
    
def print_details(name, outstanding):
    print("고객명: {name}".format(name))
    print("외상액: {outstanding}".format(outstanding))
        

지역변수를 다시 대입

def print_owing(name, previous_amount):
    print_banner()
    outstanding = get_outstanding(previous_amount * 1.2)
    print_details(name, outstanding)
    
def print_banner():
    print("***********************")
    print("*******고객 외상*********")
    print("***********************")
    
def print_details(name, outstanding):
    print("고객명: {name}".format(name))
    print("외상액: {outstanding}".format(outstanding))
    
def get_outstanding(initial_value):
    result = initial_value
    e = order.elements()
    for ele in e:
        result += ele.get_amount()
    return result

메서드 내용 직접 삽입(Inline Method)

메서드 기능이 너무 단순해서 메서드명만 봐도 너무 뻔할 땐 그 메서드의 기능을 호출하는 메서드에 넣어버리고 그 메서드는 삭제하자.

def get_rating():
    return 2 if is_more_than_five_late_deliveries else 1

def is_more_than_five_late_deliveries():
    return number_of_late_deliveries > 5
def get_rating():
    return 2 if number_of_late_deliveries > 5 else 1

동기

임시변수 내용 직접 삽입(Inline Temp)

간단한 수식을 대입받는 임시변수로 인해 다른 리팩토링 기법 적용이 힘들 땐 그 임시변수를 참조하는 부분을 전부 수식으로 치환하자.

base_price = an_order.base_price()
return (base_price > 1000)
return (an_order.base_price() > 1000)

동기

임시변수를 메서드 호출로 전환(Replace Temp with Query)

수식의 결과를 저장하는 임시변수가 있을 땐 그 수식을 빼내어 메서드로 만든 후, 임시변수 참조 부분을 전부 수식으로 교체하자. 새로 만든 메서드는 다른 메서드에서도 호출 가능하다.

base_price = quantity * item_price
if base_price > 1000:
    return base_price * 0.95
else:
    return base_price * 0.98
if base_price() > 1000:
    return base_price() * 0.85
else:
    return base_price() 0.98
...
def base_price():
    return quantity * item_price

동기

예제

def get_price():
    base_price = quantity * item_price
    discount_factor = 0
    
    if base_price > 1000:
        discount_factor = 0.95
    else:
        discount_factor = 0.98
    return base_price * discount_factor
def get_price():
    discount_factor = 0
    
    if base_price() > 1000:
        discount_factor = 0.95
    else:
        discount_factor = 0.98
    return base_price() * discount_factor


def base_price():
    return quantity * item_price
def get_price():
    return base_price() * discount_factor()

def base_price():
    return quantity * item_price

def discount_factor():
    if base_price() > 1000:
        return 0.95
    else:
        return 0.98
    
NINETY_FIVE_DISCOUNT_FACTOR = 0.95
NINETY_EIGHT_DISCOUNT_FACTOR = 0.98

def get_price():
    return base_price() * discount_factor()

def base_price():
    return quantity * item_price

def discount_factor():
    if base_price() > 1000:
        return NINETY_FIVE_DISCOUNT_FACTOR
    return NINETY_EIGHT_DISCOUNT_FACTOR
    
NINETY_FIVE_DISCOUNT_FACTOR = 0.95
NINETY_EIGHT_DISCOUNT_FACTOR = 0.98

def calc_price():
    return base_price() * discount_factor()

def calc_base_price():
    return quantity * item_price

def calc_discount_factor():
    return NINETY_FIVE_DISCOUNT_FACTOR base_price() > 1000 else NINETY_EIGHT_DISCOUNT_FACTOR
    

직관적 임시변수 사용 (Introduce Explaining Variable)

사용된 수식이 복잡할 땐 수식의 결과나 수식의 일부분을 용도에 부합하는 직관적 이름의 임시변수에 대입하자.

if (platform.upper() == 'MAC' and 
    platform.upper() == 'CHROME' and 
    was_initialized and resize > 0):
    # 기능 코드
is_mac_os = platform.upper() == 'MAC'
is_chrome_browser = platform.upper() = 'CHROME'
was_resized = resize > 0

if (is_mac_os and is_chrome_browser and was_resized):
    # 기능 코드

동기