조건문 분해하기
// before
if (!aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd)) {
charge = quantity * plan.summerRate;
}
else {
charge = quantity * plan.regularRate + plan.regularServiceCharge;
}
// after
if (summer()) {
charge = summerCharge();
}
else {
charge = regularCharge();
}
- 복잡한 조건문은 코드를 어렵게 만드는 원흉이다.
- 코드를 부위별로 분해한 다음 코드 덩어리들을 의도를 살린 이름의 함수 호출로 바꿈
조건식 통합하기
// before
if (someExp1) return 0;
if (someExp2) return 0;
if (someExp3) return 0;
// after
if (someFunc()) return 0;
function someFunc() {
return (someExp1 || someExp2 || someExp3);
}
- 조건은 다르나 결과가 같은 여러 조건문이 있을 때 조건 검사 함수를 만들어 하나로 통합한다.
중첩 조건문을 보호 구문으로 바꾸기
// before
function getPayAmount() {
let result;
if (isDead) {
result = deadAmount();
}
else {
if (isSeperated) {
result = separatedAmount();
}
else {
if (isRetired) {
result = retiredAmount();
}
else {
result = normalAmount();
}
}
}
return result;
}
// after
function getPayAmount() {
if (isDead) return deadAmount();
if (isSeperated) return separatedAmount();
if (isRetired) return retiredAmount();
return normalAmount();
}
- 조건문이 주로 쓰이는 두 가지 형태
- 참, 거짓 경로 모두 정상 동작일 때
- 한쪽만 정상인 형태 (보호 구문)
- 한쪽만 정상인 경우, 비정상 조건을 if에서 검사하고 참이면 바로 리턴하는 방식으로 구현하는게 가독성이 좋음
조건부 로직을 다형성으로 바꾸기
// before
switch (bird.type) {
case '유럽 제비':
return "보통이다";
case '아프리카 제비':
return "지쳤다";
case '노르웨이 파랑 앵무':
return "그을렸다";
default:
return "알 수 없다";
}
// after
class Bird {
get plumage() {
return "알 수 없다";
}
}
class EuropeanSwallow extends Bird {
get plumage() {
return "보통이다";
}
}
class AfricanSwallow extends Bird {
get plumage() {
return "지쳤다";
}
}
class NorwegianBlueParrot extends Bird {
get plumage() {
return "그을렸다";
}
}
- 다형성을 이용하여 복잡한 switch 문을 처리할 수 있다.
- Bird bird = new EuropeanSwallow() 와 같이 사용하여 동작을 처리할 수 있다.
- 자바의 경우 추상 클래스, 인터페이스를 이용해서 더 유연하게 가능
- 무조건 모든 if 나 switch에 다형성을 적용하라는 것은 아니고, 복잡하거나 매우 자주 나타날 때 이렇게 할 수도 있다는 참고로써 사용
특이 케이스 추가하기
// before
if (customer === "미확인 고객") customerName = "거주자";
// after
class UnknownCustomer {
get name() {return "거주자";}
}
- 특정 값에 대해 똑같은 동작을 수행하는 코드가 여러 곳이라면 이를 한 곳에 모으는 게 좋다.
- 특이 케이스는 클래스로 만들 수도 있고, 리터럴 객체 형태로 준비할 수도 있다.
- 솔직히 잘 모르겠다..이렇게까지 해야하나? 걍 함수로 빼놓는 정도면 될 거 같긴 한데
어서션 추가하기
// before
if (this.discountRate) {
base = base - (this.discountRate * base);
}
// after
assert(this.discountRate >= 0);
if (this.discountRate) {
base = base - (this.discountRate * base);
}
- 특정 조건이 참일 때만 제대로 동작하는 코드가 있을 수 있음
- 제곱근 계산은 입력이 양수일때만 제대로 동작
- 객체 필드 중 최소 하나에는 값이 들어있어야 동작하는 경우
- 어서션을 코드에 추가하면 주석을 굳이 달지 않아도 쉽게 알 수 있다.
- 어서션 : 항상 참이라고 가정하는 조건부 문장
- 어서션이 들어간다고 해서 동작이 달라지지는 않는다.
제어 플래그를 탈출문으로 바꾸기
// before
for (const p of people) {
if (!found) {
if (p === "조커") {
sendAlert();
found = true;
}
}
}
// after
for (const p of people) {
if (p === "조커") {
sendAlert();
break;
}
}
- 플래그는 거의 좋을 때가 없다. 그냥 쓰지 말자.
- 반복문의 경우 break, continue 등을 쓰는게 낫고, 함수의 경우에는 그냥 조건이 되면 바로 return 하는 것도 방법이다.
https://product.kyobobook.co.kr/detail/S000001810241