프런트엔드/리팩터링

레거시 코드 리팩터링 시리즈(4/5) 조건문

조드래곤나인 2023. 7. 17. 18:25

 

 

조건문

동일한 값을 비교할 경우

if/else로 작성되면 에러코드에 따른 동작을 파악하기 위해

시선이 Z형태(errorCode -> 211 -> navigate)로 이동되어

한번에 읽기 어렵게 한다.

if (errorCode === 211) {
  navigate('/signup')
} else if (errorCode === 208) {
  navigate('/user/registration')
} else if (errorCode === 202) {
  navigate('/home')
} else if (errorCode === 212 || errorCode === 213) {
  navigate('/signup')
} else {
  navigate('/login')
}
 

switch/case로 작성되면 에러코드와 동작이 수직으로 위치하여 시선이 수직으로 이동되어 읽기 쉽게 만든다. 그리고 숫자를 작은 것부터 높은 순서로 작성하고 동일한 동작을 하는 코드는 같이 작성하였다.

switch (errorCode) {
  case 202: navigate('/home')
    break
  case 208: navigate('/user/registration')
    break
  case 211:
  case 212:
  case 213: navigate('/signup')
    break
  default: navigate('/login')
    break
}
 

 

다른 값을 비교할 경우

조건문에 다른 값들을 비교할 때이다. 결과에 따라 각자 다른 동작을 하고 있다. 일관성이 없기 때문에 읽기 어렵고 이해하기 쉽게 작성되어 있다.

if (error.httpStatus === 0) {
  openToast('알 수 없는 오류가 발생했습니다.')
} else if (error.response && error.response.name === 'TimeoutError') {
  openToast('타임아웃이 발생했습니다.')
} else if (error.code === 211) {
  navigate('/signup')
} else if (error.code === 208) {
  navigate('/user/registration')
} else {
  navigate('/login')
}
 

먼저 switch/case를 통해 책임연쇄패턴을 작성하여 조건문과 동작을 동일 시선으로 만들 수 있다.

switch (true) {
  case error.httpStatus === 0:
    openToast('알 수 없는 오류가 발생했습니다.')
    break
  case error.response && error.response.name === 'TimeoutError':
    openToast('타임아웃이 발생했습니다.')
    break
  case error.code === 211:
    navigate('/signup')
    break
  case error.code === 208:
    navigate('/user/registration')
    break
  default:
    navigate('/login')
    break
}
 

그리고 마지막으로 조건문을 함수로 만들면 일관성있는 코드가 작성되어 이해하기 쉽게 한다.

const isUnknownError = error => error.httpStatus === 0
const isTimeoutError = error => error.response && error.response.name === 'TimeoutError'
const isUnregist = error => error.code === 211
const isUnauth = error => error.code === 208

switch (true) {
  case isUnknownError(error):
    openToast('알 수 없는 오류가 발생했습니다.')
    break
  case isTimeoutError(error):
    openToast('타임아웃이 발생했습니다.')
    break
  case isUnregist(error):
    navigate('/user/registration')
    break
  case isUnauth(error):
    navigate('/signin')
    break
  default:
    navigate('/login')
    break
}
 

 

특정 값이 존재할 때 할당하는 경우

응답에러와 응답메시지가 있을 때 메시지변수에 할당을 하고, 둘다 없을 경우 공통 메시지를 할당하는 코드이다. 간단한 코드지만 메세지변수를 let으로 선언하여 변경가능성을 표현하였고, 시선이 한방향으로 흐르지 않고 있다.

let message
if (response.error) {
  message = response.error
} else if (response.message) {
  message = response.message
} else {
  message = COMMON_MESSAGE
}
 

OR를 통해 작성하면 참일 때 메세지변수에 할당하게 된다. 메세지변수의 불변으로 선언하였고, 시선이 한방향으로 흐르게 하였다.

const message = response.error || response.message || COMMON_MESSAGE
 

 

각 인자값 분기

Angular의 HttpParams를 사용하여 쿼리스트링을 만드는 함수이다. 인자의 존재 유무에 따라 파라미터의 추가가 결정된다. 다른 값이 사용되어 각 값마다 분기가 사용되어 로직이 중복된다.

const convertToParams = ({name, status, page, pageSize}) => {
  let params = new HttpParams()
  if (name) {
    params = params.append('name', name)
  }
  if (status) {
    params = params.append('status', String(status))
  }
  if (page) {
    params = params.append('page', String(page))
  }
  if (pageSize) {
    params = params.append('size', String(pageSize))
  }
  return params
}
 

결국 이 함수는 여러개의 값을 모아 하나의 값을 만드는 작업을 한다. 이때 reduce를 사용하면 params과 중복된 로직을 삭제할 수 있다.

const convertToParams = ({botName, status, page, pageSize}) => {
  return [
    ['botName', botName],
    ['status', status],
    ['page', page],
    ['size', pageSize],
  ].reduce((params, [key, value]) => {
    if (value) {
      params = params.append(key, String(value))
    }
    return params
  }, new HttpParams())
}
 

이 코드에서도 개선 사항이 있다. 파라미터를 배열로 선언해야 하고, reduce 내부의 작업이 많다. 각 역할에 맞게 선언형 함수를 사용하면 좀 더 개선 가능하다.

const convertToParams = ({botName, status, page, pageSize: size}) => {
  return Object
    .entries({botName, status, page, size})
    .filter(([key, value]) => value)
    .map(([key, value]) => [key, String(value)])
    .reduce((params, [key, value]) => {
      return params.append(key, String(value))
    }, new HttpParams())
}
 

 

 


 

 

728x90