오류처리(예외처리) 관련 파트이다
요즘 기존에 했던 프로젝트 복습?하면서 react의 Suspense 관련 글을 보고 있는데 Suspense가 좋은 이유가
'로직'과 '에러' 처리 부분을 나눌 수 있어서 좋은 코드를 만들 수 있다고 한다.
Suspense에 관련해서 더욱 흥미로운 내용도 더 많은데 이건 따로 글을 하나 파서 조만간 써봐야겠다.
오류 처리
오류 처리는 매우 중요하다.
소프트웨어는 복잡계이고 사람이 작성하다보면 뭔가 빼먹은게 있을 수 있다. 버그는 거의 필연적으로 일어나기 때문에
오류 처리를 우아하게? 해내는것도 중요하다.
오류 코드보다는 예외를 사용하자
if문으로도 오류 처리를 할 수 있지만 그렇게 되면 '로직' 과 오류 처리 코드를 혼동하기 쉽다.
역할을 분리하자
try-catch-finally 문을 애용하자
예외처리 부분은 try 부분에 넣고, 꼭 실행되야 하고 오류나 예외처리 부분이 절대로 일어나지 않는다고 가정되는 부분은 finally 부분에 넣는다.
미확인 예외를 사용해라
자바스크립트의 경우 거의 반강제(?)로 미확인 예외를 사용하지만...
자바의 경우 기본 Exception이 있고 Exception을 상속받아 온갖 종류의 Exception이 있는것으로 알고 있다.
확인 예외(구체화된 Exception 종류)는 명확하지만
에러를 여러단계를 거쳐 throw 받는경우 콜백의 상위 함수에서는 그 오류에 알맞은 Exception handling을 해줘야한다. 이것은 OCP(Open Closed Principle) 를 위반한다.
즉, 하위 단계에서 코드를 고치면 상위 단계 메서드 선언부를 전부 고쳐야한다.
일반적으로 애플리케이션은 의존성이라는 비용이 이득보다 크니 미확인 예외를 사용하자.
예외에 의미를 제공하자
예외를 던질때는 전후 맥락을 짚을 수 있는 단서를 제공한다. 그럼 오류의 원인과 위치를 찾기 수월해진다.
오류 메세지에 정보를 담아 예외를 던지자.
* 다만 production 코드에서 오류 hint를 주는것은 보안 문제가 발생할 수 있으니 주의?
호출자를 고려해 예외 클래스를 정의하자
오류를 정의시 프로그래머의 가장 중요한 관심사는 '오류를 잡아내는 방법'
외부 API를 사용 시 감싸기 방식(wrapper)이 최선
public class LocalPort {
private ACMEPort innerPort;
public LocalPort(int portNumber) {
innerPort = new ACMEPort(portNumber);
}
public void open() {
try {
innerPort.open();
} catch (DeviceResponseException e) {
throw new PortDeviceFailure(e);
} catch (ATM1212UnlockedException e) {
throw new PortDeviceFailure(e);
} catch (GMXEError e) {
throw new PortDeviceFailure(e);
}
}
}
LocalPort는 단순한 wrapper class이다.
외부 API를 감싸면
1. 외부 라이브러리와 프로그램 사이에서 의존성이 크게 줄어든다.
2. 다른 라이브러리로 갈아타기 쉬워진다.
3. 테스트 할때 API대신 테스트 코드를 넣어주는 방식으로 테스트하기 쉬워진다.
정상 흐름 정의
'비즈니스 로직'와 '오류 처리'가 잘 분리된 코드가 좋은 코드
클라이언트 코드가 특수 상황을 처리할 필요가 없게 하자.
특수 상황이란 논리와 예외처리를 뒤섞어 막 사용하는 경우를 뜻한다
예를 들어
try {
MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
m_total += expenses.getTotal();
} catch (MealExpensesNotFound e) {
m_total += getMealPerDiem();
}
해당 코드는 직원이 식비를 청구했으면 expense.getTotal() 함수로 식비 청구한 만큼 값을 계산하고
청구하지 않았다면 예외처리를 일으켜서 catch문에서 기본 식비를 계산하는 상황이다.
이런경우엔 '비즈니스 로직'으로만 처리해야 좋은 코드이니 주의하자.
(* 해당 로직을 올바르게 구현한 객체를 MealExpense 객체로 반환해서 처리하는것을 특수 사례 패턴이라 부른다, 즉 클래스를 만들거나 객체를 조작해 특수 사례를 처리하는 방식)
null을 반환하지 말자
만약 메소드가 제대로 처리 안되었다는 뜻으로 가끔 null을 반환할때도 있는데
그 대신 예외를 던지거나 특수 사례 객체를 반환한다.
TS를 쓰면 그나마 양반인데 JS에서 null을 반환하는 순간 스스로 지옥을 만들수도 있을꺼 같다ㅋㅋ
null을 반환하는 대신 빈 리스트를 반환한다면 훨씬 깔끔하다.
외부 API가 null 반환시 감싸기 메서드를 구현해 예외를 던진다.
null을 전달하지 말자
(oauth2 passport 에서 하던거 같던데??)
null을 반환하는거보다 치명적
null을 기대하는 메서드가 아니라면 null을 전달하지말자
assert 문으로 null 예외처리를 한다.
js의 경운 assert 없으니 이런식으로 구현..?
function assert(condition, message) {
if (!condition) {
throw new Error(message || "Assertion failed");
}
}
https://stackoverflow.com/questions/15313418/what-is-assert-in-javascript
결론
깨끗한 코드란 가독성뿐만 아니라 안정성도 높아야 한다.
오류 처리와 논리를 분리하면 튼튼하고 깨끗한 코드를 작성 가능, 유지보수성도 크게 높아짐
toss 컨퍼런스의 suspense에 대한 내용도 비슷한 내용을 담고 있으니 한번 보는거도 추천한다
'독서 > cleancode' 카테고리의 다른 글
cleancode - unit test (0) | 2022.01.25 |
---|---|
clean code - 경계 (0) | 2022.01.24 |
cleancode - 객체와 자료구조 (0) | 2022.01.21 |
clean code - 주석 & 형식 맞추기 (0) | 2022.01.20 |
clean code - 함수 (0) | 2022.01.19 |