Showing Posts From
Null
- 05 Dec, 2025
에러 메시지 'null pointer exception': 다시는 싫다
에러 메시지 'null pointer exception': 다시는 싫다 오전 10시 32분 커피 마시다가 슬랙 알림이 울렸다. QA팀이다. "개발님, 회원가입 안 돼요." 손이 떨렸다. 어제 배포한 거다. 30분 전에 올라갔다. 벌써 터졌다. 로그를 켰다. 빨간 글씨가 가득하다. java.lang.NullPointerException at com.company.user.UserService.register(UserService.java:247)또 null이다. 247번째 줄이다. 코드를 열었다. String email = userDto.getEmail().toLowerCase();getEmail()이 null을 뱉었다. 당연히 toLowerCase()에서 터진다. "아..." 한숨이 나왔다. 어제 급하게 짠 코드다. null 체크를 안 했다. 3년 전 신입도 아니고, 7년 차가 이러면 안 되는데. 핫픽스 브랜치를 땄다. 손가락이 자동으로 움직인다. if (userDto.getEmail() == null) { throw new IllegalArgumentException("이메일은 필수입니다"); }5분 컷이다. 커밋, 푸시, PR, 머지. 배포는 10분. QA팀에 "해결했습니다" 보냈다. "감사합니다^^" 답장이 왔다. 고맙진 않다. 부끄럽다.점심시간, 김치찌개집 사장님이 물었다. "오늘 표정 안 좋네요?" "일이 좀..." "개발자는 힘들어요. 우리 아들도 그래요." 김치찌개를 떴다. 뜨거웠다. 혀가 데었다. null pointer exception. NPE. 개발자라면 누구나 안다. 제일 흔한 에러다. 제일 짜증 나는 에러다. 왜 짜증 나냐면, 내 잘못이기 때문이다. 문법 에러는 컴파일러가 잡아준다. 네트워크 에러는 인프라 탓을 할 수 있다. DB 에러는... 뭐, DBA한테 물어보면 된다. 근데 NPE는 다르다. 내가 null을 만들었다. 내가 null 체크를 안 했다. 내가 실수했다. 그래서 더 화난다. 나한테. 후배 민수가 작년에 물었다. "형, null 체크 매번 하는 게 맞아요? 코드가 너무 길어져요." "해야지. 안 하면 터져." "Optional 쓰면 안 돼요?" "그것도 결국 체크는 해야 해. 다른 방식일 뿐이지." 민수는 고개를 끄덕였다. 그러고 2주 뒤에 NPE로 배포 롤백했다. 내가 리뷰할 때 못 봤다. 둘 다 잘못이다.오후 3시, 회의실 장애 회고다. 팀장이 물었다. "원인이 뭐였어요?" "null 체크 누락이었습니다." "왜 누락됐죠?" 대답이 안 나왔다. '급했어요'라고 할 순 없다. 그건 핑계다. "제가 놓쳤습니다." 팀장이 한숨을 쉬었다. "다음부턴 조심하죠." 회의가 끝났다. 자리로 돌아왔다. 모니터를 봤다. 내 코드에 null 체크가 몇 개나 있을까. 세어봤다. 파일 하나에 12개다. if (user == null) return; if (user.getName() == null) return; if (request == null) throw new Exception(); if (request.getBody() == null) throw new Exception();지겹다. 정말 지겹다. 코틀린으로 짜는 팀이 부럽다. Null Safety가 언어 레벨에서 된다. 자바는 안 된다. Optional이 있긴 한데, 레거시 코드는 다 null 투성이다. "리팩토링 해야 하는데..." 혼잣말이 나왔다. 옆자리 수진이 물었다. "뭘요?" "아니, 아무것도." 리팩토링할 시간이 어딨나. 기획자는 매주 새 기능을 요구한다. PM은 일정을 당긴다. 기술 부채는 쌓인다. 그래서 또 null 체크를 빼먹는다. 그래서 또 터진다. 악순환이다.퇴근 직전, 6시 10분 민수가 PR을 올렸다. 리뷰 요청이 왔다. 코드를 열었다. 200줄짜리 서비스 로직이다. 쭉 읽었다. 50번째 줄에서 멈췄다. Payment payment = paymentRepository.findById(paymentId); payment.setStatus("COMPLETE");findById()는 null을 리턴할 수 있다. 민수는 체크 안 했다. 코멘트를 달았다. "findById null 체크 필요합니다." 5분 뒤에 민수가 수정했다. Payment payment = paymentRepository.findById(paymentId); if (payment == null) { throw new NotFoundException("결제 정보가 없습니다"); } payment.setStatus("COMPLETE");Approve 눌렀다. 그러고 내 코드를 열었다. 어제 짠 거다. 다시 읽었다. 3군데에서 null 체크가 없었다. 아직 배포 안 된 코드다. 고쳤다. "휴..." 7년 차다. 아직도 이런다. 언제까지 이럴 건가. 검색창에 쳤다. "how to avoid null pointer exception java" 스택오버플로우가 떴다. 똑같은 질문이 1만 개다. 똑같은 대답이다.null 체크 하세요 Optional 쓰세요 애초에 null 반환하지 마세요다 안다. 다 해봤다. 그래도 터진다. 왜냐면 사람은 실수하니까. 피곤하면 놓친다. 급하면 까먹는다. 리뷰어도 사람이라 못 본다. 결국 답은 하나다. 조심하는 수밖에. 저녁 9시, 집 아내가 물었다. "오늘 힘들었어?" "응. 장애 났었어." "또? 지난주에도 그랬잖아." "응... 내 실수야." 아내가 맥주를 건넸다. 땄다. 마셨다. NPE 이야기를 했다. 아내는 디자이너라 잘 모른다. 그래도 들어줬다. "그게 그렇게 자주 나는 거야?" "응. 진짜 많이 나." "그럼 자동으로 체크하는 프로그램 같은 거 없어?" "있어. SonarQube, SpotBugs... 다 있어. 근데 완벽하진 않아. 못 잡는 케이스도 많고." "흠..." 아내는 더 안 물었다. 나도 더 안 말했다. 맥주를 다 마셨다. 냉장고를 열었다. 한 캔 더 꺼냈다. 노트북을 켰다. 회사 코드를 열었다. 출퇴근 기록부는 6시 퇴근이다. 근데 지금 코드를 본다. UserService.java를 열었다. 쭉 읽었다. null 체크를 추가했다. 5군데. 커밋 메시지를 썼다. "add null checks for safety" 푸시했다. PR 올렸다. 내일 아침에 머지하면 된다. 시계를 봤다. 10시 반이다. "또 일해?" 아내 목소리다. 돌아봤다. 문 앞에 서 있다. "응... 좀." "그만 해. 내일 하면 안 돼?" "응. 내일 해야지." 노트북을 덮었다. 근데 머릿속은 아직 코드다. 247번째 줄. getEmail(). toLowerCase(). null. 또 떠올랐다. 자기 전까지 계속 떠오를 것이다. 그래도 해야 한다 NPE는 없앨 수 없다. 완벽한 코드는 없다. 사람은 실수한다. 근데 줄일 순 있다. null 체크를 습관화한다. PR 리뷰 때 집중한다. 단위 테스트를 꼼꼼히 짠다. 로그를 잘 남긴다. 그렇게 하면 조금 덜 터진다. 조금 덜 야근한다. 조금 덜 부끄럽다. 7년 차 개발자의 결론이다. "null은 적이다. 근데 없앨 순 없다. 그러니까 경계해야 한다." 이게 끝이다. 내일도 출근한다. 내일도 코드 짠다. 내일도 null 체크한다. 그러다 보면 또 놓친다. 또 터진다. 그럼 또 고친다. 또 배운다. 이게 개발자다.오늘도 null 체크 30개 추가. 내일은 40개.