주간 팁 #45: 플래그를 피하라, 특히 라이브러리 코드에서
최초 게시일: 2013년 6월 3일
작성자: Titus Winters
“내 코드의 동작이 전역 변수로 제어되기를 바란다. 이 변수는 코드만으로는 값이 예측되지 않으며, 사용 기록이 불완전하고, 코드를 통해 제거하는 데 큰 어려움이 따른다.” — 아무도 그런 말을 하지 않는다.
프로덕션 코드, 특히 라이브러리에서 플래그를 사용하는 것은 실수입니다. 정말 필요한 경우가 아니라면 플래그를 사용하지 마세요. 이 점을 분명히 밝힙니다.
플래그는 전역 변수입니다. 하지만 더 나쁩니다. 플래그 값은 코드를 읽는 것만으로 알 수 없습니다. 플래그는 초기화 시 설정될 뿐만 아니라, 실행 중에 임의로 변경될 수도 있습니다. 서버가 바이너리에서 실행되는 경우, 플래그 값이 주기적으로 변경되지 않을 것이라는 보장이 없으며, 변경 시 알림이 없고, 변경을 감지할 수단도 없습니다.
만약 여러분의 프로덕션 환경이 모든 바이너리 실행을 직접 기록하고 해당 로그를 저장한다면 훌륭합니다. 하지만 대부분의 환경은 그렇게 동작하지 않습니다. 특히 라이브러리 코드에서는 이러한 불확실성이 매우 해롭습니다. 특정 기능의 사용 여부를 어떻게 확인할 수 있을까요? 간단한 대답은: 확인할 수 없습니다.
플래그는 죽은 코드를 제거하기 어렵게 만듭니다. 백엔드 마이그레이션 중에 불필요한 빌드 의존성을 제거하고 역사상 가장 만족스러운 git rm
명령을 실행하는 것만으로 레거시 코드를 제거할 수 있을 것이라고 생각할 수도 있습니다. 그러나 이는 잘못된 생각입니다. 레거시 바이너리에 수백 개의 플래그가 정의되어 있고 프로덕션 코드에서 참조되고 있다면, 단순히 죽은 코드를 제거하는 것만으로도 릴리스 엔지니어에게 큰 문제를 야기할 수 있습니다. 많은 작업이 변경 이후 정상적으로 시작되지 않을 것입니다.
더 심각한 문제는 무엇일까요? 2012년 초에 Google에서 진행된 분석에 따르면, 대부분의 C++ 플래그는 데이터 보존 한계 내에서 실제로 값이 변경된 적이 없었습니다.
플래그가 적합한 경우
플래그는 특정 용도에서는 적합합니다. 예를 들어:
- 디버깅 시 플래그 기반 백트레이스 없이 작업하기는 어렵습니다.
- 적절히 관리되고 (나중에 정리되는) 기능 플래그는 정당한 사용입니다.
- SRE(Site Reliability Engineer)가 긴급 상황에서 조정해야 하는 설정용 플래그는 유용한 안전망입니다.
- 바이너리로 이름/값 입력을 전달하고
main()
에서만 사용하는 플래그는 위치 기반 매개변수보다 유지보수가 훨씬 용이합니다.
플래그 사용을 다시 생각하라
이러한 제한 사항에도 불구하고, 우리는 플래그 사용을 신중히 검토해야 할 때입니다. 라이브러리에 플래그를 추가하려는 유혹이 있을 때, 더 나은 방법을 찾아보는 데 시간을 투자하세요. 구성을 명시적으로 전달하세요. 이는 거의 항상 더 이해하기 쉽고 유지보수가 쉽습니다.
- 플래그 대신 컴파일 타임 상수를 사용하세요.
- 코드 리뷰에서 새로운 플래그를 발견하면 반대 의견을 제시하세요.
- 플래그 추가는 반드시 정당화되어야 합니다.
플래그는 간편하지만, 장기적으로는 코드 품질을 떨어뜨리고 유지보수를 어렵게 만듭니다. 신중히 사용하세요.