노트

예외 삼키기

Exception Swallowing

설계#debugging · 연결된 개념 12개

쉽게 말하면

예외 삼키기는 화재경보가 울렸는데 시끄럽다고 경보기 선만 뽑아 버리는 거예요. 불은 계속 번지는데 다들 아무 일 없다고 믿게 되고, 나중엔 어디서 불이 났는지도 알 수 없어요.

비유가 깨지는 곳 선을 뽑는 손이 안 보일 때도 있어요. 비동기 코드에선 catch를 안 써도 처리되지 않은 Promise 거부처럼 예외가 조용히 사라지니, 다시 던지거나 기록하거나 무시하는 이유를 적어요.

예외를 잡아 놓고 아무 처리 없이 흘려보내는 안티패턴(Anti-pattern). 빈 catch뿐 아니라 debug 레벨로만 찍고 정상인 척 진행하는 것도 마찬가지다.

try {
  await saveOrder(order)
} catch (e) {
  // 아무것도 안 함 → 호출자는 저장에 성공했다고 믿는다
}

왜 문제인가

  • 실제로는 실패했는데 호출자는 성공했다고 믿어 버그가 숨는다
  • 로그도 스택 트레이스도 남지 않아 운영 중 이상 동작의 원인을 찾을 수 없다
  • 일부만 성공한 채 진행하면 데이터 정합성이 깨질 수 있다(데이터 무결성)

대신 할 일

  • 다시 던진다: 여기서 할 수 있는 게 없으면 처리할 수 있는 곳으로 넘긴다(예외 처리 원칙)
  • 기록하고 의미 있게 바꾼다: 스택 트레이스를 포함해 로그를 남기고 도메인 예외로 감싸 던진다(로그 레벨과 Logback)
  • 정말 무시해도 된다면 이유를 적는다: 왜 안전한지 주석으로 남긴다

비동기 코드에서는 catch를 쓰지 않아도 예외가 삼켜진다. 처리되지 않은 Promise 거부(Unhandled Promise Rejection)나 기다리지 않은 asyncio 태스크의 예외가 그렇다(Promise, asyncio 태스크 예외가 조용히 사라지는 문제). 증상만 보고 원인을 좁혀 가는 방법은 디버깅 문제 정의 5단계 참고.

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 최종 일관성

    최종 일관성(eventual consistency)은 "지금 당장은 저장소마다 값이 다를 수 있지만, 새 변경이 멈추면 결국 같아진다"는 보장이다. 원본 DB와 검색 색인·캐시·다른 서비스처럼 물리적으로 분리된 저장소를 한 트랜잭션으로 묶을 수 없을 때 받아들이는 일관성 모델(consistency model)이다.

  • 최소 재현

    버그가 여전히 일어나는 가장 작은 코드와 조건을 만드는 것. 원인을 좁히고, 테스트로 고정하고, 남에게 묻기 쉬워진다.

  • 테스트 냄새

    테스트 코드나 테스트 습관에서 나는, 더 깊은 문제를 알리는 신호. 제라드 메스자로스의 xUnit 테스트 패턴 정리가 이름을 붙였다.

  • 트랜잭셔널 아웃박스 패턴

    DB 변경과 이벤트 발행을 안전하게 함께 처리하는 패턴이다. 실제 데이터 변경과 "이 이벤트를 내보내라"는 기록(outbox 행)을 같은 DB 트랜잭션에 넣고, 별도 워커가 outbox를 읽어 메시지 브로커로 보낸다.

  • 집단 코드 소유

    코드의 주인을 개인으로 두지 않고 팀 전체가 코드베이스 전체를 소유해, 누구나 필요한 곳을 고칠 수 있게 하는 XP 실천법.

보기 옵션