Abseil Tip 103 플래그는 전역 변수입니다

주간 팁 #103: 플래그는 전역 변수입니다

작성자: Matt Armstrong


.cc 파일에서 전역 범위로 플래그를 정의하세요. 해당 .h 파일에서는 최대 한 번만 선언하세요.


왜 헤더 파일에 선언할까요?

헤더 파일 사용은 대부분 우리에게 자연스러운 습관이지만, 그 이유를 잊었을 수도 있습니다. 헤더 파일을 사용하는 이유는 다음과 같습니다:

  1. 헤더 파일에 무언가를 선언하면 다른 곳에서 쉽게 #include할 수 있습니다. 프로그램 전체가 동일한 선언을 참조합니다.
  2. 동일한 엔티티를 정의하는 .cc 파일에서 해당 헤더 파일을 포함하면, 정의가 선언과 일치하는지 보장할 수 있습니다.
  3. 헤더 파일은 패키지의 공개 API를 문서화하는 역할을 합니다. 패키지의 공개 API 외부의 것을 사용하는 것은 좋지 않습니다.
  4. 엔티티를 재선언하는 대신 헤더 파일을 포함하면, 도구와 사람이 종속성 분석을 더 쉽게 수행할 수 있습니다.

Abseil 플래그도 다른 전역 변수처럼 취약합니다

링크 타임 에러 없이 잘못된 방법으로 플래그를 정의할 수 있습니다. 먼저, 다음과 같은 코드를 .cc 파일에 작성합니다:

// .cc 파일에서 --my_flag를 정의
ABSL_FLAG(std::string, my_flag, "", "My flag is a string.");

그리고 잘못된 플래그 선언을 다른 .cc 파일(예: 테스트 파일)에 작성합니다:

// 잘못된 선언: 타입이 std::string이어야 함
extern absl::Flag<int64> FLAGS_my_flag;

이 프로그램은 잘못된 형식이며, 발생하는 모든 결과는 정의되지 않은 동작의 결과입니다. 테스트 프로그램에서는 컴파일과 링크는 되었지만, 플래그에 접근할 때 크래시가 발생했습니다.


권장사항

명령줄 플래그를 전역 변수처럼 설계하세요.

  1. 플래그 사용을 피할 수 있다면 피하세요. 관련 팁을 참조하세요.
  2. 테스트를 작성하기 쉽게 하려고 플래그를 사용하는 경우, 프로덕션에서 이를 설정할 의도가 없다면 테스트 전용 API를 클래스에 추가하는 것을 고려하세요.
  3. 플래그를 비공개 정적 변수로 취급하는 것을 고려하세요. 다른 패키지가 플래그에 접근해야 한다면, 이를 함수로 감싸세요.
  4. 플래그를 네임스페이스 내부가 아닌 전역 범위에서 정의하세요. 이렇게 하면 플래그 이름이 충돌할 경우 링크 에러를 발생시킬 수 있습니다.
  5. 플래그가 여러 파일에서 참조된다면, 정의된 플래그에 대응하는 .h 파일에 한 번 선언하세요.
  6. ABSL_FLAG(type, ...) 매크로를 사용해 플래그를 정의하세요.

결론

플래그는 전역 변수입니다. 신중하게 사용하세요. 플래그를 사용할 때도 다른 전역 변수처럼 정의하고 선언하세요.