💡 예외 처리와 스택 풀기, 그리고 내가 뒤늦게 이해한 피드백 이야기
예외 처리에 대한 피드백을 받았던 건 꽤 오래전 일이다
컨트롤러에서 try-catch로 예외를 한꺼번에 처리하기보다는 서비스 단에서 예외를 나눠서 처리하는 게 더 낫다는 얘기였다
그 때 설명을 들었지만, 왜 굳이 그렇게 해야 하는지 이해가 잘 되지 않았다
하지만 최근에 C++의 스택 풀기(stack unwinding) 개념을 공부하면서 그 피드백의 의미가 처음으로 제대로 와닿았다
📌 스택 풀기란?
C++에서 throw로 예외가 발생하면, 함수 호출 스택을 따라 올라가며 지역 객체들이 소멸된다
이 과정을 스택 풀기(stack unwinding)라고 한다
문제는, 이 과정이 끝나고 catch 블록에 도달했을 때는 이미 호출 스택의 맥락이 다 사라진 상태라는 점이다
즉, catch에 도달했을 땐 "어디서", "왜" 예외가 발생했는지를 직접적으로 알기 어렵다
그래서 C++에서는 보통 throw할 때 예외 객체에 상황 정보를 담아 던지는 방식을 사용한다
📎 Java도 마찬가지
이건 C++만의 이야기가 아니다 Java에서도 예외가 발생하면 비슷하게 스택을 타고 올라가면서 예외를 전파한다
그리고 catch 시점에는 호출 스택이 이미 풀려 있기 때문에, 그 위치에서는 자세한 정보가 남아있지 않을 수 있다
🤯 다시 떠오른 피드백
이 부분을 공부하면서 예전에 일하면서 받았던 피드백이 떠올랐다
당시엔 컨트롤러 단에서 try-catch로 한 번에 예외를 처리하는 게 더 간단해 보였고,
서비스 단에서 굳이 예외를 나눠서 처리해야 할 필요성을 잘 이해하지 못했다
하지만 스택 풀기 개념을 공부하면서 그 이유를 조금씩 알게 됐다
C++에서는 예외가 발생하면 호출 스택을 따라 지역 객체들이 소멸되고,
catch 지점에 도달했을 땐 이미 스택이 다 풀린 상태다
즉, 예외가 발생한 위치의 정보는 사라지고, 어디서 어떤 상황이 벌어졌는지 catch 안에서는 제대로 알기 어렵다
그래서 예외를 던질 때 상황 정보를 함께 담는 게 중요하다는 걸 알게 됐다
Java도 비슷한 구조다
예외 발생 시 스택 트레이스가 예외 객체 안에 보존되긴 하지만,
서비스 단에서 의미 없이 그냥 예외를 던져버리면, 컨트롤러에선 그걸 받아도 상황을 명확히 파악하기 어렵다
게다가 처리 방식도 일관되지 않게 되기 쉽다
Spring에서는 @ControllerAdvice나 @ExceptionHandler를 활용해서 전역적으로 예외를 처리할 수 있기 때문에,
서비스 단에서는 상황에 맞는 예외를 명확히 던지고, 컨트롤러나 예외 처리기는 그걸 받아서 응답만 만들어주면 된다
예외는 발생한 위치에서 최대한 구체적으로 처리하고, 그 위 계층에서는 흐름을 정리하는 식으로 역할을 나누는 것이
결국 더 좋은 구조라는 걸 이번에 다시 느꼈다
✅ 마무리
예외 처리라는 건 단순히 try-catch로 감싸는 기술적인 문제가 아니었다
예외가 어디서 발생했고, 어떤 맥락에서 생겼는지를 "전달 가능한 형태로 남기는 구조"가 중요하다는 걸 알게 됐다
C++의 스택 풀기를 통해 언어 차원의 메커니즘을 이해했고,
그걸 바탕으로 실무에서 들었던 조언이 왜 의미 있었는지도 비로소 연결됐다
실무 피드백과 이론 공부가 맞닿는 지점에서 얻는 이해는 역시 가장 깊게 남는다
'업무_메모' 카테고리의 다른 글
Visual Studio에서 C# IL 코드 보는 방법 정리 (0) | 2025.04.09 |
---|---|
비주얼 스튜디오 파워모드 플러그인 설치 (0) | 2024.11.20 |
윈도우에서 다운 받은 파일 체크섬 확인하기 (0) | 2024.11.11 |
유니티와 비주얼 스튜디오 연결 (0) | 2024.01.03 |
유니티 옛날 버전, 유니티 허브로 다운로드 받기 (0) | 2024.01.03 |