cheese10yun / blog-comment

0 stars 0 forks source link

Spring Guide - Exception 전략 - Yun Blog | 기술 블로그 #25

Open utterances-bot opened 4 years ago

utterances-bot commented 4 years ago

Spring Guide - Exception 전략 - Yun Blog | 기술 블로그

Yun Blog | 기술 블로그

https://cheese10yun.github.io/spring-guide-exception/

NotRayor commented 4 years ago

진짜 깔끔하게 잘 작성해주셨네요.. 엄청 직관적이라서 좋아요 감사합니다

ChanYoungChoi commented 4 years ago

좋은 내용입니다.

progresivoJS commented 4 years ago

정말 잘읽었습니다.

kimsokuri commented 4 years ago

예외처리에 대해 정말 막연했는데 너무 감사합니다~ 이 글말고 다른 예외글도 너무 잘봤어요 완벽하게는 아니고 아직도 많이 부족하지만 예전보다는 훨씬 나은 방법으로 하는것같습니다. 너무 감사합니다!!!

HyeonUkCho commented 4 years ago

정리하신 내용과 관련된 도서 있는지 알 수 있을까요?

cheese10yun commented 4 years ago

@HyeonwookCho

정리하신 내용과 관련된 도서 있는지 알 수 있을까요?

클린 코드 : 오류 코드 보다 예외를 사용하라 리팩토링 이 내용은 본문 처럼 클린 코드에서 참고 하였고 나머지는 실제 개발하면서 정리한 내용이라서 딱히 다른 도서를 참고 하지는 않았습니다.

BaeJi77 commented 4 years ago

글이 너무 좋네요!! 잘 참고하겠습니다!!

scribnote5 commented 4 years ago

좋은 글 게시해주셔서 감사드립니다. 하나 질문이 있습니다.

