기본 (The Basics) - 역설과 전제조건 (Assertions and Preconditions)

00yhsp·2024년 4월 1일

역설과 전제조건 (Assertions and preconditions)은 런타임 시 발생하는 조건이다.
추가 코드를 실행하기 전에 이를 사용하여 필수조건이 충족되는지 확인할 수 있다.
역설 또는 전제조건의 부울 조건이 true이면 코드는 평소와 같이 진행되며,
false이면 프로그램의 현재 상태는 유효하지 않아 코드 실행이 종료되고 앱이 종료된다.

역설과 전제조건은 가정과 기대치를 표현하므로 코드의 일부로 포함할 수 있다.
역설은 개발 과정에서 실수와 잘못된 가정을 찾는 데 도움이 되고 전제조건은 프로덕션을 문제를 감지하는 데 도움이 된다.

런타임 시 기대치를 확인하는 것 이외에 역설과 전제조건은 또한 코드 내에서 유용한 문서 형식이 된다.
에러 처리와 다르게 역설과 전제조건은 복구 가능하거나 예상되는 에러에 대해 사용되지 않는다.
실패한 역설 또는 전제 조건은 유효하지 않은 프로그램 상태를 나타내기 때문에,
실패한 상태를 잡을 방법은 없다.
유효하지 않은 상태에서 복구하는 것은 불가능하다.
역설이 실패하면 프로그램의 데이터 중 하나가 유효하지 않다는 것을 의미한다.
그러나, 그것이 왜 유효하지 않은지 추가로 다른 상태도 유효하지 않은지 알 수 없다.

역설과 전제조건을 사용하는 것은 유효하지 않는 조건이 발생하지 않게 코드를 디자인하기 위함이다.
그러나 유효한 데이터 및 상태를 적용하기 위해 이를 사용하면 유효하지 않은 상태가 발생하면 앱이 종료되기 때문에 더 쉽게 문제에 대해 디버깅할 수 있다.
가정을 확인하지 않으면, 다른 코드가 실패하기 시작하고, 사용자 데이터가 손상된 이후에야 이런 종류의 문제를 알 수 있다.
유효하지 않은 상태가 감지되는 즉시 실행을 중지하면 해당 유효하지 않은 상태로 인한 피해를 제한하는 데 도움이 된다.

역설과 전제조건의 차이점은 언제 체크되는지에 있다.
역설은 오직 디버그 빌드에서만 체크되지만, 전제조건은 디버그와 프로덕션 빌드에서 체크된다.
프로덕션 빌드일 때 역설 내부의 조건은 실행되지 않는다.
이 의미는 프로덕션에서 성능의 영향이 없이 개발 단계에서 많은 양의 역설을 사용할 수 있다는 뜻이다.

역설을 통한 디버깅 (Debugging with Assertions)

Swift 표준 라이브러리에 assert(::file:line:) 함수로 역설을 작성할 수 있다.
이 함수에 true 또는 false로 판단될 표현식과 조건이 false일 경우 출력될 메세지를 전달한다.

let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
// This assertion fails because -3 is not >= 0.

이 예에서 코드는 age가 음수가 아니고 age >= 0이 true일 경우 이어서 실행된다.
age가 음수이면 age >= 0은 false가 되고, 역설은 실패되며 애플리케이션이 종료된다.

평범하게 조건만 반복될 때 메시지를 생략할 수 있다.

assert(age >= 0)

코드가 이미 조건이 체크되었다면 역설이 실패되었는지를 알 수 있는 assertionFailure(_:file:line:) 함수를 사용한다.

if age >= 10 {
	print("You can ride the roller-coaster or the ferris wheel")
} else if age >= 0 {
	print("You can ride the ferris wheel")
} else {
	assertionFailure("A person's age can't be less than zero.")
}

강제 전제조건 (Enforcing Preconditions)

조건이 거짓일 가능성이 있을 때마다 전제조건을 사용하지만 코드가 순차적으로 실행되려면 확실하게 참이어야 한다.
예를 들어 어떤 값들이 범위를 벗어나는지 또는 함수에 유효한 값이 전달되는지 체크하기 위해 전제조건을 사용한다.

precondition(::file:line:) 함수로 전제조건을 작성할 수 있다.
이 함수에 true 또는 false로 판단될 표현식과 조건이 false일 경우 출력될 메세지를 전달한다.

// In the implementation of a subscript...
precondition(index > 0, "Index must be greater than zero.")

preconditionFailure(_:file:line:) 함수를 호출하여 실패가 발생했음을 알릴 수 있다.
예를 들어, 유효한 데이터는 스위치의 기본 케이스가 아닌 다른 케이스에서 처리되어야 한다.

Note:
체크하지 않는 모드 (-Ounchecked)로 컴파일하면 전제조건은 체크하지 않는다.
컴파일러는 전제조건은 항상 참이라 가정하고 코드에 알맞게 최적화한다.
그러나 fatalError(:file:line:) 함수는 최적화 설정과 무관하게 항상 중지를 실행한다.
프로토타입과 초기 개발단계에서 아직 구현되지 않는 기능에서 fatalError(
:file:line:)을 사용할 수 있으며 fatalError("Unimplemented")와 같이 작성할 수 있다.
역설 또는 전제조건과 다르게 치명적인 에러는 절대 최적화되지 않기 때문에 이 구현을 만나면 항상 중지된다.

profile
iOS Dev

0개의 댓글