ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 클린 코드 - 오류 처리
    클린 코드(Clean Code) 2022. 2. 15. 00:01
    728x90

    입력이 이상하거나 디바이스가 실패할지도 모르기 때문에 오류 처리는 프로그램에 필수적인 요소입니다.

    여기저기 흩어진 오류 처리 코드는 실제 코드가 하는 일을 파악하기 어렵게 만들기 때문에 오류 처리는 중요합니다.

     

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

     

    오류 플래그를 사용한 경우 = 예외를 사용하지 않음

    if(!Error1){
    	doSomething1();
    	if(!Error2){
    		doSomething2();
    	} else {
    		logger.log("Error2 발생");
    	}
    } else{
    	logger.log("Error1 발생");
    }

     

    예외를 사용하는 경우

    try{
    	doSomething1();
    } catch (Exception e){
    	logger.log(e);
    }
    
    try{
    	doSomething2();
    } catch (Exception e){
    	logger.log(e);
    }

    메서드들을 분리하여 처리하게 때문에 각 개념을 독립적으로 살펴보고 이해하기가 편해집니다.

     

    2. 미확인 예외(Unchecked Exception)를 활용하자

    확인된 예외(checked exception)란?

    - 예외처리를 구현하지 않으면 컴파일 에러가 발생한다.(파일 열기와 같은 코드를 구현했지만, 파일이 없는 상황이 있을 수 있기 때문에 예외를 작성해야 함)

    - 컴파일 시 에러를 확인하기 때문에 확인된 예외라고 부릅니다.

     

    미확인 예외(uncheked excpetion)란?

    - 런타임 시 잘못 구현된 코드로 인해 발생하는 예외(대표적으로 0으로 나누는 경우)

    - 컴파일 시 확인하지 않기 때문에 미확인 예외라고 부릅니다.

     

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

    해당 메서드에서 예외를 던졌는데 catch 블록이 상위에 있다면 그 사이 메서드 모두 해당 예외를 정의해야 합니다.

    따라서 하위 메서드에서 코드를 변경하면 하위 메서드가 호출하는 상위 메서드를 모두 수정해야 합니다.

    따라서 모든 함수가 최하위 함수의 예외를 알아야 한다면 이는 캡슐화를 깨트립니다.

     

    OCP란?

    개방 폐쇄 원칙이라고 불리며 Open Closed Principle의 약자로 확장에서 열려있고 변경에는 닫혀있는 원칙을 의미합니다.

    즉, 기존의 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계함을 의미합니다.

     

    3. 예외의 의미를 제공하자

    보통 함수의 호출 스택을 제공하지만 오류 메시지에 실패한 연산 이름과 실패 유형의 정보를 담아 예외를 던진다면 오류가 발생한 원인과 위치를 찾기 쉬워집니다.

     

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

    외부 라이브러리가 던질 예외를 모두 잡아 각각 처리하는것은 비효율적입니다.

    이것을 하나의 예외 클래스를 반환하는 래퍼 클래스를 사용한다면 프로그램이 훨씬 깔끔해집니다.

    // Bad
    // 외부 라이브러리가 던질 예외를 모두 잡아 낸다. 
    // 같은 에러 잡아 내는 코드가 많다. 
    // 변경하기 어렵다.
    
    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 {
      ...
    }
    // Good
    // 호출하는 라이브러리 API를 감싸면서 예외 유형 하나를 반환.
    // Wrapper클래스 덕분에 의존성이 크게 감소.
    
    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);
        }
      }
      ...
    }

    5. null을 반환하지 마라

    null을 확인하는 코드가 필수적으로 따라오기 때문에 일거리가 증가할 뿐만 아니라 null을 확인하는 코드를 하나라도 빼먹는다면 애플리케이션이 통제 불능에 빠질 수도 있습니다.

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

    만약 getEmployees() 메서드가 null을 반환한다면 null을 확인해야 하지만 만약 직원이 없을 때 Collections.emptyList();를 반환한다면 null을 확인할 필요가 없습니다.

     

     

     

    6. null을 전달하지 마라.

    정상적인 인수로 null을 기대하는 API가 아니라면 메서드로 null을 전달하는 코드는 최대로 피해야 합니다.

    null이 전달되게 된다면 필연적으로 전달받는 쪽은 null을 확인하는 구문을 작성해야 합니다.

     

     

     

     

     

    출처

    클린 코드( 로버트 C. 마틴)

    https://codevang.tistory.com/140

     

    예외(Exception) 처리하기_기본개념과 예외처리 클래스 [1/5]

    자바에서 오류는 예외(exception)과 에러(Error) 2가지가 있습니다. 아래의 두 가지 설명에서 볼 수 있듯이, 개발자가 코드 내에서 처리할 수 있는 것은 "예외"에 관련된 사항입니다. [ 예외 (Exception) ]

    codevang.tistory.com

     

    댓글

Designed by Tistory.