피처 플래그란: 코드베이스 관리 완벽 가이드
요약
피처 플래그는 새 배포 없이 런타임에 기능을 제어하는 if 문입니다. 타입별 수명, 안전한 롤아웃 절차, 기술 부채 방지, 기존 코드베이스에서 플래그 찾기 및 정리하는 법을 배우세요.
피처 플래그란 새로운 배포 없이 런타임에 코드의 특정 동작을 켜거나 끌 수 있는 조건문입니다. 이게 전부입니다. 실제로는 설정 파일, 데이터베이스 행, 또는 플래그 서비스에서 답을 받아오는 if 문이죠.
개념은 간단합니다. 하지만 저장소에 200개의 플래그가 있으면서 그것들을 관리하는 건 그렇지 않습니다. 이 가이드의 핵심은 바로 두 번째 부분입니다.
코드에서 피처 플래그는 어떻게 보이나요?
가장 최소한의 실용적인 버전입니다:
if (flags.isEnabled("new-checkout", { userId })) {
return renderNewCheckout();
}
return renderOldCheckout();두 코드 경로 모두 같은 빌드에 포함됩니다. 플래그 값은 재배포 없이 변경할 수 있는 곳에 있습니다: 환경 변수, JSON 파일, 테이블, 또는 호스팅된 서비스. 값을 바꾸면 다음 평가 때 동작이 바뀝니다.
이 분리가 핵심입니다. 배포는 코드를 서버에 올리는 것입니다. 릴리스는 사용자가 그것을 보게 하는 것입니다. 플래그는 이 두 이벤트를 분리하므로, main에 머지한다는 것이 더 이상 "모두가 지금 바로 이것을 얻는다"를 의미하지 않습니다.

팀이 피처 플래그를 왜 사용하나요?
5명에서 50명 규모의 실제 팀에서는 세 가지 이유가 계속 나옵니다.
미완성 작업을 안전하게 머지하세요. 플래그를 끈 상태로 반은 완성된 기능을 커밋하면, 브랜치가 3주간 살아있을 필요가 없습니다. 이것이 트렁크 기반 개발을 실현 가능하게 만듭니다.
단계적으로 롤아웃하세요. 내부 사용자를 위해 기능을 켜거나, 트래픽의 5%에만 켜거나, 모두에게 켭니다. 에러율이 상승하면 초 단위로 다시 끌 수 있습니다.
빠르게 무언가를 꺼두세요. 오전 2시에 결제 제공자가 오작동하면, 플래그를 통해 한 기능을 제한하는 것이 전체 릴리스를 롤백하는 것보다 빠릅니다.
이 중 어느 것도 벤더가 필요하지 않습니다. 플래그는 설정 테이블의 불린값일 수 있습니다. 백분율 롤아웃, 감시 추적, 엔지니어가 아닌 사람이 토글을 조작하는 기능이 필요할 때까지 플랫폼은 건너뛰세요.
피처 플래그의 네 가지 종류는 무엇인가요?
Pete Hodgson의 광범위하게 인용된 Martin Fowler 사이트의 feature toggles 기사는 플래그를 얼마나 오래 살아있는지, 얼마나 자주 결정이 바뀌는지에 따라 분류합니다. 이 분류들은 여전히 가장 명확한 정신 모델입니다.
릴리스(Release): 며칠에서 몇 주 정도, 엔지니어가 토글합니다. 예: 미완성 체크아웃 재설계 숨기기.
실험(Experiment): 수 주, 상품 담당자와 데이터 팀이 토글합니다. 예: 두 가지 가격 책정 페이지의 A/B 테스트.
운영(Ops): 시간에서 영구적, 온콜이 토글합니다. 예: 느린 추천 서비스의 킬 스위치.
권한(Permission): 몇 달에서 몇 년, 상품 담당자와 지원팀이 토글합니다. 예: 베타 접근 또는 프리미엄 전용 기능.
수명 열이 가장 중요합니다. 릴리스를 넘어서는 릴리스 플래그는 아직 찾지 못한 버그입니다. 정리 스프린트에서 삭제되는 권한 플래그는 아직 겪지 못한 장애입니다.
플래그를 만들 때 이름과 종류를 지정하세요. 6개월 후에는 아무도 "new-nav-v2"가 어떤 종류인지 기억하지 못할 것입니다.

