제목을 뭐로 지어야 할까? 2

박정훈·2023년 3월 13일
0

Java Script

목록 보기
7/8

if else 리팩토링
리팩토링 관련 영상이다. 해당 영상을 참고해 실제로 회사에서의 reducer코드를 개선했다. 기타 다른 코드도 객체나 Map으로 개선시키는 등 실제로 유익한 팁이었다.

if문 개선하기

소셜로그인

조건에 따른 소셜로그인이다.

const naverLogin = (id) => {
    // ~~
    return "naver"
}

const kakaoLogin = (id) => {
    // ~~
    return "kakao"
}

const facebookLogin = (id) => {
    // ~~
    return "facebook"
}

const googleLogin = (id) => {
    // ~~
    return "google"
}

const socialLogin = (where, id) => {
    let domain;
    if(where === 'naver') {
        domain = naverLogin(id)
    } else if(where === 'kakao') {
        domain = kakaoLogin(id)
    } else if(where === 'facebook') {
        domain = facebookLogin(id)
    } else if(where === 'google') {
        domain = googleLogin(id)
    }
    return `${domain} ${id}`
}

console.log(socialLogin('naver', 'malza')) // naver malza
console.log(socialLogin('google', 'malza')) // google malza

if와 else if문은 switch로 대체 가능하다.

const socialLogin = (where, id) => {
  let domain;
  switch (where) {
	case 'naver':
	  domain = naverLogin(id)
	  break
	case 'kakao':
	  domain = kakaoLogin(id)
	  break
	case 'facebook':
	  domain = facebookLogin(id)
	  break
	case 'google':
	  domain = googleLogin(id)
	  break
  }    
  return `${domain} ${id}`
}

여기서 switch부분만 함수로 쏘옥 빼보자.

const excuteLogin = (where, id) => {
 switch (where) {
   case 'naver':
     return naverLogin(id)
   case 'kakao':
     return kakaoLogin(id)
   case 'facebook':
     return facebookLogin(id)
   case 'google':
     return googleLogin(id)
 }
}
const socialLogin = (where, id) => {
   const domain = excuteLogin(where, id);
   return `${domain} ${id}`
}

역시 잘 동작한다. 함수에 return만 남아있으니 이를 객체로 맵핑해보자!

const naverLogin = (id) => {
    // ~~
  return "naver"
}

const kakaoLogin = (id) => {
    // ~~
  return "kakao"
}

const facebookLogin = (id) => {
    // ~~
  return "facebook"
}

const googleLogin = (id) => {
    // ~~
  return "google"
}

const SocialLoginMap = {
  'naver': naverLogin,
  'kakao': kakaoLogin,
  'facebook': facebookLogin,
  'google': googleLogin,
}

const socialLogin = (where, id) => {
  const domain = SocialLoginMap[where](id);
  return `${domain} ${id}`
}

음~ 보기 좋다.

구간별 적용

const getSeason = month => {
  if(month >= 3 && month <= 5) return '봄'
  else if(month >= 6 && month <= 8) return '여름'
  else if(month >= 9 && month <= 11) return '가을'
  else if(month >= 12 || month <= 2) return '겨울'
}

역시 switch case문으로 바꿔보자.

const getSeason = month => {
  switch(month) {
    case 3:
    case 4:
    case 5:
      return '봄'
    case 6:
    case 7:
    case 8:
      return '여름'
    case 9:
    case 10:
    case 11:
      return '가을'
    case 12:
    case 1:
    case 2:
      return '겨울'
  }
}

12 다음 1,2가 나오는것도 그렇고, case가 3부터 시작하는것도 그렇고 불편하다. case를 0부터 시작하도로록 3을 빼면?
case 1, 2였던 친구들이 -2, -1이 되서 또 불편하다~😥 그래도 일단 0 ~ 9 까지 case문이 생성되겠다.

const getSeason = month => {
  const shiftedMonth = month - 3
  switch(shiftedMonth) {
    case 0:
    case 1:
    case 2:
      return '봄'
    case 3:
    case 4:
    case 5:
      return '여름'
    case 6:
    case 7:
    case 8:
      return '가을'
    case 9:
    case -2:
    case -1:
      return '겨울'
  }
}

-2와 -1 두 친구가 규칙에 맞게 10, 11이 세팅되면 참 좋겠다.

// 기존의 const shiftedMonth = month - 3 에서 변형
const getSeason = month => {
    const shiftedMonth = (month + 9) % 12
    switch(shiftedMonth) {
        case 0:
        case 1:
        case 2:
            return '봄'
        case 3:
        case 4:
        case 5:
            return '여름'
        case 6:
        case 7:
        case 8:
            return '가을'
        case 9:
        case 10:
        case 11:
            return '겨울'
    }
}

이제 shiftedMonth는 1월이 오면 10, 2월이 오면 11이 된다. 나머지 애들은 기존 그대로다!
여기서 또 규칙을 찾을 수 있다. 0~2는 3으로 나누면 몫이 0, 3~5는 1, 6~8은 2, 9~11은 3이 떨어진다.

