관리 메뉴

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

[Refactoring] 5-1. 기본적인 리펙토링 (함수 추출하기, 함수 인라인하기) 본문

Refactoring (리펙토링)

[Refactoring] 5-1. 기본적인 리펙토링 (함수 추출하기, 함수 인라인하기)

jake-kim 2023. 3. 7. 01:50

리펙토링 핵심

  • 각 방법들을 '왜' 수행해야 하는지 깨닫고 유연하게 적용하기

함수 추출하기

  • 하나의 블록 안에 있는것을 함수로 빼는 것
    • 반대 리펙토링: 함수 인라인하기

함수 추출하기

ex) 함수 추출하기 예제

  • 리펙토링 전
func printSome() {
    let person = Person()
    person.name = "jong"
    person.age = 20
    
    print("person's name: \(person.name)")
    print("person's age: \(person.age)")
}
  • 함수 추출하기 리펙토링 반영
func printSome() {
    let person = Person()
    person.name = "jong"
    person.age = 20
    
    print("person's name: \(person.name)")
    print("person's age: \(person.age)")
    printInfo(person: person)
}

func printInfo(person: Person) {
    print("person's name: \(person.name)")
    print("person's age: \(person.age)")
}
  • 함수 추출하기를 왜 하는지?
    • 보통 함수 안에서 코드가 길어지고 복잡해지고 어려운 내용을 담고 있다면, 코드 위에 주석을 담지만 이런 방법보다는 따로 함수로 추출하여 이 함수 시그니처가 주석을 대신하고, 코드를 읽어 나갈때 더욱 빠르게 읽기가 가능한 장점이 존재
  • 함수 추출하기를 잘 하는 방법
    • '어떻게'가 아닌 '무엇을'하는지가 드러나게끔 함수 이름을 짓기 - 함수 이름만 봐도 해당 함수에서 무엇을 하는지가 드러나게 되면 함수 내부를 보지 않아도 무엇을 수행하는지 예측이 가능한 장점이 존재
    • 단, 함수 이름이 길어지지 않고 목적이 분명히 드러나는 이름의 짤막한 함수의 이름을 선정할 것
    • 만약 함수를 추출할 때 많은 수의 파라미터가 필요한 경우, 함수 추출을 멈추고 추후에 알아볼 변수 쪼개기임시 변수를 질의 함수로 바꾸기를 수행한 후 함수 추출을 시도할 것
  • 중첩(nested) 함수로 함수 추출하기
    • 중첩 함수로 추출하면 안쪽 함수에서는 바깥 함수에서 선언한 지역변수에 접근이 가능하며 따로 파라미터를 선언하지 않아도 되는 장점이 존재하여 오버 엔지니어링을 줄일 수 있는 포인트
    • 중첩 함수로 구현하면 해당 함수에서만 사용한다는 의미도 주어서 더욱 응집화에 용이

ex) 위 예제에서 printInfo(person:)를 중첩 함수로 만들어서 person 파라미터 따로 없이 구현 가능

func printSome() {
    let person = Person()
    person.name = "jong"
    person.age = 20
    
    printInfo()
    
    func printInfo() {
        print("person's name: \(person.name)")
        print("person's age: \(person.age)")
    }
}

함수 인라인하기

  • 코드가 명로해지고 이해하기 쉬워지기 위해서는 짤막한 함수를 이용하기를 권하지만, 때로는 함수 이름보다 본문이 더욱 짧고 명확한 경우가 존재하는데 이때, 따로 함수로 뺄 필요 없이 바로 쓰도록 구현할 것
  • 과한 간접 호출은 때로는 거슬리므로, 이런 간접 호출을 제거하는 목적

함수 인라인하기

ex) 함수 인라인 예제 - job이 많은 직원에게 인센티브를 주는 코드

func printTotalSalary(person: Person) {
    print(getSalary(person: person))
}

func getSalary(person: Person) -> Int {
    moreThanThreeJobs(person: person) ? person.salary * 2 : person.salary
}

func moreThanThreeJobs(person: Person) -> Bool {
    person.jobs > 3
}
  • moreThanThreeJobs 함수를 따로 두지 말고 getSalary(person:) 메소드에 인라인하기
func getSalary(person: Person) -> Int {
    (person.jobs > 5) ? person.salary * 2 : person.salary
}
  • 함수 인라인을 했더니 getSalary 함수가 더욱 짧고 명확한 의미를 전달된 상태이며, 쓸데없는 간접 호출이 없어진 상태

* 참고

- Refactoring (Marting Flowler)

Comments