Abseil Tip 130 네임스페이스 이름 지정

주간 팁 #130: 네임스페이스 이름 지정

원래 게시일: 2017-02-17
작성자: Titus Winters (titus@google.com)

정확한 이름 지정은 보는 이의 독창성을 제한한다.
— 피에르 보나르(Pierre Bonnard)

Google C++ 스타일 가이드 초기에는 네임스페이스 이름 지정에 대한 지침이 포함되어 있었습니다. 이 지침은 일반적으로 다음과 같이 요약될 수 있습니다:

네임스페이스는 패키지 경로에서 파생됩니다.

이는 Java 패키지 이름 지정 요구사항의 영향을 받아 합리적으로 보였습니다. C++에서 고유한 심볼을 식별하고 네임스페이스 선택에서 일관성을 유지하기 위해 도입된 것입니다.
그러나 시간이 지나면서 이 방식이 C++에서는 문제가 있다는 것을 깨닫게 되었습니다.


이름 검색(Name Lookup)

C++의 이름 검색 방식과 Java와의 차이점을 살펴보겠습니다.

C++의 이름 검색:

namespace foo {
namespace bar {
void f() {
  Baz b;
}
}
}
  • C++에서는 미수식 이름(Baz)에 대한 검색이 확장된 범위에서 수행됩니다:
    1. f() 함수 내부
    2. bar 네임스페이스
    3. foo 네임스페이스
    4. 전역 네임스페이스

Java의 이름 검색:

public void f() {
  com.google.foo.bar.Baz b = new com.google.foo.bar.Baz();
}
  • Java에서는 미수식 이름이 없습니다. 모든 이름은:
    1. 명시적으로 수식된 이름(예: com.google.foo.bar.Baz)이거나,
    2. import를 통해 가져옵니다.

Java에서는 부모 패키지나 하위 패키지를 자동으로 검색하지 않습니다. 이는 Java와 C++의 네임스페이스 설계에서 본질적인 차이를 만듭니다.


문제점

1. 깊은 네임스페이스 중첩의 문제

C++에서는 미수식 이름을 사용하는 경우가 많습니다(std::unique_ptr 대신 unique_ptr).
하지만 깊게 중첩된 네임스페이스에서는 이름 충돌이 발생할 가능성이 커집니다.
예를 들어, std::unique_ptr을 사용할 때 다음 네임스페이스들 중 어느 것이 참조되는지 예측할 수 없습니다:

  • ::std::unique_ptr
  • ::division::std::unique_ptr
  • ::division::section::std::unique_ptr
  • ::division::section::team::std::unique_ptr

2. 잘못된 심볼 참조

검색이 하위 네임스페이스에서 시작하여 일치하는 첫 번째 심볼에서 멈추므로, 예기치 않은 심볼이 참조될 수 있습니다.
이로 인해 컴파일 오류가 발생하거나 런타임에서 호환되지 않는 API가 호출되어 오류가 발생할 수 있습니다.


해결 방안

이 문제를 해결하려면 두 가지 원칙을 따르는 것이 중요합니다:

  1. 최상위 네임스페이스의 이름 충돌 방지:
    • 하위 네임스페이스가 상위 네임스페이스 이름과 충돌하지 않도록 합니다.
  2. 미수식 이름 사용 최소화:
    • 네임스페이스 밖의 이름은 항상 완전히 수식합니다.

3가지 접근법

  1. 모든 이름을 완전히 수식:
    • ::std::unique_ptr처럼 항상 네임스페이스를 완전히 명시.
    • 이는 안전하지만 매우 장황하여 비현실적입니다.
  2. 네임스페이스 중복을 자동으로 탐지하는 도구 개발:
    • 새 네임스페이스 추가 시 기존 네임스페이스와의 충돌 여부를 검사.
  3. 최상위 네임스페이스를 단일화:
    • 각 프로젝트별로 단일 최상위 네임스페이스를 사용(예: absl).
    • 이 접근법은 충돌 가능성을 줄이고, 이름 지정의 간결성을 유지.

Google 스타일 가이드는 세 번째 방식을 권장합니다.


“작은 네임스페이스가 더 조직적이다”는 오해

작은 네임스페이스가 코드 구조를 더 체계적으로 만든다는 의견이 있습니다.
그러나 C++에서는 부모 네임스페이스에서의 이름 충돌 가능성이 작을수록 안전합니다.
즉, 네임스페이스를 세분화한다고 해서 안전해지는 것이 아니라, 오히려 충돌 가능성이 증가할 수 있습니다.


베스트 프랙티스

  1. 네임스페이스 고유성 관리:
    • 코드베이스에 등록된 네임스페이스 데이터베이스를 사용해 고유성을 확인.
  2. 최상위 네임스페이스 사용:
    • 각 프로젝트는 하나의 최상위 네임스페이스를 사용.
  3. 네임스페이스 별칭 사용 시 완전 수식:

결론

깊게 중첩된 네임스페이스 사용은 C++에서 이름 충돌과 유지보수성을 저하시킬 수 있습니다.
최상위 네임스페이스를 통일하고, 필요한 경우 완전 수식을 사용하여 충돌을 방지하는 것이 가장 좋은 접근법입니다.