{ "message": " Invalid Input Value", "status": 400, // "errors":[], 비어있을 경우 null 이 아닌 빈 배열을 응답한다. "errors": [ { "field": "name.last", "value": "", "reason": "must not be empty" }, { "field": "name.first", "value": "", "reason": "must not be empty" } ], "code": "C001" }

제 생각에는 errors 배열의 요소 개수가 최대 한 개라고 생각하는데, 요소 개수가 여러 개 있을 수 있는지 궁금합니다. 예를 들어 @Valid를 사용하여 input 값을 검증할 때, @NotEmpty(message ="test")에 멤버 변수가 걸린다고 하면 하나의 MethodArgumentNotValidException이 발생하고 errors에도 하나의 요소가 추가되기 때문입니다.

감사합니다.

cheese10yun commented 4 years ago

@scribnote5 결론부터 말씀드리면 errors 최대 개수는 1개 이상일 수 있습니다.

{
  "message": " Invalid Input Value",
  "status": 400,
  // "errors":[], 비어있을 경우 null 이 아닌 빈 배열을 응답한다.
  "errors": [
    {
      "field": "name.last",
      "value": "",
      "reason": "must not be empty"
    },
    {
      "field": "name.first",
      "value": "",
      "reason": "must not be empty"
    }
  ],
  "code": "C001"
}

해당 메시지는 실제 HTTP 요청을 통해서 Response 받은 내용입니다.

@Valid을 통해서 Bean Validation을 진행하는 경우 ConstraintValidator 인터페이스를 사용하는것으로 알고 있습니다. ConstraintValidator인터페이스는 유효성 검사를 isValid 메서드를 사용합니다.

    /**
     * Implements the validation logic.
     * The state of {@code value} must not be altered.
     * <p>
     * This method can be accessed concurrently, thread-safety must be ensured
     * by the implementation.
     *
     * @param value object to validate
     * @param context context in which the constraint is evaluated
     *
     * @return {@code false} if {@code value} does not pass the constraint
     */
    boolean isValid(T value, ConstraintValidatorContext context);

해당 메서드는 예외가 발생했을때 Exception을 발생시키는 구조가 아니라, ConstraintValidatorContext 객체에 에러 메시지와 해당 에러의 node(json key, value)를 정보를 추가하는 방식입니다.

isValid false를 리턴하게 되면 ConstraintValidatorContext 객체에있는 에러메시지, 필드명, 필드 값 들이 출력되는 구조이기 때문에 errors는 1개 이상이 될 수 있습니다. 해당 내용은 ConstraintValidator을 이용해서 효과적인 검증을 참고하시면 좋을거 같아요

물론 ConstraintValidator을 사용하지 않고 비지니스 예외를 던지게되는 경우에는 해당 errors 배열이 1개로 고정될 수는 있습니다 (물론 그것도 처리하면 1개 이상이 되긴 합니다.). errors는 비지니스 예외 보다는 Request Body 예외를 더 표현하기 위한 수단이기 때문에 이렇게 처리했던거 같네요.

dyl6266 commented 4 years ago

안녕하세요, Exception 클래스 구조 좀 보고 싶은데 가능할까요?

cheese10yun commented 4 years ago

@dyl6266

안녕하세요, Exception 클래스 구조 좀 보고 싶은데 가능할까요?

본문에 링크는 깃허브 링크는 첨부 했습니다.

해당 코드는 Github를 확인해주세요.

mijosan commented 3 years ago

와 이거 대박인데요.. 잘썻습니다..

byeungoo commented 3 years ago

예외 처리 항상 고민이었는데 너무 잘보고 갑니다.

tlrruddbs commented 3 years ago

안녕하세요 덕분에 도움이 많이 됐습니다! 혹시 궁굼한게 있는데 일부로 예외를 터뜨릴 수 있나요? 혹시 방법을 알고계신다면 도움을 조금 주시면 감사하겠습니다!

dev-splin commented 3 years ago

아직 취업 준비 중인 취준생입니다!! Exception에 대한 구글링 중에 발견했는데, 너무 깔끔한 글 감사합니다!! ErrorResponse라는 객체를 따로 만들어서 Exception 상황에서 사용하는게 엄청 인상적이었고 좋은 방법이라고 생각되는데, 현업에서 이런 방식으로 많이들 사용하시나요?? 혹시 단점은 없을지 궁금합니다!

dev-splin commented 3 years ago

그리고 혹시 실례가 안된다면 예외처리할 때 어떤 것을 중점으로 생각하시면서 처리하게 되는지 여쭤봐도 될까요?? (팁 같은게 궁금합니다..!! 아직 예외처리가 많이 미숙해서요 ㅠ)

cheese10yun commented 3 years ago

아직 취업 준비 중인 취준생입니다!! Exception에 대한 구글링 중에 발견했는데, 너무 깔끔한 글 감사합니다!! ErrorResponse라는 객체를 따로 만들어서 Exception 상황에서 사용하는게 엄청 인상적이었고 좋은 방법이라고 생각되는데, 현업에서 이런 방식으로 많이들 사용하시나요?? 혹시 단점은 없을지 궁금합니다!

실제 업무에서도 위와 같은 방식으로 처리하고 있습니다. 단점 부분은 Exception 클래스들이 많아 지는 것들과, ERROR CODE의 HTTP status code가 있는 부분이 좋은 구조라고 생각들지는 않습니다.

특히 ERROR CODE에서 HTTP status code를 가지고 있지 않으면 다른곳에서 해당 책임을 구현해야되기 때문에 저렇게 처리하기는 했습니다. 각자 환경이 다 다르기 때문에 각 애플리케이션 특성을 고려하는 부분이 선행되는게 더 좋을거 같네요

cheese10yun commented 3 years ago

그리고 혹시 실례가 안된다면 예외처리할 때 어떤 것을 중점으로 생각하시면서 처리하게 되는지 여쭤봐도 될까요?? (팁 같은게 궁금합니다..!! 아직 예외처리가 많이 미숙해서요 ㅠ)

딱히 팁이라고 할거는 없는데 최대한 앞단에서 많이 검증하고 뒤에서는 앞에서 검증한 내용에 대해서 믿고 가는 방향이 좋다고 생각합니다.

dev-splin commented 3 years ago

아직 취업 준비 중인 취준생입니다!! Exception에 대한 구글링 중에 발견했는데, 너무 깔끔한 글 감사합니다!! ErrorResponse라는 객체를 따로 만들어서 Exception 상황에서 사용하는게 엄청 인상적이었고 좋은 방법이라고 생각되는데, 현업에서 이런 방식으로 많이들 사용하시나요?? 혹시 단점은 없을지 궁금합니다!

실제 업무에서도 위와 같은 방식으로 처리하고 있습니다. 단점 부분은 Exception 클래스들이 많아 지는 것들과, ERROR CODE의 HTTP status code가 있는 부분이 좋은 구조라고 생각들지는 않습니다.

특히 ERROR CODE에서 HTTP status code를 가지고 있지 않으면 다른곳에서 해당 책임을 구현해야되기 때문에 저렇게 처리하기는 했습니다. 각자 환경이 다 다르기 때문에 각 애플리케이션 특성을 고려하는 부분이 선행되는게 더 좋을거 같네요

자세한 답변 정말 감사합니다!! 좋은 글 덕분에 많이 배워갑니다!! 오늘도 좋은 하루 되세요!

2wjdwo97 commented 2 years ago

안녕하세요~ 좋은 글 정말 잘 읽었습니다 질문 드릴 게 몇 가지 있어서 댓글 남깁니다!

ErrorCode enum의 필요성은 무엇인가요? Exception마다 errorCode를 가지고 있다면 따로 errorCode를 enum으로 만들지 않고 Exception 클래스 내부에서 각자 선언하는 거랑 어떤 차이가 있나요?

ErrorCode 자체의 필요성은 무엇인가요? 에러 코드를 보내지 않아도 에러 메세지만 있다면 어떤 에러인지 알 수 있을 거 같은데 코드로 관리하는 특별한 이유가 무엇인가요?

cheese10yun commented 2 years ago

@2wjdwo97

ErrorCode enum의 필요성은 무엇인가요? Exception마다 errorCode를 가지고 있다면 따로 errorCode를 enum으로 만들지 않고 Exception 클래스 내부에서 각자 선언하는 거랑 어떤 차이가 있나요?

ErrorCode의 필요성은 에러에 대한 효율적인 관리의 목적입니다. 본 포스팅에서는 디테일하게 다루진 않았지만 Error Code를 체계적으로 관리하면 해당 코드만 보고도 에러를 빠르게 파악할수 있게됩니다. 같은 맥락으로 Exception에서 각자 관리하면 Error Code를 체계적으로 관리할 수 없습니다. 결국 체계적으로 관리하려면 중앙에서 관리해야 합니다. (각자 Exception 클래스에서 정의하면 중복여부, 해당 체계를 잘 따르는지 확인이 어려움)

ErrorCode 자체의 필요성은 무엇인가요? 에러 코드를 보내지 않아도 에러 메세지만 있다면 어떤 에러인지 알 수 있을 거 같은데 코드로 관리하는 특별한 이유가 무엇인가요?

시스템 내부에서 발생 시키는 메시지를 그대로 노출시키는 것은 보안상에 좋지 않습니다. 회사 내부 시스템에서는 Exception 메세지를 그대로 노출 시켜도 크게 문제가 되진 않겠지만 유져향 서비스에서는 결코 바람직하지 않습니다. 그러기 떄문에 내부 예외 메시지를 어느정도 유저 친화적으로 바꿔야 합니다. 그 형태가 굳이 ErrorCode 필요는 없지만 시스탬 내부의 Exception 메시지는 필터링 헤야합니다. 그런 필터링을 ErrorCode의 message 필드가 대행합니다.

2wjdwo97 commented 2 years ago

@cheese10yun 답변 감사합니다! :)

