오류 처리

문지은·2021년 10월 12일
0

clean code

목록 보기
7/10

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

오류 코드를 사용하면 함수를 호출한 즉시 오류를 확인해야 한다.
예외를 사용해서 논리와 오류 처리 코드를 분리하자.

// 오류 코드를 사용한 코드
if (handle != DeviceHandle.INVALID) {
  // 비즈니스 로직
}
else {
  logger.log("Invalid handle for: " + DEV1.toString())
}

// 예외를 사용한 코드
public void sendShutDown() {
  try{
    tryToShutDown();    // 비즈니스 로직
  } catch (DeviceShutDownError e) {
    logger.log(e);    // 예외
  }
}

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

범위를 정의한다.
try안에서 생긴 일과 무관하게 catch에서 프로그램을 일관되게 유지해야 한다는 점에서 트랜잭션과 비슷.

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

확인된 예외는 OCP를 위반한다.

만약 최하위 함수를 변경해 새로운 오류를 던진다고 가정해보자. 그러면 상위 함수에서 catch 블록에서 새로운 오류 처리 or throw 절 추가해야 한다. -> 캡슐화 깨진다.

예외에 의미를 제공하라

오류 메세지에 정보를 담아 던진다. -> 오류가 발생한 원인과 위치를 찾기 쉬워진다.

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

오류를 정의할 때 가장 중요한 것 : 오류를 잡아내는 방법

//오류를 형편없이 분류한 사례
ACMEPort port = new ACMEPort(12);

try {
  port.open();
} catch (DeviceResponseException e) {
  reportPortError(e);
  logger.log("Device response exception: ", e);
} catch (ATM1212UnlockedException e) {
  reportPortError(e);
  logger.log("unlocked exception: ", e);
}...

// 예외 대응 방식이 동일하므로 호출하는 라이브러리 API를 감싸서 예외 유형 하나를 반환
LocalPort port = new LocalPort(12);

try {
  port.open();
} catch (PortDeviceFailuer e) {
  reportError(e);
  logger.log(e.getMessage(), e);
}

// wrapper 클래스 이용
public class LocalPort {
  private ACMEPort innerPort;

  public LocalPort(int portNumber) {
    innerPort = new ACMEPort(portNumber);
  }
  ...
}

wrapper 클래스를 이용했을 때 장점
1. 외부 라이브러리와 프로그램 사이의 의존성이 크게 줄어든다.
2. 테스트할 때 외부 API를 호출하지 않고 테스트 코드를 집어넣어서 테스트할 수 있다.
3. 특정 업체가 API를 설계한 방식에 발목 잡히지 않는다.

정상 흐름을 정의하라

외부 API를 감싸서 독자적인 예외를 던지고 그 위에 처리기를 정의해 중단된 계산을 처리하는 방식이 적합하지 않을 때도 있다.

// 위의 말한 방식대로 코드 작성했을 때
try {
  MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
  m_total += expenses.getTotal();
} catch (MealExpensesNotFound e) {
  m_total += getMealPerDiem();
}

// 특수 사례 패턴 이용
MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
m_total += expenses.getTotal();

// expenseReportDAO가 항상 MealExpenses를 반환하도록 수정

null을 반환하지 마라

null을 반환하는 행위는 일거리를 늘리고 호출자에게 문제를 떠넘긴다. null 반환하는 대신에 예외를 던지거나 특수 사례 객체를 반환하는 방식을 지향하자.

List<Employee> employees = getEmployees();
if (employees != null) {
  for (Employee e : employees) {
    totalPay += e.getPay();
  }
}

// 빈 list를 반환하도록 수정
List<Employee> employees = getEmployees();
for (Employee e : employees) {
  totalPay += e.getPay();
}

public List<Employee> getEmployees() {
  if (직원이 없다면)
    return Collections.emptyList();
}

null을 전달하지 마라

위와 같은 이유로 null을 다른 메서드로 전달하지 말고 예외를 던지자.

profile
백엔드 개발자입니다.

0개의 댓글