const getSeason = month => {
    const shiftedMonth = Math.floor((month + 9) % 12 / 3) // 소수점 아래를 버리면 딱 떨어진다.
    switch(shiftedMonth) {
        case 0:
            return '봄'
        case 1:
            return '여름'
        case 2:
            return '가을'
        case 3:
            return '겨울'
    }
}

ohhhh my goddd! 이제 객체로 맵핑 해 보자.

const SeasonMap = {
  0: '봄',
  1: '여름',
  2: '가을',
  3: '겨울',
}

const getSeason = month => {
  const shiftedMonth = Math.floor((month + 9) % 12 / 3)
  return SeasonMap[shiftedMonth]
}

와우~ 잘 된다. 여기서 0,1,2,3 을 배열로 바꿔버리면

const seasons = ['봄','여름','가을','겨울']

const getSeason = month => seasons[Math.floor((month + 9) % 12 / 3)]

오마갓~ 가독성이 많이 올라갔다. 리팩토링에서 규칙을 찾는것이 중요해 보인다.

구간별 적용 2

0 미만 : 몹시 추워용
0 이상 10미만 : 추워용
10 이상 20미만 : 선선해용
20 이상 30미만 : 조금 더워용
30 이상 40미만 : 더워용
40 이상: 몹시 더워용

const getWeather = (temperature) => {
  if(temperature < 0) return '몹시 추워용'
  if(temperature < 10) return '추워용'
  if(temperature < 20) return '선선해용'
  if(temperature < 30) return '조금 더워용'
  if(temperature < 40) return '더워용'
  return '몹시 더워용'
}

역시 switch로 바꿔!

const getWeather = (temperature) => {
  const score = Math.floor(temperature / 10)
  switch (score) {
    case 0:
      return '추워요'
    case 1:
      return '선선해용'
    case 2:
      return '조금 더워용'
    case 3:
      return '더워용'
    default: {
      if(score < 0) return '몹시 추워요'
      return '몹시 더워요'
    }
  }
}

default가 매우 몹시 거슬리므로, 이 또한 규칙성을 찾는게 관건으로 보인다.

// 이렇게 바꾸고 싶다.
const getWeather = (temperature) => {
  const score = Math.floor(temperature / 10) // 이 부분을 건드려야겠다.
  switch (score) {
    case -1:
      return '몹시 추워요'
    case 0:
      return '추워요'
    case 1:
      return '선선해용'
    case 2:
      return '조금 더워용'
    case 3:
      return '더워용'
    case 4:
      return '몹시 더워용'
  }
}
Math.max(Math.floor(temperature / 10), -1)
// -55도를 10으로 나누면 -5.5고, 이를 floor하면 -6이다. 그리고 max를 구하면 -1이 나온다. -1보다 작으면 반드시 -1이 반환될것이다.
Math.min(Math.max(Math.floor(temperature / 10), -1), 4)
// 40도 이상이면 min으로 4와 비교한다.

즉, 0미만은 -1로 수렴하도록 강제하고, 4이상은 모두 4로 수렴한다. 자! 이제 또 객체로 바꿀수 있을것 같다.

const TemperatureMap = {      
    -1: '몹시 추워요',
    0: '추워요',
    1: '선선해용',
    2: '조금 더워용',
    3: '더워용',
    4: '몹시 더워용',
}

const getWeather = (temperature) => {
  return TemperatureMap[Math.min(Math.max(Math.floor(temperature / 10), -1), 4)]
} // -1 이 문제네~

아차차! -1때문에 에러를 뱉는다! 그냥 string 처리 해도 된다! 근데 난 0으로 바꾸고 싶어! 하면?

const TemperatureMap = {      
    0: '몹시 추워요',
    1: '추워요',
    2: '선선해용',
    3: '조금 더워용',
    4: '더워용',
    5: '몹시 더워용',
}

const getWeather = (temperature) => {
  return TemperatureMap[Math.min(Math.max(Math.ceil(temperature / 10), 0), 5)] // 0과 5로 수렴하게끔 한다.
}

역시 0~5 인덱스라면 배열로 가능하겠다.

const Temperatures = ['몹시 추워요', '추워요', '선선해용', '조금 더워용', '더워용', '몹시 더워용']
const getWeather = (temperature) => {
  return Temperatures[Math.min(Math.max(Math.ceil(temperature / 10), 0), 5)] // 0과 5로 수렴하게끔 한다.
}

이후는 마찬가지로 함수로 빼거나 arrow function의 특징인 return 제거같은것으로 더 줄일 수 있겠다.

reducer

switch case로 쓰여진 reducer를 프로젝트에서 객체 매핑으로 바꾼 결과다.

const reducerMap = {
  [GridContants.LAYOUT]: produce((state, { value }) => {
    state.layout = value;
  }),
  //...
  [GridContants.REMOVE_ITEM]: produce((state, { index }) => {
    state.layout.splice(index, 1);
  }),
  [GridContants.CHANGE_INFO]: produce((state, { title, fontSize, color, index }) => {
    state.layout[index].i = title;
    state.layout[index].fontSize = fontSize;
    state.layout[index].color = color;
  }),
};

export const GridReducer = (state, action) =>
  reducerMap[action.type]?.(state, action) || state;

보기 좋아진거 같은가? :)

profile
그냥 개인적으로 공부한 글들에 불과

0개의 댓글