Exception Part. 03

최완식·2023년 1월 26일
0
post-thumbnail

그래서 예외는 어떻게 처리하는 것이 좋은걸까?

오류 상황

  • 예외 상황과 오류 상황을 다른 의미로 사용할 것
  • 오류 상황은 error condition을 말함
  • 이 오류 상황을 처리하는 방법 중에 예외가 있음

오류 상황은 예측 가능한 상황을 의미함

  • 프로그램 실행 중에 기본적으로는 일어나지 않음
  • 하지만 일어날 수 있는 일
    • 따라서 이러한 상황을 처리하는 코드는 프로그램 기능의 일부임
  • 프로그래머가 이를 예측하지 못했다면?
    • 버그

오류 상황을 처리하는 4가지 방법

무시

  1. 곧바로 크래시
  2. 일단은 작동하는데 언젠가는 크래시
  3. 안정적이지 못한 상태로 계속 동작
    • 데이터가 망가진 상태
    • 올바르지 않은 결과가 나올 수 있음
    • 은행 출금 서비스?

검사 후 정상적 프로그램 종료

  • 사용자에게 문제 상황을 보여주고 종료
    • 팝업
    • 로그 파일
  • 크래시보다 나은점
    • 제대로 시스템 상태를 정리하고 프로그램 종료할 가능성이 높음
    • 종료 후 시스템이 좀 더 안정적인 가능성이 높음
    • 작업했던 내용을 날리지 않고 저장해줄 수 있음

미리 검사 후 문제를 고친다.

  • 분모가 0일 경우 1로 바꾼다.
  • 사용자에게 올바른 값을 입력하라고 다시 요청한다.
  • 누군가는 이런 방식을 개체지향적이 아니라며 배척함
    • 모든 오류를 예외로 하자 부류들
  • 하지만 UX를 포기하면서까지 OO를 계승할 이유가 없음
  • 예외는 다른 방법에 비해 성능이 가장 느림
  • 설계와 필요한 성능 수준에 따라 OO에서도 충분히 좋은 방법이다.

단점

  • 문제가 처음 발생한 곳을 파악하기가 쉽지 않다.
  • 파일 읽는 함수에서 파일 못찾은 경우 빈 문자열을 반환한다면?
    • 그 당시에는 맞을 수 있음
    • 근데 나중에 그 파일에 문자열을 덧붙이려고 하면 불가능함
    • 프로그래머는 있던 파일이 사라졌다 생각할 수 있음
  • 즉, 디버깅이 어려워짐

예외를 던진다.

  • 문제가 발생했다는 사실을 알려줄 수는 있음
  • 그 예외를 처리할 수도 있음

오류 상황을 피하는게 최고

  • 처음부터 문제가 없는 것이 가장 좋음
  • 내가 가진 가정이 옳은지부터 검토하는 것이 좋다.
    • 파일이 항상 있는가?
    • 0으로 나눌 가능성은 없는가?
    • 데이터는 항상 들어와 있는가?

프로그램은 여러 시스템으로 구성되어 있다.

  • 각각의 모듈은 완전하다고 가정하자.
  • 문제는 경계에서 생기는데, 이럴 때 좋은 것은
  • 내 영역으로 들어오는 데이터는 언제나 유효하게 만드는 것이다.
  • 경계에서 들어오는 데이터들은 반드시 검증해야 한다.
  • 만약 잘못된 데이터라면 거부해버린다.
  • 즉, 내가 통제 가능하도록 하는것이 중요.

남에게 문제를 알려주는 방법

  • 참/거짓이나 null을 반환
  • 오류 코드 (int, enum)을 반환
  • 예외를 던짐

예외는 OOP의 일부가 아니다.

  • 비슷한 시기에 나와 예외가 OO의 일부라 생각하는 사람들이 있음
  • 극단적인 진영은 OO에서 무조건 예외만 사용해야 한다고 함
    • 예외만 잘하면 프로그램이 튼실해 진다??

예외 외에는 해결책이 없는 경우: 생성자

  • null을 반환하여 생성시 문제가 없다는 것을 알려줄 수 없음
    • Swift와 같은 언어는 가능
  • 위와 같은 언어의 경우 문제가 발생했다는 사실을 알려주려면 예외가 유일한 방법
  • 왜냐하면 결국 위와 같은 언어도 C로 구현되었을 가능성이 높기 때문
  • C의 경우 메모리 할당 > 메모리를 개체에 배정 > 생성자를 통해 상태 초기화 의 흐름을 갖기 때문
  • 일단 메모리 할당을 시켜놨는데 생성자 블록 안에서 문제가 생기면 되돌릴 방법이 없음
    • 사실 언어의 제약사항..!

잘못된 예외처리보다 크래시가 낫다.

  • 잘못 처리하면 크래시가 안나고 프로그램이 계속 실행되곤 함
  • 당연히 안정적이지 않은 상태임

