주간 팁 #171: Sentinel 값 피하기

원래 TotW #171로 2019년 11월 8일 게시됨
작성자: Hyrum Wright
2020-04-06 업데이트됨

빠른 링크: abseil.io/tips/171

Sentinel 값은 특정 컨텍스트에서 특별한 의미를 가지는 값입니다. 예를 들어, 다음과 같은 API를 생각해봅시다:

CPP
// 계좌 잔액을 반환하거나 계좌가 닫힌 경우 -5를 반환합니다.
int AccountBalance();
클릭하여 더 보기

int의 모든 값은 AccountBalance의 유효한 반환 값으로 문서화되어 있지만, -5는 예외입니다. 직관적으로, 이것은 약간 이상해 보입니다. 호출자가 -5에 대해 명시적으로만 확인해야 하는지, 아니면 모든 음수 값이 “계좌 닫힘” 신호로 신뢰할 수 있는지 명확하지 않습니다. 시스템이 음수 잔액을 지원해야 하거나 API가 음수 값을 반환하도록 조정되면 어떻게 될까요?

Sentinel 값을 사용하는 것은 호출 코드의 복잡성을 증가시킵니다. 만약 호출자가 엄격하다면, Sentinel 값을 명시적으로 확인합니다:

CPP
int balance = AccountBalance();
if (balance == -5) {
  LOG(ERROR) << "account closed";
  return;
}
// 여기서 `balance`를 사용합니다.
클릭하여 더 보기

일부 호출자는 문서에 명시된 것보다 더 넓은 범위의 값을 확인할 수도 있습니다:

CPP
int balance = AccountBalance();
if (balance <= 0) {
  LOG(ERROR) << "where is my account?";
  return;
}
// 여기서 `balance`를 사용합니다.
클릭하여 더 보기

그리고 일부 호출자는 Sentinel 값을 완전히 무시하고, 실제로 발생하지 않는다고 가정할 수도 있습니다:

CPP
int balance = AccountBalance();
// 여기서 `balance`를 사용합니다.
클릭하여 더 보기

Sentinel 값의 문제점

위의 예는 Sentinel 값을 사용할 때 발생하는 일반적인 문제를 보여줍니다. 그 외에도 다음과 같은 문제가 있습니다:

특정 Sentinel 값을 확인하지 않는 것은 일반적인 버그입니다. 최상의 경우, 확인되지 않은 Sentinel 값을 사용하는 것은 런타임에 시스템을 즉시 충돌시킬 것입니다. 더 자주 발생하는 경우는, 확인되지 않은 Sentinel 값이 시스템을 통해 계속 전파되어 잘못된 결과를 초래하는 것입니다.


Sentinel 값 대신 std::optional 사용하기

특별한 값을 사용하는 대신 std::optional을 사용하여 유효하지 않거나 사용할 수 없는 정보를 나타내세요.

CPP
// 계좌 잔액을 반환하거나 계좌가 닫힌 경우 std::nullopt를 반환합니다.
std::optional<int> AccountBalance();
클릭하여 더 보기

AccountBalance()의 새 버전을 호출하는 호출자는 이제 반환된 값 내부에 잠재적인 잔액이 있는지 명시적으로 확인해야 하며, 결과가 유효하지 않을 수 있음을 신호로 전달합니다. 추가 문서화가 없으면, 호출자는 이 함수가 반환할 수 있는 유효한 int 값을 특정 Sentinel 값 없이 가정할 수 있습니다. 이 단순화는 호출 코드의 의도를 더 명확히 합니다.

CPP
std::optional<int> balance = AccountBalance();

if (!balance.has_value()) {
  LOG(ERROR) << "Account doesn't exist";
  return;
}
// 여기서 `*balance`를 사용합니다.
클릭하여 더 보기

다음에 시스템 내에서 Sentinel 값을 사용하고 싶은 유혹이 생긴다면, 대신 적절한 std::optional을 사용하는 것을 강력히 고려해보세요.


관련 자료

라이선스

저작자: Jaehun Ryu

링크: https://jaehun.me/posts/abseil-tip-171-sentinel-%EA%B0%92-%ED%94%BC%ED%95%98%EA%B8%B0/

라이선스: CC BY 4.0

이 저작물은 크리에이티브 커먼즈 저작자표시 4.0 국제 라이선스에 따라 이용할 수 있습니다. 출처를 밝히면 상업적 목적을 포함해 자유롭게 이용 가능합니다.

댓글

검색 시작

검색어를 입력하세요

↑↓
ESC
⌘K 단축키