예외처리는 왜 Custom해서 써야할까?

Shinny·2022년 4월 15일
0

Java의 예외 클래스 구조를 살펴보면 모든 예외 클래스는 Throwable 클래스를 상속받고 있으며, Throwable은 최상위 클래스 Object의 자식 클래스이다. 그리고 Throwable을 상속받는 클래스는 Error와 Exception이 있는데, Error 같은 경우는 개발자가 예상하지 못한 시스템 레벨의 오류이기 때문에 미리 대비하여 처리하는 것은 어려운 부분이 있다.
반면 Exception은 개발자가 로직을 추가하여 처리할 수 있다.
개발을 하면서 예외처리를 위한 Class를 생성할 때 RuntimeException을 상속받는 것을 볼 수 있는데 모든 Exception이 RuntimeException인 것은 아니고 우선 CheckedException과 UncheckedException으로 나뉜다.

Checked Exception VS Unchecked Exception

Checked Exception

  • 반드시 예외처리를 해야 한다.
  • 컴파일 단계에서 에러발생
  • 예외 발생 시 트랜잭션 처리(Roll-back X)
  • RuntimeException 제외 모든 Exception(ex. IOException)

Unchecked Exception

  • 예외처리를 강제하지는 않음
  • 실행단계에서 에러발생
  • 예외 발생 시 트랜잭션 처리(Roll-back O)
  • RuntimeExcpetion(ex. NullPointerException etc)

CheckedException이 발생할 수 있는 경우라면 반드시 try-catch 문으로 감싸서 처리해줘야 하며, 이부분은 IntelliJ를 쓰면 자동으로 IntelliJ가 빨간줄을 띄워서 알려주기도 한다. 하지만 UncheckedException의 경우 실행단계에서 발생할 수 있는 에러이기 때문에 꼼꼼한 에러 핸들링 없이는 놓칠 수 있는 부분이 크다. 하지만 고객에게 보여서는 안 되는 정보노출을 방지하거나 혹은 고객에게 못생긴 에러 창을 띄우지 않게 하려면 꼼꼼히 처리해줘야 하는 부분이다. (개발자에게 대단한 기능을 구현하는 것보다 더 중요한 것은 안정된 서비스를 만드는 일이니까!)

처음에는 나도 이러한 에러들을 만났을 때, throw new NullPointerException("error message") 이런식으로 처리를 해준 적이 있었다. (당시에는 예외처리를 했다는 뿌듯함도 있었지만 지금 생각해보면, 통일성이 전혀 없고 또 정확한 에러 원인과 이유도 밝히지 않은 문구들로 프론트에 혼란을 초래할 수 있는 코드였다.)
개발자는 팀원들과 구현한 비즈니스 로직에서 발생하는 RuntimeExcxeption은 반드시 따로 Custom하여 처리를 해주어야 한다. 이 부분은 컴파일 단계에서 에러를 내지 않고 실행단계에서 에러를 내기 때문에 더욱 꼼꼼히 처리를 해주는 것이 안정된 서비스를 만드는 좋은 개발자의 역량이라고 생각한다.
나는 이번 실전 프로젝트 시작 전 팀원들과 함께 예외 처리 방식에 대해 고민해보고 방식을 통일하여 사용하기로 결정했다.

우리가 고민한 기준은 총 2가지인데 프론트에게 통일되고 정확한 에러 메세지 전달하기가 그것이었다. 그리고 우리는 ExceptionHandling의 방식을 1. JSON형식으로 전달, 2. 통일된 에러 메세지 작성, 3. 상태 코드까지 함께 전달하는 방법으로 하기로 했다. 그리고 @ControllerAdvice와 @RestControllerAdvice라는 어노테이션을 사용해서 하나의 ExceptionController를 만들었고 이전 미니 프로젝트 때보다 좀더 가독성과 편의성이 높은 방법으로 예외처리를 할 수 있었다.
(아래는 이번 프로젝트에서 사용한 Exception 처리 방식 코드이다.)

public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException() { super(); }
}
@RequiredArgsConstructor
@RestControllerAdvice
@ControllerAdvice
public class ExceptionController {
@ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<Fail> UserNotFoundException(UserNotFoundException e) {
        return new ResponseEntity<>(new Fail("닉네임이 존재하지 않습니다."), HttpStatus.BAD_REQUEST);
    }
}
profile
비즈니스 성장을 함께 고민하는 개발자가 되고 싶습니다.

0개의 댓글