1.8오류 무시하지 않기
오류를 무시하지 말고 반환값이나 예외로 대응하라.
TL;DR
메커니즘
우리는 코드의 오류를 여러가지 방법으로 확인한다.
코드 응답
함수는 값을 반환한다. 함수는 오류가 났다는 내용의 값을 반환하기도 하는데, 이는 가장 보편적인 오류 검출 방법이다.
예외
예외는 보다 구조적으로 오류를 전달하고 다루는 방법이지만, 아래와 같이 예외처리를 안하는 나쁜 코드가 흔하다.
javascripttry { // ... } catch(err){ // 아무것도 안함! }
예외는 강력하지만, 무분별하게 사용하면 제어 흐름이 모호해지고 오류 경로를 숨겨 디버깅을 어렵게 할 수도 있다. 예를 들어 비정상적 경로로 콜스택을 벗어나 리소스 누수나 함수의 비정상적 작동을 일으킬 때도 있다. 하지만 오류 처리 자체를 하지 않는다면 이런 문제가 발생한다는 사실조차 인식할 수 없다.
광기
오류를 적절히 처리하지 않으면:
- 불안정한 코드: 찾아내기 어려운 충돌로 가득 차게 된다.
- 불안전한 코드: 크래커들은 소프트웨어 시스템을 파괴하기 위해 종종 오류 처리 과정의 취약점을 이용한다.
- 나쁜 구조: 반복적으로 다루어야 하는 오류로 인해 코드가 깨끗하지 않아진다면, 인터페이스 때문일 수도 있다. 오류 발생이나 처리 과정이 특정 패턴에 따라 일괄적으로 처리되도록 코드를 개선하면, 같은 코드를 반복하지 않아도 된다.
코드에서 모든 잠재적 오류를 확인해야 하는 것처럼, 사용자 인터페이스에서도 모든 잠재적인 잘못된 상황을 노출시켜야 한다. 숨기지 마라. 정상적으로 작동되는것처럼 보이게 하면 안된다.
프로그래머는 프로그램의 오류에 대해 알아야 하고, 사용자도 사용 중에 발생하는 오류에 대해 알아야 한다.
감형 사유
오류를 왜 확인하지(처리하지) 않을까? 사실 많은 이유가 있다.
- 오류 처리로 인해 코드 흐름이 방해되고 코드 읽기가 어려워진다. 정상적인 흐름을 파악하기가 어려워진다.
- 시간이 없다.
- 이 함수는 절대 오류가 발생하지 않는다.(
console.log()
같은 경우) - 정말 간단한 프로그램이라서, 굳이 상용 수준으로 작성하지 않았다.
마치며
8장은 짧지만, 명확한 내용을 전달한다: 오류를 무시하지 마라.
🥸 생각해보기
1. 코드가 하위 레벨에 의해 보고된 오류를 무시하지 않았음을 어떻게 확신할 수 있는가? 코드 수준에서의 해결 방법과 프로세스 수준에서의 기법에 대해 생각해보라.
코드 수준에선 오류를 명시적으로 반환해야할 것이다. 예를 들어 throw new Error
라던지 Promise.reject
등의 방법이 있다. 또, try/catch
, if(!response.ok)
등으로 정상-오류 흐름을 나눠야한다. console.warn
등으로 오류가 나면 콘솔에 메시지를 띄우고, 뜨는 메시지는 무시하면 안될 것이다.
개인적으로 시간에 쫓겨서 잘 돌아가기만 한다면 무시했던 메시지들이 많았다. 또, 단순히 메시지만 없애기 위해 근본 원인을 살피지 않고 땜빵하기 급급했던 적도 있었다. 물론 시간이라는 변수를 감안하지 않을 수는 없지만, 이런 땜빵들을 이후에 여유가 될때라도 고치려고 하지 않고 미룬 것은 잘못이다.
프로세스 수준으론 lint 도구의 제약을 풀어버린다거나 하지 않아야한다. 또, 테스트를 한다면 실패 케이스도 다뤄야 한다.
2. 예외는 반환 코드처럼 쉽게 무시할 수 없다. 예외가 오류를 보고하기에 더 안전한 방법이라는 것이 이유가 될 수 있는가?
예외는 정상 흐름이 아닌 경우에 사용하면 오류를 보고하기에 좋은 방법이다. catch
로 에러가 잡히면 프로그램은 크래시되므로 의도치 않은 결과를 받을 염려가 줄어 안전하다.
3. 오류와 예외가 섞인 코드를 다룰 때 어떠한 접근 방법이 요구되는가?
이 부분은 검색해보니 오류 흐름을 일관되게 설계해야 한다고 한다. 또, 반환값 기반 로직에는 null/false 대신 Result<T, Error>
같은 구조체 패턴을 반환하는 것도 방법이라고 한다.
예외는 외부 API 등 불확실성이 높은 부분에서, 반환은 내부 로직 제어에서 사용하는 식으로 통일하면 좋다고 한다.
4. 적절하지 못한 오류 처리로 실패하는 코드를 식별하는 데 어떤 테스트 기법이 도움되는가?
에러 상황을 의도적으로 발생시키는 네거티브 테스트를 한다. 잘못된 입력, API 실패, 파일 미존재 등의 실패 케이스들을 일으켜 각각 적절하게 처리한다.