두 번째 질문에서의 ErrorCode는 "C001"과 같은 코드 자체를 말씀드린 거였는데 해주신 답변이 자세해서 어느 정도 해결된 거 같습니다~

Wave1994-Hoon commented 2 years ago

남윤님 ~~ 혹시 예제코드에서 아래와 같이 파라미터나 혹은 메서드 내부에서 final 키워드를 사용하신 이유에 대해서 알 수 있을까요 ??, 만약 final 키워드를 사용하지 않는다면 발생할 사이드이펙트 같은 것이 있는지 궁금합니다. 😱😱😱

@ExceptionHandler(BusinessException.class) protected ResponseEntity handleBusinessException(final BusinessException e) { log.error("handleEntityNotFoundException", e); final ErrorCode errorCode = e.getErrorCode(); final ErrorResponse response = ErrorResponse.of(errorCode); return new ResponseEntity<>(response, HttpStatus.valueOf(errorCode.getStatus())); }

cheese10yun commented 2 years ago

@Wave1994-Hoon 대부분의 변수는 사실상 상수로 사용되 것들이 대부분이라고 생각드는데요. 일단 선언할 때 부터 final 으로 시작하고 이후에 변수로 사용할 경우 그때 제거 하는 방법이 더 좋다고 생각해요.

만약 final 키워드를 사용하지 않는다면 발생할 사이드이펙트 같은 것이 있는지 궁금합니다.

