Refactoring (리펙토링)
[Refactoring] 5-3. 기본적인 리펙토링 (여러 함수를 하나의 함수로 묶기)
jake-kim
2023. 3. 19. 02:30
리펙토링 핵심
- 각 방법들을 '왜' 수행해야 하는지 깨닫고 유연하게 적용하기
함수들을 클래스로 묶기
- 함수는 데이터를 입력받아서 여러가지 정보를 얻는데, 이렇게 입력받는 데이터들의 중복을 줄이기 위한 방법
- 매개변수 같은 중심(공통 데이터)으로 긴밀하게 엮여 작동하는 함수 무리를 하나의 함수로 묶는 것
- 장점 - 중복코드를 막고 함수들이 공유하는 공통 환경을 더욱 명확하게 표현이 가능

ex) 여러 함수를 묶기
- 보일러 사용량과 기간에 대해 세금을 계산하는 코드
// 보일러 사용 정보
struct UseInfo {
let quantity = 1
let month = 2
let year = 3
}
// 보일러 정보 획득
func getUseInfo() -> UseInfo {
UseInfo()
}
// 기본적으로 내야하는 비율
func baseRate(month: Int, year: Int) -> Int {
month + year
}
// 세금의 최댓값
func taxThreshold(year: Int) -> Int {
year * 3
}
- a 고객의 세금 계산
- 문제점: baseRate를 구할때 month, year 모두 aUserInfo 하나만 받으면 내부에서 .month, .year 접근해서 사용 가능하므로 파라미터를 하나만 받도록 수정해도 처리가 가능
let aUserInfo = getUseInfo()
let aBaseCharge = baseRate(month: aUserInfo.month, year: aUserInfo.year) * aUserInfo.quantity
let aTexableCharge = max(0, bBaseCharge - taxThreshold(year: 2023))
- calculateBaseCharge(userInfo:) 를 만들어서 리펙토링
func calculateBaseCharge(useInfo: UseInfo) -> Int {
baseRate(month: useInfo.month, year: useInfo.year)
}
let bUseInfo = getUseInfo()
let bBaseCharge = calculateBaseCharge(useInfo: aUseInfo) * bUseInfo.quantity
let bTexableCharge = max(0, bBaseCharge - taxThreshold(year: 2023))
- 하나의 함수로 묶어서, 사용하는 쪽(=클라이언트 코드)에서는 단순히 useInfo와 year만 넣으면 되도록 구현
func calculateTotalCharge(useInfo: UseInfo, year: Int) -> Int {
let baseCharge = calculateBaseCharge(useInfo: useInfo)
let textableCharge = max(0, baseCharge, taxThreshold(year: year))
return textableCharge
}
let cTexableCharge = calculateTotalCharge(useInfo: getUseInfo(), year: 2023)
- 결과
- 중복 제거 - 리펙토링전에 클라이언트 코드에서 baseCharge와 textableCharge를 계산하는 코드가 a 클라이언트 코드, b 클라이언트 코드가 생성되지만 리펙토링 후에는 이런 중복 작업이 불필요
- 주의
- 파라미터의 데이터들이 중복으로 생길때 함수로 묶을수도 있지만, 원본 데이터가 코드 안에서 갱신될때는 함수가 아닌 클래스로 묶을 것 (상태가 변경된다는 것은 함수가 아닌 인스턴스의 성격을 갖는 클래스로 묶는것이 더욱 적합)
- * 클래스는 상태(state)와 동작(method)로 이루어져 있기 때문에 상태를 변경할땐 이러한 인스턴스로 관리하는게 논리적으로 더욱 코드를 읽는 입장에서 예측하기 쉬움
* 참고
- Refactoring (Marting Flowler)