구체적인 예외처리 없이는 에러 원인 파악도 사용성도 기대할 수 없다
레거시 유지보수 업무 중 있었던 일이다.
사용자가 화면에서 잘못된 날짜 값을 입력하고 업로드를 실행했다. Java 로직에서 그 날짜 값으로 쿼리를 날렸는데, 당연히 조회 결과가 없었다. 그 상태에서 .get()으로 null에 접근하려다 Null Pointer Exception이 터졌다.
CoreMap outMap = traExpFndMapper.selectOneTraExpFnd(inParam);
inParam.put("negoSeq", outMap.get("negoSeq")); // null인 outMap에 접근 → NPE문제는 에러 메시지였다. 사용자 화면에는 그냥 NPE가 떴다. 사용자 입장에서는 뭐가 잘못됐는지 알 수가 없다. 개발자 입장에서도 해당 데이터를 직접 들고 디버깅해봐야만 원인을 알 수 있는 상황이었다.
뒤늦게 깨달은 건 처음부터 이 쿼리에 null 검사를 넣어야 했다는 것이다. 결과가 없을 때는 NPE가 아닌 비즈니스 예외로 처리하고, 사용자가 이해할 수 있는 메시지를 던져줬어야 했다.
CoreMap outMap = traExpFndMapper.selectOneTraExpFnd(inParam);
if (outMap == null) {
throw new BusinessException(MessageUtil.getMessage("error.noTradeRecord"));
}
inParam.put("negoSeq", outMap.get("negoSeq"));NPE는 JVM이 던지는 기술적 예외다. 사용자도, 로그를 처음 보는 개발자도 이 에러만으로는 “뭘 잘못했는지”를 알 수 없다. 반면 비즈니스 예외는 도메인 맥락을 담고 있다. “해당 거래 건을 찾을 수 없습니다”라는 메시지 하나가 디버깅 시간을 몇 배로 줄여준다.
예외처리를 어떻게 하느냐는 단순히 코드의 방어성 문제가 아니다. 애플리케이션이 실제로 쓰기 좋은 도구가 되느냐, 장애가 났을 때 빠르게 원인을 찾을 수 있느냐의 문제다.
연결 (이유)
- 레거시 시스템 유지보수에서 문서화 부재는 예상치 못한 복잡성으로 이어진다 — 본 노트의 NPE 사례가 발생한 동일 프로젝트이며, 레거시 시스템에서 예외처리 부재가 복잡성을 키운다는 맥락이 이어짐
- 리팩토링할 때는 쿼리 호출을 로직 바깥으로 꺼내야 프로세스가 보인다 — 쿼리 호출을 바깥으로 꺼내는 리팩토링 원칙은 null 검사 위치 결정과 같은 문제이며, 예외처리 전략과 코드 구조가 맞닿아 있음