사용자에게 피해 없이 플래그를 어떻게 롤아웃하나요?
단순한 순서가 가장 잘 작동합니다.
플래그를 끈 상태로 코드를 배포합니다. 아무것도 바뀌지 않았는지 확인합니다.
여러분의 팀에만 프로덕션에서 활성화합니다. 하루 동안 사용해봅니다.
사용자의 1%에서 5%에게 활성화합니다. 사용자별로 고정하여 아무도 세션 중에 변형 사이를 오가지 않습니다.
에러율, 레이턴시, 그리고 하나의 비즈니스 지표를 관찰합니다. 대시보드를 바라보면서가 아니라 시작하기 전에 임계값을 정하세요.
100%로 확대하고, 정의된 기간 동안 기다린 후, 플래그를 제거합니다.
5단계가 팀들이 건너뛰는 부분입니다. 이것이 여러분이 생각하는 것보다 훨씬 더 비용이 듭니다.
평가에 대한 실용적인 조언: 플래그 읽기를 저렴하고 장애 안전하게 만드세요. 플래그 서비스가 다운되면, 코드에는 기본값이 필요합니다. 플래그별로 목적에 맞게 기본값을 선택하세요. 킬 스위치는 "안전하게" 실패해야 하고, 새 기능은 "꺼진" 상태로 실패해야 합니다.
피처 플래그는 왜 기술 부채가 되나요?
모든 플래그는 코드의 분기입니다. 두 개의 플래그는 4개의 가능한 경로를 만들고, 10개는 1,024개를 만들며, 여러분은 그 중 소수만 테스트했을 가능성이 높습니다. GrowthBook의 플래그 부채 엔지니어링 가이드는 약 75%의 토글 컴포넌트가 도입 후 49주까지 코드베이스에 남아있었다는 연구를 인용하며, 대부분의 개발자는 제거할 계획이었다고 말했습니다.
Hodgson은 같은 Fowler 기사에서 이를 잘 표현합니다: 현명한 팀은 토글을 수용비를 갖는 인벤토리로 취급하고, 그 인벤토리를 낮게 유지하기 위해 작업합니다.
고전적인 공포 이야기는 2012년 Knight Capital입니다. 은퇴한 기능의 플래그가 한 서버의 기존 코드가 여전히 살아있는 동안 새로운 동작에 재사용되었습니다. 그 불일치는 1시간 미만에 대략 4억 6천만 달러의 손실에 기여했습니다. 여러분의 낡은 플래그는 아마도 그렇게 하지 않을 것입니다. 더 조용한 일을 할 것입니다: 아무도 존재하지 않는다고 알지 못했던 분기를 깨뜨리는 리팩터링, 또는 새 직원이 두 체크아웃 경로 중 어느 것이 실제인지 파악하는 데 오후를 보내는 것.

