소트웍스 앤솔로지의 Object Calisthenics 내용을 TypeScript로 적용해봤습니다.
대부분의 프로그래밍 언어는 if
/else
구문을 지원한다. 하지만 조건문이 중첩될수록 가독성은 떨어지기 마련이다. else if
를 넣어 조건문의 분기를 추가하는 것은 코드를 리팩토링하는 것보다 훨씬 쉽지만 이는 가독성이 떨어지고 유지보수하기 어려운 코드를 만들어내곤 한다.
else
가 있는 다음 코드를 살펴보자.
const login = (username: string, password: string) => {
if (userRepository.isValid(username, password)) {
redirect('homepage');
} else {
addFlash('ERROR', '잘못된 인증 정보입니다.');
redirect('login');
}
};
이런 경우 else
구문을 쉽게 없애는 방법은 early return 기법을 적용하는 것이다.
const login = (username: string, password: string) => {
if (userRepository.isValid(username, password)) {
return redirect('homepage');
}
addFlash('ERROR', '잘못된 인증 정보입니다.');
return redirect('login');
};
이제 예외처리를 하는 경우와 기본값으로 실행되어야 하는 경우에 대해 생각해보자.
어려운 말이 아니고 말 그대로 예외를 위에서 처리하는 것이다. 위에 제시된 코드의 경우 isValid
하면 redirect("homepage")
하고 그 외의 예외의 경우 addFlash
와 redirect("login")
를 실행하게 된다.
const login = (username: string, password: string) => {
if (!userRepository.isValid(username, password)) {
addFlash('ERROR', '잘못된 인증 정보입니다.');
return redirect('login');
}
return redirect('homepage');
};
또는 return
이 싫거나 함수의 반복(이 경우 redirect
)을 줄이고 싶을 경우 이런 방법도 가능하다.
const login = (username: string, password: string) => {
let redirectRoute = 'homepage'
if (!userRepository.isValid(username, password)) {
addFlash('ERROR', '잘못된 인증 정보입니다.');
redirectRoute = 'login';
}
redirect(redirectRoute);
};
필자의 경우는 early return을 하는 방어적 프로그래밍의 방식을 선호한다. 순서만 바뀌었을뿐이지만, 개인적으로 예외상황을 먼저 처리한다면
null
이나undefined
를 처리할 때TypeError
를 잡기도 용이하고 기본 로직을 확장하기 좋다고 생각한다.
객체지향 프로그래밍의 다형성을 활용한 상태 패턴과 전략 패턴을 사용하는 방법도 있다. 이런 패턴들을 사용한다면 상태(Unauthorized
, Authorized
)에 따라 수행되는 로직(next
)을 캡슐화 할 수 있고, 코드를 수직이 아닌 수평적으로 확장할 수 있다. ~~사실 적당한 예시인지 모르겠지만~~ 주요 디자인 패턴을 다룰 때 살펴보도록 하자.
interface RedirectStatus {
next: () => void;
}
class Authorized implements RedirectStatus {
next() {
return redirect('homepage');
}
}
class Unauthorized implements RedirectStatus {
next() {
addFlash('ERROR', '잘못된 인증 정보입니다.');
return redirect('login');
}
}
class Page {
constructor(private status: RedirectStatus = new Authorized()) {}
setStatus(status: RedirectStatus) {
this.status = status;
}
handleNext() {
return this.status.next();
}
}
const page: Page = new Page();
const login = (username: string, password: string) => {
if (!userRepository.isValid(username, password)) {
page.setStatus(new Unauthorized());
}
page.handleNext();
};
else를 쓰면 조건문 안에서 실수로 return을 빼먹어도 안전하게 코드가 실행되는 장점이 있다고 생각합니다.
그럼에도 early return이 더 젠틀하다고 생각하시는지 궁금합니다!