본문 바로가기

swift공부

[Swift] 리픽토링_메서드 정리 - 메서드 추출

1년 정도 현업에서 개발을 하면서 더 나은 코드에 대한 얘기를 나눌 때 근거가 부족하다는 것을 느끼게 되었습니다. 경험으로 좋은 코드를 깨닫게 될 수 있지만 좀 더 빠르고 명확하게 좋은 코드에 대한 고민을 하기 위해서 마틴 파울러의 리펙토링이라는 책을 읽게 되었습니다. 

 

메서드 추출이란?

어떤 코드를 그룹으로 묶어도 되겠다고 판단될 때, 해당 코드를 뺴내 목적을 잘 나타내는 직관적 이름의 메서드로 만들기

 

메서드가 너무 길거나 코드에 주석을 달아야만 의도를 이해할 수 있을 때 코드를 빼내서 별도의 메서드를 만드는 방식

 

목적에 부합하는 이름으로 메서드를 만들기, 여기서 메서드명은 원리가 아니라 기능을 나타내는 이름이어야 한다. 

-> 즉 무엇을 하는가를 명확하게 드러내는 메서드명을 써야 한다. 

 

원리를 나타내는 이름

calculate(), process(), handle()

해당 메서드명들은 내부 동작 위주의 메서드명으로 좀 더 구체적인 역할의 이름이 보충되어야 한다.

 

✅ 기능을 나타내는 이름

isValidEmail(), saveUserProfile(), printInvoice()

외부에서 봤을 때 메서드의 목적이나 행동을 파악할 수 있도록 하는 것이 좋다. 

 

class Order {
    var amount: Double

    init(amount: Double) {
        self.amount = amount
    }
}

class Customer {
    var name: String
    var orders: [Order]

    init(name: String, orders: [Order]) {
        self.name = name
        self.orders = orders
    }

    func printOwing() {
        var outstanding: Double = 0.0

        // 배너 출력
        print("**************")
        print("** 고객 외상 **")
        print("**************")

        // 외상액 계산
        for order in orders {
            outstanding += order.amount
        }

        // 세부 내역 출력
        print("고객명: \(name)")
        print("외상액: \(outstanding)")
    }
}

 

printOwing 이라는 외상을 출력하는 메서드가 있다고 하자. 현재 메서드 내부를 개선하며 리펙토링을 진행해보고자 한다. 

 

 

1. 지역변수를 사용 안 함

다음과 같이 지역변수를 사용하지 않는 경우 간단히 메서드 추출을 적용할 수 있다. 

   func printOwing() {
        var outstanding: Double = 0.0

        printBanner()

        // 외상액 계산
        for order in orders {
            outstanding += order.amount
        }

        // 세부 내역 출력
        print("고객명: \(name)")
        print("외상액: \(outstanding)")
    }
    
        private func printBanner() {
          print("**************")
          print("** 고객 외상 **")
          print("**************")
      }

 

2. 지역변수를 사용

만약 지역변수를 사용하고 있다면, 그리고 간단히 지역변수가 읽히고만 있다면 지역변수를 매개변수로 전달할 수 있다.

func printOwing() {
        var outstanding: Double = 0.0

        printBanner()

        // 외상액 계산
        for order in orders {
            outstanding += order.amount
        }

        printDetails(outstanding: outstanding)
    }
    
     private func printDetails(outstanding: Double) {
        print("고객명: \(name)")
        print("외상액: \(outstanding)")
    }

 

3. 지역변수를 다시 대입

이럴 경우 임시변수가 추출한 코드 안에서만 사용된다면 간단히 임시변수를 추출한 코드로 옮기면 된다. 

func printOwing() {
        printBanner()

        let outstanding = getOutstanding()
        printDetails(outstanding: outstanding)
    }
    
     private func getOutstanding() -> Double {
        var total = 0.0
        for order in orders {
            total += order.amount
        }
        return total
    }

 

추가로 만약 임시변수가 추출한 코드 밖에서 사용되는 경우, 임시변수는 코드가 추출된 후 사용되지 않는다면 추출한 코드에서 임시변수의 변경된 값을 반환하게 수정해야 한다. 

 

    func printOwing(previousAmount: Double) {
        printBanner()

        let outstanding = getOutstanding(initialValue: previousAmount * 2)
        printDetails(outstanding: outstanding)
    }
    
    private func getOutstanding(initialValue: Double) -> Double {
        var result: Double = initialValue
        

        for order in orders {
            result += order.amount
        }
        return result
    }