Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[Refactoring] 7-6. 기능 이동 (함수 이동, 중첩함수 제거, 모듈성) - 문장 슬라이드 본문

Refactoring (리펙토링)

[Refactoring] 7-6. 기능 이동 (함수 이동, 중첩함수 제거, 모듈성) - 문장 슬라이드

jake-kim 2023. 4. 25. 01:03

문장 슬라이드

  • 관련된 코드끼리 모아두는 형태를 의미
    • 관련된 코드들이 가까이 모여 있을때 이해하기가 더욱 쉽기 때문 
    • 변수 선언을 첫머리에 모아두는 것보다는 변수를 처음 사용할 때 선언하는 형태를 지향

문장 슬라이드

ex) 문장 슬라이드가 필요한 코드

  • 아래 코드는 변수 선언을 첫머리에 모아두는 코드지만, b 변수는 아래에서 사용되고 있으므로 아래로 이동시킬 것
func calculate() {
    var base = 1
    let a: Int
    let b: Int // <-
    
    if base % 2 == 0 {
        a = 1
    } else {
        a = 2
    }
    base += a
    
    if base < 6 {
        b = 3
    } else {
        b = 1
    }
}
  • b선언을 아래로 이동하여 문장 슬라이드 리펙토링 수행
    • b를 계산하는 관련 코드 바로 위에 b선언부도 같이 있기 때문에 b에관한 수정을 할 때 여러곳을 보지 않고 아래 b관련 부분만 보면 수정이 쉬운 장점을 얻을 수 있음
func calculate() {
    var base = 1
    let a: Int
    
    if base % 2 == 0 {
        a = 1
    } else {
        a = 2
    }
    base += a
    
    let b: Int // <-
    if base < 6 {
        b = 3
    } else {
        b = 1
    }
}

문장 슬라이드 리팩토링

ex) 특정 가격이(Plan) 있고 이 가격에 따라 주문(Order)을 했을때 최종 지불 가격(charge)를 계산하는 코드

  • 필요한 구조체와 예제에 사용될 함수 정의
struct Plan {
    var base = 0
    var unit = 1
    var discountThreshold = 2
    var discountFactor = 3
}

struct Order {
    var units = 0
    var isRepeat = false
}

private func retrievePricingPlan() -> Plan {
    Plan()
}
private func retrieveOrder() -> Order {
    Order()
}
private func chargeOrder(charge: Int) {
    print("charge:", charge)
}
  • 현재 가격 정책과(pricingPlan) 주문(order)을 받아서 지불(charge)을 계산하는 코드
// 문장 슬라이드 리펙토링할 코드

let pricingPlan = retrievePricingPlan()
let order = retrieveOrder()
let baseCharge = pricingPlan.base

var charge: Int
let chargePerUnit = pricingPlan.unit
let units = order.units

var discount: Int
charge = baseCharge + units * chargePerUnit

let discountableUnits = max(units - pricingPlan.discountThreshold, 0)
discount = discountableUnits * pricingPlan.discountFactor

if order.isRepeat {
    discount += 20
}

charge -= discount
chargeOrder(charge: charge)
  • cf) 함수를 작성할때의 주의 사항 - side effect 없는 코드를 지향
    • 항상 side effect가 없도록 코딩한다면 코드들의 재배치를 자유자재로 수행해도 재배치가 가능하기 때문에 좋은 코드 유지가 가능
    • 명령-질의 원칙) 함수의 리턴값이 있으면 side effect가 없는 코드로 작성될 것이므로 아래 작성된 retrivePricingPlan(), retrieveOrder()는 단순히 값을 얻어오며 side effect가 없도록 작성할 것
    • 코드 슬라이드를 할 때 명령-질의 원칙(Command-Query Separation)이 지켜져 있으면 코드를 슬라이드할때 side effect를 고려하지 않아도 되므로 더욱 수월
    • 전역 변수보단 지역 변수를 사용할것
    • 만약 명령-질의 원칙이 지켜지지 않는 코드라면, 코드 슬라이드 전에 함수 내부를 먼저 확인해보며 작업해야함
  • 1) 문장 슬라이드 - order 부분을 사용하고 있는 쪽 바로 이동시키기
// before
let pricingPlan = retrievePricingPlan()
let order = retrieveOrder() // <-
let baseCharge = pricingPlan.base

var charge: Int
let chargePerUnit = pricingPlan.unit
let units = order.units

...

// after
let pricingPlan = retrievePricingPlan()
let baseCharge = pricingPlan.base

var charge: Int
let chargePerUnit = pricingPlan.unit

let order = retrieveOrder() // <-
let units = order.units

...
  • 2) 문장 슬라이드 - dicsount 부분을 사용하는 부분에서 바로 초기화하기
// before

...

var discount: Int // <-
charge = baseCharge + units * chargePerUnit
let discountableUnits = max(units - pricingPlan.discountThreshold, 0)
discount = discountableUnits * pricingPlan.discountFactor

if order.isRepeat {
    discount += 20
}

charge -= discount
chargeOrder(charge: charge)

// after

...

charge = baseCharge + units * chargePerUnit
let discountableUnits = max(units - pricingPlan.discountThreshold, 0)

var discount = discountableUnits * pricingPlan.discountFactor // <-

if order.isRepeat {
    discount += 20
}

charge -= discount
chargeOrder(charge: charge)

 

* 전체 코드: https://github.com/JK0369/ExRefactoring_7_6

* 참고

- Refactoring (Marting Flowler)

 

Comments