크래시를 예전보다 덜 심각하게 생각함

  • 크래시의 문제는 작업물을 잃어버리는 것
  • 그런데 요즘은 차라리 크래시가 나게하고 자동 세이브로 해결함
  • 심지어 온라인 문서 편집기는 언제나 저장
  • 즉, 사용자들은 더더욱 크래시에 신경 안 씀 (옛날에 비해)

요새 OS, 하드웨어는 많이 발전됨

  • 이제는 다음의 두 사항이 안정성 측면에서 큰 차이가 없다.
    • 크래시 발생 > 프로그램 종료
    • 발생한 예외를 처리 안함 > 프로그램 종료
  • 예전에는 서버 앞에서 사람이 있었어야 했으니 둘이 차이가 난다.
  • 하지만 이제는 OS에서 처리해줌
  • 디버깅 잘하는 프로그래머들은 오히려 크래시를 선호
    • 문제를 일찍 발견
    • 크래시 발생 이유를 곧바로 조사 가능

크래시와 메모리 덤프

  • 메모리 덤프: 거의 모든 정보
    • 디버거에서 열면 모든 스택 값을 볼 수 있음
  • 예외: 정보가 적음
    • 호출 스택 정보 (문자열)
    • 메시지 (null인 경우가 빈번)
    • 예외 타입
  • 예외를 던지게 되면 많은 내용을 담고 있지 않기 때문에 크래시 나는 순간 그냥 메모리 덤프를 보내주는게 낫다.

프로그램 종료도 올바른 방법이다.

  • 잘못된 예외 처리 때문에 이상한 상태에 빠지는 일을 방지하자.
  • 물론 크래시보다도 좋다.
    • 최근 5분 동안의 작업물도 다 저장해 줄 수 있으니
    • 그런데 자동 세이브 기능만으로 충분하다.

오류 처리 방법의 순위: 책임감 순위

  1. 수정
  2. 종료
  3. 예외: 남에게 폭탄 돌리는 꼴
  4. 무시: 말할 필요 없음

오류 처리 방법의 순위: 오지랖 순위

클라이언트가 할 일을 내가 해줌

  1. 종료
  2. 수정: 호출자가 수정을 원하지 않을 수도? 혹은 내가 잘못 고치는 걸 수도?
  3. 예외
  4. 무시

오류 처리 방법의 순위: 명확성 순위

코드를 보는 것만으로 어떤 일이 일어나는지 알 수 있는가?

  1. 종료 / 수정
  2. 무시
    • 크래시가 안나는 경우 예외보다 나쁨
  3. 예외: 예외가 온 경우, 어떻게 처리..? 애매함.
    • 폭탄 돌리기 (그냥 위쪽으로 전파)
    • 예외에 대해 안전하게 작성하도록 노력 (난 예외가 와도 복구시킬 수 있어)
      • 자신을 과대평가

예측 가능한 상황의 처리법

  • 위에 소개한 4가지 처리 방향은 언제나 4가지 방법이 있는게 아니다.
  • 즉, 상황따라 사용할 수 있는 방법의 개수가 달라진다.
    • 오류를 예측O: 기능의 일부
    • 오류를 예측X: 버그

이미 예측 + 고치기 쉬움

  • 안전하게 고칠 수 있는 자신이 있어야 함, 어렵지 않아야 함
  • 쉬운 경우 고치고 계속 프로그램 진행
  • 다른 시스템에서 발생한 예외 역시 경계에서 처리하고 계속 진행시킴
  • 즉, 이런 경우 수정하여 진행시킴

이미 예측 + 고치기 어려운 경우

  • 최종 사용자에게 메시지를 보여주고 싶다면? (예외를 던졌다면)
    • 중간에서 아무데도 catch안하고 최상위까지 예외를 전달
    • 최상위 함수에서 팝업창을 띄워 메시지를 보여줌
    • GUI가 아니라면 main함수에서 로그파일에 기록
  • 최종 사용자에게 메시지를 보여주기 싫다면?
    • 문제 발생 시점에서 로그를 남기고 프로그램 종료
    • 예외를 던져 main에서 catch 후 로그남기고 프로그램 종료

예측하지 못한 상황

  • 처리 코드는 당연히 없음
  • 수정도 당연히 불가능
  • 프로그래밍 언어 따라 달라짐
    • 혹시라도 발생할 수 있는 모든 예외를 main에서 catch하고 로그를 남겨줌
      • 예외로 남기기 때문에 자세한 디버깅 정보는 없음
    • 크래시가 나서 바로 메모리 덤프가 생김

정리

  • 실행 중에 문제를 고치려 한다고 프로그램의 안정성이 높아지는 것은 아니다.
  • 무조건 고치라는 말은 잘못된 조언이다.
  • 좀비 상태가 되는 것이 더 큰 문제다.

Reference

profile
Goal, Plan, Execute.

0개의 댓글