[클린코드] 7장. 오류 처리

June·2021년 11월 30일
0

[클린코드]

목록 보기
6/15

오류 코드보다 예외를 사용하라

오류가 발생하면 예외를 던지는 편이 낫다. 그러면 호출자 코드가 더 깔끔해진다. 논리가 오류 처리 코드와 뒤섞이지 않으니까.

Try-Catch-Finally 문부터 작성하라

예외가 발생할 코드를 짤 때는 try-catch-finally 문으로 시작하는 편이 낫다. 그러면 try 블로그에서 무슨 일이 생기든지 호출자가 기대하는 상태를 정의하기 쉬워진다.

먼저 강제로 예외를 일으키는 테스트 케이스를 작성한 후 테스트를 통과하게 코드를 작성하는 방법을 권장하낟. 그러면 자연스럽게 try 블록의 트랜잭션 범위부터 구현하게 되므로 범위 내에서 트랜잭션 본질을 유지하기 쉬워진다.

미확인(unchecked) 예외를 사용하라

checked exception은 OCP를 위반한다. 메서드에서 checked exception을 던졌는데 catch 블록이 세 단계 위에 있다면 그 사이 메서드 모두가 선언분에 해당 예외를 정의해야 한다. 즉, 하위 단계에서 코드를 변경하면 사우이 단계 메서드 선언부를 전부 고쳐야 한다는 말이다.

오류를 원거리에서 처리하기 위해 예외를 사용한다는 사실을 감안하면 checked exception이 캡슐화를 깨버리는 현상은 좋지않다.

때로는 checked exception이 유용하다. 아주 중요한 라이브러리를 작성한다면 모든 예외를 잡아야한다. 하지만 일반적인 애플리케이션은 의존성이라는 비용이 이익보다 크다.

예외에 의미를 제공하라

호출자를 고려해 예외 클래스를 정의하라

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 (GMXError e) {
            throw new PortDeviceFailure(e);
        }
    }
    ...
}

LocalPort 클래스처럼 ACMEPort를 감싸는 클래스는 매우 유용하다. 실제로 외부 API를 사용할 때는 감싸기 기법이 최선이다. 외부 API를 감싸면 외부 라이브러리와 프로그램 사이에서 의존성이 크게 줄어든다.

정상 흐름을 정의하라

다음은 비용 청구 애플리케이션에서 총계를 계산하는 허술한 코드다.

try {
    MealExpenses expenses = expenseReportDao.getMeals(employee.getId());
    m_total += expenses.getTotal();
} catch (MealExpensesNorFound e) {
    m_total += getMealPerDiem();
}

식비를 비용으로 청구했다면 직원이 청구한 식비를 총계에 더한다. 식비를 비용으로 청구하지 않았다면 일일 기본 식비를 총계에 더한다. 예외가 논리를 따라가기 어렵게 만든다.

MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
m_total += expenses.getTotal();

ExpenseReportDao를 고쳐서 언제나 MealExpense 객체를 반환한다. 청구한 식비가 없다면 일일 기본 식비를 반환하는 MealExpense 객체를 반환한다. 이를 특수 사례 패턴이라 부른다. 클래스를 만들거나 객체를 조작해 특수 사례를 처리하는 방식이다.

null을 반환하지마라

null을 반환하는 코드는 일거리를 늘리고 호출자에게 문제를 떠넘긴다.
Collections.emptyList() 같은 것을 넘기면 된다.

null을 전달하지마라

애초에 null을 넘기지 못하도록 금지하는 정책이 합리적이다.

0개의 댓글