주간 팁 #176: 출력 매개변수 대신 반환 값을 선호하세요

원래 TotW #176으로 2020년 3월 12일 게시됨
작성자: Etienne Dechamps
2020-04-06 업데이트됨

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


문제

다음과 같은 함수를 고려해봅시다:

CPP
// 주어진 doodad에서 foo 사양과 bar 사양을 추출합니다.
// 입력이 유효하지 않으면 false를 반환합니다.
bool ExtractSpecs(Doodad doodad, FooSpec* foo_spec, BarSpec* bar_spec);
클릭하여 더 보기

이 함수를 올바르게 사용하거나 구현하려면 개발자는 다음과 같은 질문을 해야 합니다:

이 질문들에 함수 시그니처만으로는 답할 수 없습니다. 또한 C++ 컴파일러가 이러한 계약을 강제하지 않습니다. 함수 주석은 도움이 될 수 있지만, 종종 충분하지 않습니다. 위 함수의 문서화는 대부분의 문제를 다루지 않고 있으며, “입력"이라는 의미조차도 모호합니다. 이는 doodad만을 의미하는지, 아니면 다른 매개변수까지 포함하는지를 명확히 하지 않습니다.

게다가, 이 접근법은 모든 호출 위치에 보일러플레이트 코드를 요구합니다. 호출자는 FooSpecBarSpec 객체를 미리 할당해야만 함수를 호출할 수 있습니다.

이 경우, 보일러플레이트를 제거하고 컴파일러가 계약을 강제할 수 있도록 간단히 해결할 수 있습니다.


해결책

다음과 같이 모든 문제를 해결할 수 있습니다:

CPP
struct ExtractSpecsResult {
  FooSpec foo_spec;
  BarSpec bar_spec;
};
// 주어진 doodad에서 foo 사양과 bar 사양을 추출합니다.
// 입력이 유효하지 않으면 nullopt를 반환합니다.
std::optional<ExtractSpecsResult> ExtractSpecs(Doodad doodad);
클릭하여 더 보기

이 새로운 API는 의미적으로 동일하지만, 오용하기 훨씬 어려워졌습니다:

이로 인해 버그 가능성이 줄어들고 개발자의 인지 부담이 줄어듭니다.

또 다른 장점은 함수가 더 쉽게 조합 가능하다는 것입니다. 예를 들어, SomeFunction(ExtractSpecs(...))와 같은 방식으로 간단히 사용할 수 있습니다.


주의사항


권장 사항

  1. 출력 매개변수 대신 반환값을 선호하세요. 이는 스타일 가이드와 일치합니다.
  2. 반환값이 없음을 표현하려면 std::optional과 같은 일반 래퍼를 사용하세요. 더 유연한 표현이 필요하다면 std::variant를 고려하세요.
  3. 구조체를 사용하여 함수에서 여러 값을 반환하세요.
    • 필요하다면 해당 함수의 반환값을 표현하기 위해 새로운 구조체를 만들어도 좋습니다.
    • std::pairstd::tuple 사용의 유혹에 저항하세요.

라이선스

저작자: Jaehun Ryu

링크: https://jaehun.me/posts/abseil-tip-176-%EC%B6%9C%EB%A0%A5-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98-%EB%8C%80%EC%8B%A0-%EB%B0%98%ED%99%98-%EA%B0%92%EC%9D%84-%EC%84%A0%ED%98%B8%ED%95%98%EC%84%B8%EC%9A%94/

라이선스: CC BY 4.0

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

댓글

검색 시작

검색어를 입력하세요

↑↓
ESC
⌘K 단축키