요새 참 머리가 아프다.
여러 가지 일이 겹치면서 조용히 컴퓨터 앞에서 공부하고 일기 작성하듯이 블로그를 작성하는 하루하루를 보내고 있다.
때로는 내가 원하는 것들을 못 이룰 때 상실감이 제일 크다는 것은 다들 겪어볼거다.
근데 나는 이 상실감이 시간이 지나면 해결해준다가 아니라 시간이 지나면서 이로 인해 성장하면서 이런 것들을 컨트롤하고 참을 수 있게 되는 거 같다.
힘들 때 도와주는 주변 사람들도 많아져서 금방 일어설 수 있는 거 같다.
이렇게 작게나마 일기처럼 작성해 봤다.
[자유] 3. 한 사람의 조언으로 시작
2024년 끝 무렵 1. 가르침의 의미 가르친다는 것은 매우 어려움이 많다. 내가 진짜 한 가지에 대해서 제대로 알고 확실성이 있어야 가르칠 수 있다. 난 프로게이머를 하기 전에 꿈이 교사였다. 하
bumh07.tistory.com
이건 내가 예전에 일기처럼 작성했던 블로그이다.
2~4달 정도마다 있었던 일기들을 적었는데 잠시 비공개로 해두다가 재밌어하길래 다시 열어둠. ( 약간 관종 )
서론
IT시대로 떠오르는 지금 거의 모든 사람은 전자기기를 소유하고 있으며 사용한다는 사실은 알 것이다.
우리는 그중에서 한 번쯤은 무조건 봤을 ' 404 Not found ' 가 정확히 왜 생기는지에 대해 대부분 의문점은 가지지 않는다.
" 야 그냥 서버가 이상해서 그렇겠지 " , " 와이파이가 안 되나? 왜 안돼 ㅋㅋ "
물론 다 맞을 수도 있는 말이지만 404는 정확히는 클라이언트가 브라우저에게 어떤 요청을 한 URL에 해당된 리소스가 서버에 없는 경우에
바로 404 Not Found가 생긴다.
예를 들면, 어떤 과일 장수가 사과를 파는 창고를 가르쳐줘서 갔는데 그곳에는 아무것도 없는 창고가 있는 알맹이 없는 창고가 있는 격이다.
즉, 접근할 URL에 들어가 봤는데 이미 서버에서 그 자원을 없애거나 없는 경우다.
이 404 또한 4xx의 에러코드 중에 하나에 속한다.
그럼 간단하게 http status에 대해 알아보자.
말 그대로 직역하면 그냥 인터넷 상태를 의미한다.
보통 내가 개발 공부를 하며 많이 봤던 코드는 4xx와 5xx인 거 같다. ( 성공한 적이 거의 없네.. 2xx.. )
이렇게 간단하게 그림만 봐도 무슨 에러인지 무슨 상태인지는 대충 알 수 있다.
하지만 세세하게는 당연히 잘 모른다.
유명한 400 bad request , 404 not found 코드는 아는 정도?
자 이제 http status code를 봤다. 그럼 자바에서 겪을 수 있는 에러에 대해 알아보겠다.
실제로 코틀린이나 자바로 개발 공부를 하면서 나는 'IllegalArgumentException' 한 번쯤은 봤다고 생각한다.
그리고 이런 에러들을 알아가는 과정은 성장에 도움이 된다.
https://techblog.woowahan.com/21686/
실제로 우아한 형제들 기술 블로그에도 다뤄진 내용으로 공부하기 더 수월했다.
본론
예외를 고르기 전에, 먼저 IllegalArgumentException에 대해
요새 자꾸 내가 던진 예외가 진짜로 "클라이언트 잘못"인지, "내 잘못"인지 헷갈리는 순간이 많아졌다.
Spring으로 API를 만들다 보면 @ExceptionHandler로 예외 처리하는 일이 많다 보니, 예외를 대충 던졌다가 로그 보면서 땀 뻘뻘 흘리는 경우가 종종 생긴다.
이번에는 실무에서 자주 등장하는 IllegalArgumentException에 대해 조금 정리해보고자 한다.
예외를 던질 때, 나는 무슨 기준으로 던지고 있었을까?
처음에는 그냥 간단했다.
"클라이언트가 이상한 값을 보냈으면 → 400 에러 줘야지!"
그래서 아래처럼 코드도 만들었다.
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResponse onIllegalArg(IllegalArgumentException ex) {
return new ErrorResponse("입력 오류.", ex.getMessage());
}
그리고 비즈니스 로직 중간중간에 이런 식으로 예외를 던졌다.
if (name.length() > 5) {
throw new IllegalArgumentException("이름은 최대 5자.");
}
그런데... 진짜 그럴 때만 발생할까?
이 예외는 과연 클라이언트 탓일까?
이 질문이 내 사고를 완전 뒤흔들었다.
예를 들어 다음과 같은 코드가 있다고 해보자.
int priority = priorityResolver.getPriority(); // 어떤 전략으로 우선순위를 구함
thread.setPriority(priority); // 1~10 사이의 값이어야 함
여기서 priorityResolver가 이상한 값을 내보내면 IllegalArgumentException이 터진다.
근데 이건 클라이언트가 잘못한 게 아니라 서버 내부 로직 실수다.
그렇다면 이 예외는 클라이언트가 수정해야 하는 오류인가? → 아니다.
응답으로 400을 주면 클라이언트는 계속 자기 탓인 줄 안다. → 문제 해결이 늦어짐.
4xx와 5xx는 경계가 분명해야 한다
4xx | 클라이언트 요청 잘못 | 프론트엔드 / 사용자 |
5xx | 서버 내부 처리 실패 | 백엔드 개발자 |
내가 IllegalArgumentException을 무조건 400으로 처리하면
내 코드가 잘못됐는데도 프론트탓을 하게 되는 상황이 생길 수 있다.
그리고 모니터링 알림도 안 울리니까 문제 발견도 늦다.
그럼 어떻게 처리해야 할까?
진짜 클라이언트 잘못이라면?
→ BusinessException 같은 커스텀 예외를 만들어서 명확하게 400으로 처리
public class NameTooLongException extends BusinessException {
public NameTooLongException(String name) {
super("name.length.exceeded", "이름은 최대 5자입니다.");
addArgument("input", name); }
}
그리고 핸들러에서 400 응답
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleBusiness(BusinessException e) { ... }
원인 모를 오류나 예상치 못한 상황이라면?
→ 그냥 터뜨리자. IllegalArgumentException, NullPointerException 등은 그대로 두고
500 에러로 로그 남기자. 그래야 우리가 디버깅을 할 수 있다.
자 이제 정리해 보자
IllegalArgumentException은 범용 예외다. → 사용을 조심하자.
클라이언트가 잘못한 게 명확할 때만 400을 주자.
내부 로직 오류는 절대 400을 주지 말자.
예외를 커스텀하고, 어떤 상황에서 어떤 예외를 던질지 명확하게 선 그어야 한다.