메서드 정리 - ChoDragon9/posts GitHub Wiki

메서드 정리

메서드 추출(Extract Method)

어떤 코드를 그룹으로 묶어도 되겠다고 판단될 때

// Before
const printOwing = (amount) => {
  printBanner()
  console.log(`name:${_name}`)
  console.log(`amount:${amount}`)
}

// After
const printOwing = (amount) => {
  printBanner()
  printDetails(amount)
}
const printDetails = (amount) => {
  console.log(`name:${_name}`)
  console.log(`amount:${amount}`)
}

메서드 내용 직접 삽입(Inline Method)

매서드 기능이 너무 단순해서 메서드명만 봐도 너무 뻔할 때

// Before
const moreThanFiveLateDeliveries = () => {
  return _numberOfLateDeliveries > 5
}
const getRating = () => {
  return (moreThanFiveLateDeliveries()) ? 2 : 1
}

// After
const getRating = () => {
  return (_numberOfLateDeliveries > 5) ? 2 : 1
}

임시변수 내용 직접 삽입(Inline Temp)

간단한 수식을 대입받는 임시변수로 인해 다른 리팩토링 기법 적용이 힘들 때

// Before
const basePrice = anOrder.basePrice()
return basePrice > 1000

// After
return anOrder.basePrice() > 1000

임시변수를 메서드 호출로 변환(Replace Temp with Query)

수식의 결과를 저장하는 임시변수가 있을 때

// Before
const basePrice = _quantity * _itemPrice
if (basePrice > 1000) {
  return basePrice * 0.95
} else {
  return basePrice * 0.98
}

// After
const basePrice = () => _quantity * _itemPrice
if (basePrice() > 1000) {
  return basePrice() * 0.95
} else {
  return basePrice() * 0.98
}

직관적 임시변수 사용(Introduce Explaining Variable)

사용된 수식이 복잡할 때

// Before
if (
  platform.toUpperCase().indexOf('MAC') > -1 &&
  browser.toUpperCase().indexOf("IE") > -1 &&
  wasInitialized() && resize > 0 ) {
  // 기능 코드  
}

// After
const isMacOs = platform.toUpperCase().indexOf('MAC') > -1
const isIEBrowser = browser.toUpperCase().indexOf("IE") > -1 
const wasResized = resize > 0
if ( isMacOs && isIEBrowser && wasInitialized() && wasResized ) {
  // 기능 코드  
}

임시변수 분리(Split Temporary Variable)

루프 변수나 값 누적용 임시변수가 아닌 임시변수에 여러 번 값이 대입될

// Before
let temp = 2 * (_height + _width)
console.log(temp)
temp = _height * _width
console.log(temp)

// After
const perimeter = 2 * (_height + _width)
console.log(perimeter)
const area = _height * _width
console.log(area) 

매개변수로의 값 대입 제거(Remove Assignments to Parameters)

매개변수로 값을 대입하는 코드가 있을 때

// Before
const discount = (inputVal, quantity, yearToDate) => {
  if (inputVal > 50) {
    inputVal -= 2
  }
}

// After
const discount = (inputVal, quantity, yearToDate) => {
  let result = inputVal
  if (inputVal > 50) {
    result -= 2
  }
}

메서드를 메서드 객체로 전환(Replace Method with Method Object)

지역변수 때문에 메서드 추출을 적용할 수 없는 긴 메서드가 있을 때

그 메서드 자체를 객체로 전환해서 모든 지역변수를 객체의 필드로 만들자. 그런 다음 그 메서드를 객체 안의 여러 메서드로 쪼개면 된다.

// Before
class Account {
  gamma (inputVal, quantity, yearToDate) {
    const val1 = (inputVal * quantity) + delta()
    let val2 = (inputVal * yearToDate) + 100
    if ( (yearToDate - val1) > 100) {
      val2 -= 20
    }
    const val3 = val2 * 7
    
    return val3 - 2 * val1
  }
}

// After
class Gamma {
  constructor (source, inputVal, quantity, yearToDate) {
    this.source = source
    this.inputVal = inputVal
    this.quantity = quantity
    this.yearToDate = yearToDate
  }
  compute () {
    const val1 = (this.inputVal * this.quantity) + this.source.delta()
    let val2 = (this.inputVal * this.yearToDate) + 100
    if ( (this.yearToDate - val1) > 100) {
      val2 -= 20
    }
    const val3 = val2 * 7
    
    return val3 - 2 * val1
  }
}

class Account {
  gamma (inputVal, quantity, yearToDate) {
    return new Gamma(this, inputVal, quantity, yearToDate).compute()
  }
}

알고리즘 전환(Substitute Algorithm)

알고리즘을 더 분명한 것으로 교체해야 할 때

// Before
const foundPerson = (people) => {
  for (let i = 0; i < people.length; i++) {
    if (people[i] === 'Don') {
      return 'Don'
    }
    if (people[i] === 'John') {
      return 'John'
    }
    if (people[i] === 'Kent') {
      return 'Kent'
    }
  }
  return ''
}

// After
const foundPerson = (people) => {
  const candidates = ['Don', 'John', 'Kent']
  for (let i = 0; i < people.length; i++) {
    if (candidates.contains(people[i])) {
      return people[i]
    }
  }
  return ''
}