-
리팩터링 - Guard Clause를 사용하여 코드 가독성 높히기JS & TS 2022. 9. 13. 22:52
리팩터링이란 소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법이다 - 리팩터링 2판, 마틴 파울러
수많은 리팩터링 방법 중 하나인 Guard Clause에 대해 소개합니다. Guard Clause는 무엇일까요?
A guard clause is simply a check that immediately exits the function, either with a return statement or an exception.
Guard Clause 는 반환 문이나 예외를 포함하여 함수를 즉시 종료하는 단순한 검사와 같은 문법입니다.
아래의 코드를 보겠습니다.
export function payAmount(employee) { let result; if (employee.isSeparated) { result = { amount: 0, reasonCode: "SEP" }; } else { if (employee.isRetired) { result = { amount: 0, reasonCode: "RET" }; } else { result = someFinalComputation(); return result; } } return result; }
payAmount 라는 함수에 파라미터로 employee 객체를 전달합니다. employee 내부에 뭐가 들었는지는 모르지만, isSeparated, isRetired 와 같은 내부 속성에 의해 if - else 문을 복잡하게 반복합니다.
코드를 짜는 본인의 경우에는 알아볼 수 있지만 며칠만 지나도 쉽게 헷갈리게 되고 다른 사람들이 봤을 때 유지보수의 어려움을 느끼게 될 것입니다.
result 라는 임시 변수를 선언하고 각 조건에 따라 result 변수에 값을 할당한 뒤 마지막에 result 를 리턴합니다. 임시 변수를 무조건 사용하자라고는 말할 수 없지만, 코드의 임시 변수가 많아질수록 가독성이 떨어지게 됩니다.
이와 같은 코드 흐름을 Guard Cluase 를 사용하면 어떻게 될까요?
export function payAmount(employee) { if (employee.isSeparated) { return { amount: 0, reasonCode: "SEP" }; } if (employee.isRetired) { return { amount: 0, reasonCode: "RET" }; } return someFinalComputation(); }
임시 변수를 사용하지 않고 각 조건에 따라 바로 리턴을 해줍니다. if else 문 또는 if else 문 내부에서 중첩된 if else 문을 사용하지 않고, 같은 스코프에서 조건에 따라 바로 반환하기 때문에 복잡하지 않고 가독성이 높아졌습니다.
Guard Clause 를 사용한 다른 예제 코드를 첨부해 두겠습니다.
리팩터링 이전
export function adjustedCapital(instrument) { let result = 0; if (instrument.capital > 0) { if (instrument.interestRate > 0 && instrument.duration > 0) { result = (instrument.income / instrument.duration) * anInstrument.adjustmentFactor; } } return result; }
리팩터링 이후
export function adjustedCapital(instrument) { function isEligibleForAdjustedCapital(instrument) { return ( instrument.capital > 0 && instrument.interestRate > 0 && instrument.duration > 0 ); } if (!isEligibleForAdjustedCapital(instrument)) { return 0; } return ( (instrument.income / instrument.duration) * anInstrument.adjustmentFactor ); }
리팩터링 이전
const onLogin = useCallback(async () => { if (isModerator) { if (deviceSelected.audioInput !== DEVICE_DISABLE) { setSituation(info, ROLE.MODERATOR_ROLE, STATUS.STAGE); return; } else { setSituation(info, ROLE.MODERATOR_ROLE, STATUS.BACKSTAGE); return; } } else { setSituation(info, ROLE.AUDIENCE_ROLE, STATUS.AUDIENCE); return; } }, [deviceSelected, info, isModerator, RTM_join, setSituation]);
리팩터링 이후
const onLogin = useCallback(async () => { if (isModerator && deviceSelected.audioInput !== DEVICE_DISABLE) { setSituation(info, ROLE.MODERATOR_ROLE, STATUS.STAGE); return; } if (isModerator && deviceSelected.audioInput === DEVICE_DISABLE) { setSituation(info, ROLE.MODERATOR_ROLE, STATUS.BACKSTAGE); return; } setSituation(info, ROLE.AUDIENCE_ROLE, STATUS.AUDIENCE); return; }, [deviceSelected, info, isModerator, RTM_join, setSituation]);
레퍼런스
https://deviq.com/design-patterns/guard-clause
book_study_storage/README.md at master · junh0328/book_study_storage
'JS & TS' 카테고리의 다른 글
iframe communication quick start (0) 2023.02.24 REST API 바로 알기 (0) 2022.10.23 프로미스(Promise) 바로 알기 (0) 2022.10.22 이벤트 루프 동작 원리 (0) 2022.10.20 모바일 기기를 체크하여 크로스 브라우징 지원하기 (navigator.userAgent 사용하기) (0) 2022.08.25