기존 코드베이스에서 모든 플래그를 어떻게 찾나요?
이것은 벤더 문서가 건너뛰는 질문이며, 대부분의 팀이 막히는 부분입니다. 플래그 대시보드는 무엇이 설정되어 있는지 알려줍니다. 각 플래그가 코드의 어디에서 읽히는지, 또는 "끄기" 플래그 뒤의 코드 경로가 여전히 도달 가능한지는 알려주지 않습니다.
저렴한 방법으로 시작하세요:
# wrapper를 통해 읽혀지는 모든 리터럴 플래그 키
rg -n 'isEnabled\("' src/ | sort
# 정의되었지만 참조되지 않는 플래그
comm -23 <(jq -r 'keys[]' flags.json | sort) <(rg -o 'isEnabled\("([^"]+)"' -r '$1' src/ | sort -u)이것은 빨리 부러집니다. 문자열 연결로 만들어진 플래그 키는 grep에서 표시되지 않습니다. 헬퍼 함수를 통해 전달된 플래그는 호출 지점을 숨깁니다. 모노레포와 다중 저장소 설정은 같은 키를 세 개의 서비스에서 읽을 수 있기 때문에 문제를 곱합니다.
도구로 코드를 읽는 것이 도움이 되는 곳입니다. 저장소를 이해하는 코드 검색 도구는 "new-checkout이 어디에서 평가되고 결과에 무엇이 의존하는가?"를 오후의 grep 세션 대신 한 번의 쿼리로 답할 수 있습니다. Cursor와 GitHub Copilot은 한 저장소 내에서 이를 합리적으로 처리합니다. 여러 저장소에 걸쳐서는 모든 저장소를 아우르는 인덱스가 필요하며, 이것이 우리가 codebasechat을 만든 사례입니다.
이성적인 플래그 정리 프로세스는 어떻게 보이나요?
제거를 나중의 잡일이 아니라 일의 일부로 취급하세요.
플래그와 함께 제거 티켓을 만드세요. 플래그 설명에 링크하세요. 티켓이 없으면 플래그는 배포되지 않습니다.
모든 비영구 플래그에 소유자와 만료일을 설정하세요. 약 90일 동안 변경이 없으면 검토의 합리적인 트리거입니다.
두 개의 풀 요청에서 제거하세요. 먼저 플래그 체크를 삭제하고 승리한 경로를 유지합니다. 그 다음 죽은 분기와 그 테스트를 삭제합니다. 작은 diff는 리뷰 가능한 diff입니다.
타임 폭탄 테스트를 추가하세요. 릴리스 플래그가 만료일을 통과할 때 실패하는 테스트는 좋은 의도를 빨간색 빌드로 바꿉니다.
총액을 상한하세요. 40개의 활성 플래그가 있고 상한이 40이면, 하나를 추가하는 것은 하나를 제거해야 한다는 의미입니다.
정적 분석이 여기서도 도움이 됩니다. CodeScene 같은 도구는 가장 복잡한 조건부 논리를 담은 파일을 보여주며, 이것은 보통 오래된 플래그가 모여있는 곳입니다. SonarQube는 체크를 제거한 후 도달할 수 없고 죽은 코드를 표시합니다.
플래그 뒤의 코드를 어떻게 테스트하나요?
테스트는 아무도 예산을 잡지 않는 부분입니다. 플래그당 두 개의 경로로, 테스트 제품군은 둘 다 커버해야 하며, 최소한 위험한 동작을 보호하는 플래그는 그렇습니다.
실용적으로 유지하세요. 라이브 서비스를 읽는 대신 플래그 값을 주입하여 단위 테스트에서 모든 릴리스 플래그의 켜짐과 꺼짐 상태를 테스트합니다. 기본 프로덕션 구성에 대한 하나의 엔드-투-엔드 제품군을 실행하세요. 그러면 사용자가 오늘 얻는 것입니다. 그 다음 릴리스할 기능에 대해 플래그를 켠 상태로 두 번째 통과를 실행합니다.
모든 조합을 테스트하지 마세요. 10개의 플래그로는 할 수 없습니다. 대신 플래그를 독립적으로 유지하세요: 다른 플래그도 켜져 있을 때만 동작을 변경하는 플래그는 설계 냄새이며, 정리할 첫 번째 것입니다.
신입 엔지니어들이 플래그에 대해 뭘 잘못 이해하나요?
주니어들은 같은 세 가지 실수를 하는 경향이 있으며, 각각을 리뷰에서 저렴하게 예방할 수 있습니다.
플래그 중첩. 하나의 플래그가 다른 플래그 안에 있으면 두 플래그가 모두 켜져 있을 때만 존재하는 경로를 만듭니다. 명확한 이름의 단일 플래그를 요청하세요.
플래그 이름에 논리를 넣기. "show-new-nav-to-premium-users-in-eu" 같은 키는 플래그 서비스에 속하는 타게팅 규칙을 문자열에 인코딩합니다.
기본값을 잊기. 플래그 조회가 실패하면 어떻게 되나요? 저자가 풀 요청 설명에 답을 작성하게 하세요.
새 직원의 첫 두 주는 정확히 그들이 소유자가 없는 오래된 플래그를 마주치는 때입니다. 각 항목에 대한 종류, 소유자, 제거 날짜가 있는 짧은 플래그 레지스트리는 몇 시간의 질문을 절약합니다.
피처 플래그를 언제 건너뛰어야 하나요?
플래그는 무료가 아니므로 다음의 경우 건너뛰세요:
변경이 작고, 되돌릴 수 있으며, 배포 한 번으로 롤백할 수 있는 경우. 플래그는 이득 없이 코드 경로를 추가합니다.
변경이 플래그가 숨길 수 없는 방식으로 데이터베이스 스키마에 닿을 때. 대신 확장-수축 마이그레이션을 사용하세요.
팀에 플래그를 제거하는 프로세스가 없을 때. 먼저 그것을 고치거나, 미래의 가독성에 빌려주는 것입니다.
변경이 위험하고, 사용자 관련이며, 재배포로 되돌리기 어려울 때 망설임 없이 사용하세요. 결제 흐름, 인증 변경, 그리고 뒤에 데이터 마이그레이션이 있는 모든 것이 해당합니다.
10명 팀에서는 실제로 뭘 하나요?
부울값과 하나의 래퍼 함수를 설정에서 시작하여, 모든 플래그 읽기가 한 곳을 통해 가도록 합니다. 그 단일 병목은 플래그 목록을 grepable하고, 감사할 수 있으며, 나중에 호스팅된 서비스로 쉽게 마이그레이션할 수 있게 만듭니다.
각 플래그를 종류별로 지정하고, 소유자를 지정하고, 첫 날에 제거 티켓을 제출하세요. 월간으로 10분 동안 목록을 검토합니다. 2주 동안 100%에 있었던 플래그들을 삭제합니다.
피처 플래그는 대출입니다. 위험한 릴리스를 구할 때 가져가고, 이자가 다음 리팩터에 나타나기 전에 갚으세요.