오류를 ‘예상된 오류’와 ‘예상치 못한 오류’ 두 범주로 나누고, 각각을 어떻게 다뤄야 하는지에 대한 관점을 정리한다.
by Evan Hahn, posted Mar 1, 2026, tagged #software-development
요약: 내 생각에 오류는 두 범주로 나뉜다. 예상된 오류(“사용자가 잘못된 데이터를 입력함” 같은 것)는 정상 동작의 일부로, 개발자의 잘못이 아니며, 처리되어야 한다. 예상치 못한 오류(“null pointer exception” 같은 것)는 개발자의 잘못이고, 대개 버그를 의미하며, 크래시가 나도 된다.
오류 처리는 프로그래밍과 사용자 경험에서 중요하지만, 종종 소홀히 다뤄지는 부분이다.
수년에 걸쳐 나는 소프트웨어에서의 오류 두 종류에 대한 나름의 견해를 갖게 되었다. 이는 주로 웹 및 애플리케이션 개발 경력에서 비롯되었지만, 이 배움이 폭넓게 적용되기를 바란다.
내 생각에 오류는 두 범주로 나뉜다: 예상된 오류와 예상치 못한 오류.
예상된 오류는 정상 동작 중에 발생한다. 예시:
이런 일이 일어났다고 해서 개발자가 실수한 것은 아니며, 이를 예방하기 위해 할 수 있는 일도 대개 많지 않다. 이런 오류가 존재하는 것 자체는 버그가 아니다(다만 처리하지 않는 건 버그가 될 수 있다). 이것들은 프로그래머의 잘못이 아니다.
예상된 오류는 복구 가능하다. 이는 경고를 로깅한다든지, 사용자에게 메시지를 보여준다든지, 대체(fallback)를 사용하는 것을 의미할 수 있다.
예상된 오류는 throw, raise, panic을 하면 안 된다. 대신 오류 결과를 반환해야 한다. 이는 언어마다 다르지만, 흔히 Result 타입, null과 성공 값의 유니언, 또는 오류 코드 형태다. 이런 패턴은 오류 처리를 하도록 당신을 밀어붙이는데, 소프트웨어를 신뢰할 수 있게 만들고 싶다면 실제로 그렇게 해야 한다.
예상된 오류는 WARN 또는 INFO 로그 메시지를 사용해야 한다. 이것은 해결해야 할 문제가 아니기 때문이다. 경고가 아주 많이 발생하기 시작하면 알림을 설정하고 싶을 수도 있다.
예상치 못한 오류는 절대 발생하면 안 된다. 만약 발생한다면 버그가 있는 것이다! 예시:
일반적으로 이런 오류를 복구하려고 시도하면 안 된다. 터져도 된다—크래시, panic, throw.
더 급진적으로 말하자면: 나는 종종 예상치 못한 오류는 프로그램을 완전히 크래시 내야 한다고 생각한다. 단기적으로는 방해가 되지만, 장기적으로는 크래시가 소프트웨어를 더 신뢰할 수 있게 느끼게 만든다고 본다. 이런 문제는 (자신의 테스트가 아니라면) 화난 사용자들을 통해 더 쉽게 알게 되기 때문이다.
예상치 못한 오류는 ERROR 또는 FATAL 로그 메시지를 사용해야 한다. 실제 문제를 나타내기 때문이다. 좋게 보면 잘못된 가정을 뜻한다. 나쁘게 보면 어딘가에 심각한 버그가 있다는 뜻이다.
“예상된”과 “예상치 못한”의 경계는 작업에 따라 달라진다.
한쪽 극단: 프로토타입이나 빠르게 만드는 스크립트라면, 내 생각엔 모든 오류가 예상치 못한 오류다. 네트워크, 파일시스템, 사용자 입력에서 생기는 문제를 처리하지 않기로 결정할 수도 있다. 누가 신경 쓰겠는가? 그냥 작은 스크립트나 아이디어일 뿐이다.
다른 쪽 극단: 50년 임무의 우주 탐사선용 코드를 작성한다면, 거의 모든 오류가 예상된 오류이며, 치명적인 하드웨어 고장까지 포함해서 그렇게 봐야 한다.
대부분의 프로그램은 그 중간 어딘가에 있고, 어떤 오류가 예상치 못한 오류인지 결정해야 한다. 예를 들어 메모리 할당 오류는 당신의 프로그램에서 예상된 오류인가? 상황에 달려 있다.
내 경험상, 더 신뢰할 수 있게 만들고 싶다면 점점 더 많은 오류를 예상하게 되는 쪽으로 기울게 된다. 평범한 하루에도 잘못될 수 있는 건 많다! 예를 들어 우리 팀은 최근 Node.js 앱을 작성하면서도 메모리 할당 오류를 다뤄야 했다.
Rust와 Zig 같은 일부 프로그래밍 언어는 많은 오류를 예상된 오류로 분류한다. JavaScript와 Python 같은 다른 언어는 이를 예상치 못한 오류로 분류한다. 예를 들어 Go에서 JSON을 파싱할 때는 컴파일러가 오류 처리를 강제하지만, Ruby에서는 그렇지 않다. 나는 운영(프로덕션) 소프트웨어에는 더 엄격한 컴파일러를, 스크립트와 프로토타입에는 더 느슨한 언어를 선호하는 편인데, 그 이유 중 하나가 오류에 대한 철학 때문이다. (Rustacean이라면 아마 이 글 전체가 Rust의 오류 철학과 매우 비슷하다는 걸 알아챌 것이다.)
분명히 하자면: 이것은 그저 내 생각이다. 나는 이런 식으로 오류를 분류하는 것이 유용하다고 느꼈다. 당신이 오류를 다르게 생각한다면, (1) 의견을 들려주면 좋겠다 (2) 소프트웨어에서 오류 처리에 대해 고민하고 있다는 사실이 반갑다.
별도 표기가 없는 한, 콘텐츠는 Creative Commons Attribution-NonCommercial License에 따라, 코드는 Unlicense에 따라 라이선스가 적용된다. 로고: Lulu Tang. 프로필 사진: Ali Boschert-Downs.