본문 바로가기

프로그래밍(공통)

Software의 방어적인 프로그래밍

Assertion

크고 방대한 시스템에서 오류를 찾아내기 위해 적합하다.

사용 지침

  • 절대로 발생해서는 안 되는 조건을 위해서 어설션을 사용하라.
  • 선행 조건과 후행 조건을 문서화하고 검증하기 위하여 어설션을 사용하라.

eg.

Private Funtion Velocity { _
  ByVal latitude AS Single, _
  ByVal longitude AS Single, _

  ' 선행조건
  Debug.Assert( - 90 <= latitude And latitude <= 90 )

  ' 후행 조건
  Debug.Assert( 0 <= returnVelocity And returnVelocity <= 600 )
}

만약 latitude, longitude 변수들이 외부에서 온 것이라면, 무효한 값은 어설션보다는 오류 처리 코드에 의해서 검사되고 처리되어야 한다. 하지만 만약 변수가 신뢰할 수 있는 내부로부터 온 것이고 루틴의 설계는 이 값들이 타당한 범위 내에 있을 것이라는 가정을 기반으로 하고 있다면, 이 assertion은 적합하다.

오류 처리 기법

어설션은 절대로 발생하면 안되는 오류를 처리하기 위해서 사용한다. 만약, 발생할 것이라고 예상되는 오류는 어떻게 처리해야될 것인가?

중립적인 값 리턴

잘못된 데이터에 대한 가장 무난한 대응이다. 숫자는 0, 문자열은 ""를 리턴하는 것이다.

다음에 오는 타당한 데이터로 대체

DB를 읽다가 깨진 레코드를 만날 경우, 그 다음 다시 시도한다. 예를 들어, 온도계로부터 온도를 초당 1번 읽고 있는데 타당한 값을 한 번에 얻지 못한다면, 1초 뒤의 다음 값을 사용한다.

이전과 동일한 값을 리턴

만약 소프트웨어가 온도를 한 번 읽지 못한다면, 아마도 마지막에 읽었던 값과 동일한 값을 리턴할 것이다.

가장 가까운 타당한 값으로 대체

만약 온도계가 0~100까지만 표시할 수 있는데, 현재 기온이 -10이라면 0을 리턴하는게 타당하다.

경고 메시지를 파일에 기록하라

잘못된 데이터가 감지되면 이를 기록하라. 로그를 사용한다면 공개가 가능한지 또는 암호화해야 하는지 고려하라.

오류 코드를 리턴

오류가 발생한 곳에서 오류 코드를 리턴하게 작성하면, 이를 사용하는 레이어에서 이를 처리하게 한다.

오류 처리 루틴이나 객체를 호출

오류 처리를 전역적인 오류 처리 루틴이나 오류 처리 객체에 집중시키는 것이다. 이는 오류를 처리하는 부분들이 집중될 수 있어서 디버깅이 쉬워진다.

오류가 발생한 곳에서 오류 메시지 출력

가장 저렴함 비용으로 오류 처리의 오버헤드를 줄일 수 있다. 해당 메시지가 사용자에게 알려져도 괜찮은지 고려하라.

예외(Exception)

예외는 코든가 오류나 예외적인 이벤트를 호출한 코드에 전달할 수 있는 특수한 방법이다. 쉽게 생각하면 해당 로직에서 "저는 이걸 어떻게 처리할 지 모르겠습니다. 하지만 누군가 이것을 처리하는 방법을 알고 있기를 바랍니다"라고 소리치는 것과 같다.

처리 방법

정말로 예외적인 조건인 경우에만 예외를 던져라

예외는 조건을 처리하기 위한 강력한 방법과 복잡성 증가 사이의 trade-off이다.

책임을 전가하기 위해서 예외를 사용하지 말라

오류 조건이 지역적으로 처리될 수 있다면, 지역적으로 처리하라.

일관성 있는 추상화 수준으로 예외를 던저라

예를들어, getTaxId()라는 메소드에서 RuntimeException을 던지는 것 보단 EmployeeDataNotFound라는 예외를 던지는게 추상화 수준을 유지할 수 있다.

Reference

  • Code Complete(Steve McConnell)