Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- combine
- Xcode
- clean architecture
- Refactoring
- 리펙터링
- RxCocoa
- swift documentation
- map
- Clean Code
- tableView
- HIG
- collectionview
- 클린 코드
- 스위프트
- Human interface guide
- swiftUI
- uiscrollview
- MVVM
- ios
- ribs
- 애니메이션
- 리펙토링
- uitableview
- rxswift
- UICollectionView
- Observable
- UITextView
- SWIFT
- 리팩토링
- Protocol
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[Refactoring] 1-2. 리펙토링이란?, 리펙토링의 예시 본문
* [Refactoring] 1-1. 리펙토링이란?, 리펙토링의 예시 먼저 참고
Refactoring - 함수 쪼개기
- getInvoiceInfo 함수 쪼개기
- 전체 동작을 각각의 부분으로 나눌 수 있는 지점을 탐색 -> switch 문 확인
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
}
- switch문 부분을 amountFor()함수로 따로 쪼개기
private func amountFor(genre: String, audienceCount: Int) -> Int {
var thisAmount = 0
switch genre {
case "comedy": // 희극
thisAmount = 40000
if audienceCount > 30 {
thisAmount += 1000 * (audienceCount - 30)
}
case "tragedy": // 비극
thisAmount = 30000
if audienceCount > 20 {
thisAmount += 10000 + 500 * (audienceCount - 30)
}
default: fatalError()
}
return thisAmount
}
func getInvoiceInfo(customer: Customer) -> String {
var totalAmount = 0 // 토탈 비용
var volumnCredits = 0 // 포인트 적립
var result = "청구 내역 (고객명: \(customer.name))\n"
for performance in customer.requestPerformance {
var thisAmount = amountFor( // <- 호출
genre: performance.playId.genre,
audienceCount: performance.audienceCount
)
...
- 이렇게 수정한 후 테스트 코드가 있다면, 실수한 게 없는지 확인
- 사람은 실수를 하기 때문에 아무리 간단한 수정이라도 테스트할것
- 오류가 생기더라도 변경 폭이 작기 때문에 살펴볼 범위도 좁아서 문제를 찾고 해결하기가 수월
- 컴파일 - 테스트 - 커밋
Refactoring - 이름을 명확하게 수정
- thisAmount를 result로 변경
private func amountFor(genre: String, audienceCount: Int) -> Int {
var result = 0 // <- 명확한 이름으로 변경
switch genre {
case "comedy": // 희극
result = 40000
if audienceCount > 30 {
result += 1000 * (audienceCount - 30)
}
case "tragedy": // 비극
result = 30000
if audienceCount > 20 {
result += 10000 + 500 * (audienceCount - 30)
}
default: fatalError()
}
return result
}
- 컴파일 - 테스트 - 커밋
Refactoring - 함수 쪼개기 2
- credit을 계산하는 부분을 함수로 빼기
private func volumnCreditsFor(performance: Content) -> Int {
// 포인트 적립
var volumnCredits = max(performance.audienceCount - 30, 0)
// 희극 관란객 5명마다 추가 포인트 제공
if performance.playId.genre == "comedy" {
volumnCredits += performance.audienceCount / 5
}
return volumnCredits
}
// 적용
func getInvoiceInfo(customer: Customer) -> String {
var totalAmount = 0 // 토탈 비용
var volumnCredits = 0 // 포인트 적립
var result = "청구 내역 (고객명: \(customer.name))\n"
for performance in customer.requestPerformance {
let thisAmount = amountFor(
genre: performance.playId.genre,
audienceCount: performance.audienceCount
)
volumnCredits += volumnCreditsFor(performance: performance) // <- 호출
// 청구 내역 출력
result += " \(performance.playId): \(thisAmount)원 \(performance.audienceCount)좌석\n"
totalAmount += thisAmount
}
result += "총액: \(totalAmount)원\n"
result += "적립 포인트: \(volumnCredits)점\n\n"
return result
}
- 컴파일 - 테스트 - 커밋
Refactoring - 반복문 쪼개기
- 먼저 volumnCredits += 하는 부분은 반복문이 한번 돌때마다 값을 누적하므로 리펙토링이 어렵기 때문에 volumnCredits값이 누적되는 부분으로 따로 뺄 것
for performance in customer.requestPerformance {
let thisAmount = amountFor(
genre: performance.playId.genre,
audienceCount: performance.audienceCount
)
// 청구 내역 출력
result += " \(performance.playId): \(thisAmount)원 \(performance.audienceCount)좌석\n"
totalAmount += thisAmount
}
for performance in customer.requestPerformance { // <- 값 누적 로직을 별도 for문으로 분리
volumnCredits += volumnCreditsFor(performance: performance)
}
- 문장 슬라이드하기(뒤에서 다룰 내용)를 통해서 volumeCredits 변수를 선언하는 문장을 반복문 바로 앞으로 이동
func getInvoiceInfo(customer: Customer) -> String {
var totalAmount = 0 // 토탈 비용
var result = "청구 내역 (고객명: \(customer.name))\n"
for performance in customer.requestPerformance {
let thisAmount = amountFor(
genre: performance.playId.genre,
audienceCount: performance.audienceCount
)
// 청구 내역 출력
result += " \(performance.playId): \(thisAmount)원 \(performance.audienceCount)좌석\n"
totalAmount += thisAmount
}
// 문장 슬라이드하기 - 변수 초기화를 반복문 앞으로 이동
var volumnCredits = 0 // 포인트 적립
for performance in customer.requestPerformance {
volumnCredits += volumnCreditsFor(performance: performance)
}
result += "총액: \(totalAmount)원\n"
result += "적립 포인트: \(volumnCredits)점\n\n"
return result
}
- 해당 부분을 함수로 쪼개기
// nested 함수로 추출
func totalVolumeCredits() -> Int { // <- 추가
return customer.requestPerformance
.map(self.volumnCreditsFor(performance:))
.reduce(0, +)
}
// 적용
func getInvoiceInfo(customer: Customer) -> String {
func totalVolumeCredits() -> Int { // <- 추가
return customer.requestPerformance
.map(self.volumnCreditsFor(performance:))
.reduce(0, +)
}
var totalAmount = 0 // 토탈 비용
var result = "청구 내역 (고객명: \(customer.name))\n"
for performance in customer.requestPerformance {
let thisAmount = amountFor(
genre: performance.playId.genre,
audienceCount: performance.audienceCount
)
// 청구 내역 출력
result += " \(performance.playId): \(thisAmount)원 \(performance.audienceCount)좌석\n"
totalAmount += thisAmount
}
let volumnCredits = totalVolumeCredits() // <- 적용
result += "총액: \(totalAmount)원\n"
result += "적립 포인트: \(volumnCredits)점\n\n"
return result
}
-> 반복문을 여러개로 쪼개서 성능에 영향이 있지만 미비하여, 마틴 파울러는 미비한 성능 부분은 무시를 권장
- 위에서 중요한 리펙토링 방법: 한꺼번에 함수를 쪼개지 않았고 여러 단계를 통해서 수행
- 반복문 쪼개기 (변수 값을 누적시키는 부분을 분리)
- 문장 슬라이드하기 (초기화 문장을 변수 값 누적 코드 바로 앞으로 이동)
- 함수 추출하기 (적립 포인트 계산 부분을 별도 함수로 추출)
* 참고
- Refactoring (Marting Flowler)
'Refactoring (리펙토링)' 카테고리의 다른 글
[Refactoring] 3-2. 코드에서 나는 악취 (중복 코드, 긴 함수, 긴 매개변수, 전역 데이터, 가변 데이터, switch 문, 반복문, default value) (0) | 2023.01.15 |
---|---|
[Refactoring] 3-1. 코드에서 나는 악취 (0) | 2022.01.23 |
[Refactoring] 2-2. 리팩터링 원칙, 리펙터링의 목적 (3) | 2022.01.21 |
[Refactoring] 2-1. 리팩터링 원칙, 리펙터링의 목적 (0) | 2022.01.20 |
[Refactoring] 1-1. 리펙토링이란?, 리펙토링의 예시 (0) | 2021.12.31 |
Comments