클린 코드(Clean Code) - 7장 오류 처리

Muzi·2023년 1월 11일
0

Clean Code

목록 보기
7/14

오류 처리

오류 처리 코드로 인해 프로그램 논리를 이해하기 어려워진다면 깨끗한 코드라 부르기 어렵다

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

/*
* 함수를 호출한 즉시 오류를 확인하다보니 호출자 코드가 복잡해진다
* 오류 발생시 예외를 던지는 편이 낫다
*/
public class DeviceController {
  ...
  public void sendShutDown() {
    DeviceHandle handle = getHandle(DEV1);
    // 디바이스 상태를 점검한댜.
    if (handle != DeviceHandle.INVALID) {
      // 레코드 필드에 디바이스 상태를 저장한다.
      retrieveDeviceRecord(handle);
      // 디바이스가 일시정지 상태가 아니라면 종료한다.
      if (record.getStatus() != DEVICE_SUSPENDED) {
        pauseDevice(handle);
        clearDeviceWorkQueue(handle);
        closeDevice(handle);
      } else {
        logger.log("Device suspended. Unable to shut down");
      }
    } else {
      logger.log("Invalid handle for: " + DEV1.toString());
    }
  }
  ...
}

// after
public class DeviceController {
  ...
  public void sendShutDown() {
    try {
      tryToShutDown();
    } catch (DeviceShutDownError e) {
      logger.log(e);
    }
  }
  
  private void tryToShutDown() throws DeviceShutDownError {
    DeviceHandle handle = getHandle(DEV1);
    DeviceRecord record = retrieveDeviceRecord(handle);
    pauseDevice(handle); 
    clearDeviceWorkQueue(handle); 
    closeDevice(handle);
  }
  
  private DeviceHandle getHandle(DeviceID id) {
    ...
    throw new DeviceShutDownError("Invalid handle for: " + id.toString());
    ...
  }
  ...
}

2. try-catch-finally부터 작성하라

  • 예외가 발생하는 코드를 짤 때는 try-cath-finally 문으로 시작하는 편이 좋다
  • 먼저 강제로 예외를 일으키는 테스트 케이스를 작성한 후 테스트를 통과하게 코드를 작성하는 방법을 권장 -> 호출자가 기대한 상태를 정의하기 쉬워지기 때문

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

  • Unchecked 예외는 실행 단계에서 확인되며 명시적인 처리를 강제하지는 않는 예외
  • checked 예외는 컴파일 단계에서 확인되며 반드시 처리해야하는 예외

4. 예외의 의미를 제공하라

예외를 던질 때 전후 상황을 충분히 덧붙힌다 ex) 실패한 연산이름, 실패유형

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

오류를 정의할 때 프로그래머에게 가장 중요한 관심사는 오류를 잡아내는 방법이 되어야 한다

// before
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("Unlock exception", e);
 } catch (GMXError e) {
  reportPortError(e);
  logger.log("Device response exception");
 } finally {
   ...
 }

/*
* 호출 라이브러리 api를 감싸 한 가지 예외 유형을 반환하는 방식
* 예외처리가 간결해짐
* 외부 라이브러리와 프로그램 사이의 의존성이 크게 줄어든다
*/
LocalPort port = new LocalPort(12);

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

 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);
    }
  }
  ...
}
profile
좋아하는걸 열심히

0개의 댓글