관리 메뉴

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

[Refactoring] 1-1. 리펙토링이란?, 리펙토링의 예시 본문

Refactoring (리펙토링)

[Refactoring] 1-1. 리펙토링이란?, 리펙토링의 예시

jake-kim 2021. 12. 31. 01:52

리펙토링이랑?

  • 겉으로 드러나는 코드의 기능은 바꾸지 않으면서 내부 구조를 개선하는 방식
  • 코드를 작성하고 난 뒤에 설계를 개선하는 일
  • 보통 소프트웨어 개발 시 설계 후 코드를 작성하지만, 시간이 흐르면서 설계에 맞춘 구조는 점차 뒤죽박죽이 되어가므로 리펙토링이 필요
  • 리펙토링이란 기존 흐름과 반대의 작업: 엉망이 되어가는 코드 또는 엉망인 설계를 가져다가 체계적으로 설계된 코드로 탈바꿈이 가능
  • 처음부터 완벽한 설계를 갖추기보다 개발을 진행하면서 지속적으로 설계하는 일이며 시스템을 구축하는 과정에서 더 나은 설계가 무엇인지 배우는 것(= 우수한 설계를 유지하게 되는 효과)

리펙토링 예시

  • 연극의 장르, 관객수 데이터를 받아서 계산하여 영수증을 출력하는 프로그램
  • 데이터 모델
    • Customer: 연극 의뢰자
    • Content: 연극 정보
      struct Customer {
        let name: String
        let requestPerformance: [Content]
      }
      
      struct Content {
        enum Name {
          case hamlet
          case othello
          
          var genre: String {
            switch self {
            case .hamlet: return "comedy"
            case .othello: return "tragedy"
            }
          }
        }
        
        let playId: Name
        let audienceCount: Int
      }​
  • Mock 데이터
    • jake라는 사람이 연극을 해달라고 요청하는 상황이고, 연극 내용은 requestPerformance에 등재
      func getMock() -> Customer {
        Customer(
          name: "jake",
          requestPerformance: [
            Content(
              playId: Content.Name.hamlet,
              audienceCount: 55
            ),
            Content(
              playId: Content.Name.othello,
              audienceCount: 32
            ),
            Content(
              playId: Content.Name.othello,
              audienceCount: 72
            ),
          ]
        )
      }​
  • 연극 정보를 받아서 영수증 출력하는 메소드 구현
    func getInvoiceInfo(customer: Customer) -> String {
      var totalAmount = 0 // 토탈 비용
      var volumnCredits = 0 // 포인트 적립
      var result = "청구 내역 (고객명: \(customer.name))\n"
      
      for performance in customer.requestPerformance {
        var thisAmount = 0
        
        switch performance.playId.genre {
        case "comedy": // 희극
          thisAmount = 40000
          if performance.audienceCount > 30 {
            thisAmount += 1000 * (performance.audienceCount - 30)
          }
        case "tragedy": // 비극
          thisAmount = 30000
          if performance.audienceCount > 20 {
            thisAmount += 10000 + 500 * (performance.audienceCount - 30)
          }
        default: fatalError()
        }
        
        // 포인트 적립
        volumnCredits += max(performance.audienceCount - 30, 0)
        
        // 희극 관란객 5명마다 추가 포인트 제공
        if performance.playId.genre == "comedy" {
          volumnCredits += performance.audienceCount / 5
        }
        
        // 청구 내역 출력
        result += "  \(performance.playId): \(thisAmount)원 \(performance.audienceCount)좌석\n"
        totalAmount += thisAmount
      }
      
      result += "총액: \(totalAmount)원\n"
      result += "적립 포인트: \(volumnCredits)점\n\n"
      return result
    }​
  • 사용
    let jake = getMock()
    let invoice = getInvoiceInfo(customer: jake)
    print(invoice)​

-> 만약 100줄이 넘는 큰 메소드였다면 어떻게 접근할지?

-> 기능을 새로 추가해야 한다면 어떻게 접근할지?

-> 급하게 기능만 추가하지 말고, 여러 함수로 쪼개고 프로그램 요소를 재구성하는 등의 구조를 먼저 변경한 후 기능 추가할 것

 

[Refactoring] 1-2. 리펙토링이란?, 리펙토링의 예시에서 계속

 

* 참고

- Refactoring (Martin Flowler)

Comments