CHAPTER 4 오류

좋은코드 나쁜코드: 프로그래머의 코드 품질 개선법(PART I 이론)

CHAPTER 4 오류

코드가 실행되는 환경은 불완전 하다. 사용자가 잘못된 입력을 제공하고, 외부 시스템이 다운되며, 자신이 작성한 코드와 다른 개발자가 작성한 코드가 종종 버그를 가질수 있다.

오류에 대해서 특히 어떻게 알리고 대처해야 하는지 논의해봐야 골치만 아픈 복잡한 문제다.

복구 가능성

복구 가능한 오류

  • 네트워크 오류
  • 잘못된 사용자 입력
  • 중요하지 않은 작업 오류

복구할 수 없는 오류

  • 코드와 함께 추가되어야 하는 리소스가 없다
  • 잘못된 입력 인수로 호출
  • 일부 필요한 상태를 사전에 초기화 하지 않음

신속한 실패와 요란한 실패

호출하는 쪽에서만 오류 복구 가능 여부를 알 때가 많다

다른 코드가 자신이 작성한 코드를 호출하는 것과 관련해 다음과 같은 사항을 신중하게 고려해야 한다

  • 오류로부터 복구하기를 호출하는 쪽에서 원하는가
  • 만약 그렇다면 오류를 처리할 필요가 있다는 것을 호출하는 쪽에서는 어떻게 알 수 있을까?

호출하는 쪽에서 복구하고자 하는 오류에 대해 인지하도록 하라

견고성 vs 실패

오류가 발생될때 다음 중 하나를 선택해야 한다

  • 실패 더 높은 코드 계층이 오류를 처리하게 하거나 전체 프로그램의 작동을 멈추게 한다
  • 오류를 처리하고 계속 진행한다

신속하게 실패하라

  • 신속하게 실패하기는 가능한 문제의 실제 발생 지점으로부터 가까운 곳에서 오류를 나타내는 것
  • 호출하는 쪽에서 오류를 복구할수 있는 기회를 최대한 제공
  • 복구 할수 없는 오류일 경우 개발자에게 문제를 신속하게 파악하고 해결할수 있는 기회를 제공

요란하게 실패하라

  • 오류가 발생하는데도 아무도 모르는 상황을 막고자 하는 법

복구 가능성의 범위

  • 오류가 발견되면 오류를 기록하고 모니터링 해야 된다
  • 복구할수 있는 또는 복구할수 없는 범위가 틀려질수 있다

오류를 숨기지 않음

  • 호출하는 쪽에서 복구하고자 할 수도 있는 오류를 숨기면 호출하는 쪽에서 오류로부터 복구할 수 있는 기회를 없에는 것이다
  • 복구할수 없는 오류를 숨기면 프로그래밍 오류가 감취진다
  • 오류를 숨기면 호출하는 쪽에서 실제코드가 잘 작동하고 있다고 가정하지만 실제코드는 작동하지 않을수 있다

오류가 발생했다는 사실을 숨길수 있는 방법

  • 기본값 반환
    • 오류가 발생했을때 기본값을 반환하는것
    • 요란한 실패의 원리를 위반 하는것
  • 널 객체 패턴
    • 개념적으로 기본값 반환가 유사
  • 아무것도 하지 않음
    • 코드가 하는 일에 대해 개발자가 가지고 있는 정신 모델과 코드가 실제로 수행하는 것 사이의 불일치를 일으킬 가능성이 높다

오류 전달 방법

오류가 발생하면 일반적으로 더 높은 계층으로 오류를 알려야 한다.

오류를 알리는 방법

  • 명시적 방법
    • 검사 예외
      • 명시적으로 오류를 전달하는 방법
      • 호출하는쪽에서 강제적으로 인식함
    • 널 반환 유형(널 안정성의 경우)
      • 널값이 의미하는 바를 설명하기 위해 주석문이나 문서를 추가해야 된다
      • 널 안정성(?)을 지원하기 때문에 호출하는 쪽에서 널인지 반듯이 확인 해야된다
    • 옵셔널 반환 유형
    • 리절트 반환 유형
      • 널값이나 옵셔널 타입을 반환할때 문제 중하나는 오류 정보를 전달할수 없다는것
      • 값을 얻을수 없음을 알릴 뿐만 아니라 값을 얻을 수 없는 이유까지 알려주면 유용하다
    • 아웃컴 반환 유형(반환값 확인이 필수인 경우)
      • 호출하는쪽에서 반환값을 강제적으로 확인해야 된다면 이것은 오류를 알리는 명백한 방법이다.
      • 컴파일러가 경고를 생성하도록 함수를 표시할수 있다
    • 스위프트 오류
  • 암시적 방법
    • 비검사 예외
      • 세부조항일 뿐 오류를 암시적으로 알리는 방법
      • 호출하는 쪽에서 예외가 발생할수도 있다는걸 몰라도 된다
    • 매직값 반환(피해야 한다)
      • 매직값은 코드 계약의 명백한 부분을 통해 호출하는 쪽에 알릴 수 없어서 예상을 벗어나는 결과를 가져올수 있고 버그로 이어질수 있다.
      • 오류를 알리는 좋은 방법이 아니다
    • 프로미스 또는 퓨처
      • 프로미스와 퓨처는 오류 상태도 전달할수 있다.
      • 호출하는 쪽에서 잠재적인 오류 시나리오를 완전히 알지 못하기 때문에 암시적인 방법
      • 리절트 유형의 프로미스를 반환하면 명시적이지만 코드가 복잡해지기 때문에 모든 사람이 다 이렇게 사용하지 않을것이다
    • 어서션
    • 체크(구현에 따라 틀려짐)
    • 패닉

복구할 수 없는 오류의 전달

  • 비검사 예외를 발생
  • 프로그램이 패닉이 되도록
  • 체크나 어셔션의 사용

호출하는 쪽에서 복구하기를 원할 수도 있는 오류의 전달

비검사 예외를 사용해야 한다는 주장

  • 코드 구조 개선
    • 대부분의 오류 처리가 상위 계층에서 이루어질 수 있기 때문에 비검사 예외를 발생시키면 구조 개선을 할수 있다.
  • 개발자들이 무엇을 할 것인지에 대해서 실용적이어야 함
    • 너무 많은 명시적 오류 전달을 접하면 결국 잘못된 일을 한다고 주장

명시적 기법을 사용해야 한다는 주장

  • 매끄러운 오류 처리
    • 비검사 예외를 사용한다면 모든 오류를 매끄럽게 처리할 수있는 단일 계층을 갖기 어렵다
  • 실수로 오류를 무시할 수 없다
    • 잘못된일이 기본적으로 혹은 실수로 인해 일어나지 않는다
  • 개발자들이 무엇을 할 것인지에 대해서 실용적이어야 함
    • 비검사 예외는 코드베이스 전반에 걸쳐 제대로 문서화가 된다는 보장이 없고 개인적인 경험을 비추어 보아 문서화되지 않는 경우가 많다.

필자는 명시적인 방식을 선호

컴파일러 경고를 무시하지 말라

컴파일러 경고는 어떤식으로든 코드가 의심스러우면 표시하는데 이것은 버그에 대한 조기 경고

참조