이 부분 답변드리면 상수 값을 사용하는 이유와 크게 다르지 않구요. 일단 상수로 가져가면 해당 값이 바뀌는 경우는 없다는 가정으로 로직을 파악할 수 있어 디버깅, 유지보수 측면에서 좋은 부분이 있죠. 너무 교과서 적인 답변 이긴 한데 그게 중요한 거니까요

Wave1994-Hoon commented 2 years ago

@cheese10yun 오 감사합니다. 코틀린으로 개발할 때 일단 val 로 선언하고 시작하는거랑 동일한 방법이군요 !!

LeeMinki commented 2 years ago

안녕하세요! http의 status가 body에 들어가 사실상 중복된 값이 들어가서 불편하다는 시각이 있는데 이에 대해 어떻게 생각하시나요?

cheese10yun commented 2 years ago

@LeeMinki http status가 response body에도 내려가고 있기 때문에 중복이 맞습니다. 굳이 중복했던 이유는 Response Body 값만 보고 확인이 편리한 부분이 있습니다. 또 error response가 json 타입이기 때문애 4xx, 5xx에 대한 통계 및 분석 하기에도 더 좋은 편리한 부분도 장점이라고 생각합니다. 물론 http 응답에 내려가는 값으로도 가능은 하죠.

정리하면 http response body json 기준으로 추가적인 작업을 진행 하는 경우 조금더 편리하게 하기 위해서 사용했습니다.

songhee23 commented 2 years ago

감사합니다. 많은 혜안을 얻었습니다.

leehyeonmin34 commented 2 years ago

짱입니다!!

violetbeach commented 2 years ago

잘봤습니다~

hanumoka commented 2 years ago

고민중이었던 내용인데 잘 보았습니다. 한가지 의문이 있는데, 위처럼 비지니스 로직에 발생할수 있는 문제들을 각각 의미있는 예외로 대응하는 방법은 좋은 방법이라 생각되지만, 그 예외의 숫자가 너무 많아지는경우 어떻게 관리하시는지 궁금합니다. 도메인의 크기에 따라 다르겠지만, 비지니스 예외의 개수가 수십개를 넘어가기 시작하면 ... 이게 이렇게 하는게 맞나 싶더라구여...

cheese10yun commented 2 years ago

@hanumoka

그 예외의 숫자가 너무 많아지는경우 어떻게 관리하시는지 궁금합니다.

이 말씀이 예외 클래스들의 증가를 말씀하시는 건가요?

제 개인적인 생각으로는 정말 특수한 케이스가 아닌 경우 대표적인 예외 클래스를 두고 ERROR Code 기반으로 헨들링 하는것이 적절하다고 봅니다.

본 문에서는 설명을 위해서 NotFoundException를 기반으로 엔티티 마다 세부 예외 클래스를 만들었는데요. 세부 엔티티에서 찾지 못하는 경우 NotFoundException를 발생 시키면 예외 클래스들의 증가가 많지는 않을거 같습니다.

저도 Business 하위 1 depth 객체 3~5개 정도만 사용하고 세부적인 내용은 ERROR CODE로 진행하고 있습니다.