Feature Flag
코드 배포와 기능 활성화를 분리하는 기법. 런타임에 기능을 켜고 끌 수 있어 안전한 배포와 점진적 롤아웃을 가능하게 함. 플래그가 쌓이면 코드베이스가 복잡해짐. 출시 완료된 Release Toggle은 반드시 제거. "플래그 청소 티켓"을 배포 직후 바로 생성하는...
목차 보기22
1. Overview
피처 플래그 물리법칙(Feature Flag & Toggle)은 "코드를 배포하는 것(Deploy)"과 "기능을 고객에게 노출하는 것(Release)"을 영원히 분리해 버리는, 코드 레벨의 통제권 역전이자 if문 하나로 수천만 명의 트래픽을 제어하는 다이나믹 스위칭 역학을 해부합니다.
학습자는 미완성된 기능 때문에 브랜치를 feature/A로 파놓고 두 달 동안 합치지 못해 썩어가는 브랜치 지옥을 뜯어보고, 미완성 코드를 당당하게 운영 서버(main)에 합치면서도 스위치를 꺼(OFF) 고객에게 숨기는 **트렁크 기반 개발(Trunk-based Development)**을 장악합니다. 나아가 코드 재배포 없이 실시간으로 기능을 1% 유저에게만 켜주는 **카나리아 릴리즈(Canary Release)**와, 피처 플래그가 쌓여서 생기는 기술 부채(Technical Debt)의 관리 파이프라인 역량을 확보합니다.
2. Scope & Boundaries
In-Scope
- Deploy vs Release: 인프라 배포와 비즈니스 기능 오픈의 완벽한 디커플링(Decoupling).
- Toggle Types: Release Toggles, Experiment Toggles (A/B Test), Ops Toggles, Permission Toggles.
- Trunk-based Development: 롱 리브드 브랜치(Long-lived branch) 폐기와 매일 10번 병합하는 극강의 CI 전략.
- Lifecycle Management: 다 쓴 플래그(if문)를 지우지 않으면 발생하는 스파게티 코드와 부채 탕감 거버넌스.
Out-of-Scope
- Canary Deployment 인프라 레벨 통제: K8s Istio를 통한 트래픽 라우팅 → 09-05-04 CI/CD Pipeline 영역으로 위임 (여기는 인프라가 아닌 '로직/코드 레벨'의 통제에 집중).
- A/B 테스트 통계학: T-test, P-value 등 통계적 유의성 검증 수학 → 01. Data & Analytics 모듈로 분리.
Boundaries
- Canary Deployment vs Feature Flag: 두 개의 서버 V1과 V2를 띄우고 로드밸런서가 트래픽을 10%만 V2(신규)로 찢어 보내면 '카나리아 배포(인프라)'입니다. 반면 서버는 V1 하나만 떠 있는데, 소스코드 안의
if(enable_new_feature)조건을 유저의 10%에게만true로 열어주면 '피처 플래그(코드)'입니다. 인프라를 늘릴 것인가, 로직 스위치를 달 것인가의 경계를 명확히 긋습니다.
3. Counterexample
- 브랜치의 부패 (Feature Branch Hell): 두 달짜리 거대한 결제 개편 기능을 만들기 위해
feature/payment_v2브랜치를 땄습니다. 두 달 뒤, 메인 브랜치는 다른 팀원들에 의해 1,000번이나 커밋(변경)되었습니다. 이제 결제 브랜치를 메인에 합치려니 충돌(Conflict)이 500군데 발생합니다. 기능을 숨길 스위치가 없어서, 완벽히 다 만들 때까지 합치지도 못하고 썩혀둔 구시대의 참사입니다. - Knight Capital 4,500억 원 증발 (Dead Code): 2012년 나이트 캐피탈은 옛날에 만들어두고 안 쓰는 죽은 코드(Dead Code) 스위치를 실수로 켜(ON)버렸습니다. 코드는 미친 듯이 시장에 고가 매수/저가 매도 주문을 난사했고, 회사는 45분 만에 4억 4천만 달러(약 4,500억 원)를 날리고 파산했습니다. 피처 플래그(스위치)를 쓴 뒤 청소하지 않고 방치한 기술 부채가 불러온 역사상 최악의 소프트웨어 파국입니다.
4. Prerequisites
- 버전 관리 시스템 (Basic): Git, Branching, Merge Conflict. (09-05 DevOps Basic)
- CI/CD 파이프라인 (Basic): 자동화된 빌드와 배포의 차이. (09-05-04 CI/CD)
5. Learning Map
6. Learning Topics
Basic
Core Topic 01: 배포와 릴리즈의 분리 (Deploy != Release)
- Why to Learn: "이번 주 금요일 밤 12시에 배포하고 즉시 오픈합시다"라는 낡고 위험한 빅뱅 릴리즈를 버리고, 수요일 대낮에 미리 배포해두고 금요일 밤에는 버튼만 딸깍 누르는 심리적 평화를 얻기 위함입니다.
- What to Learn:
- Concepts: Deployment (배포), Release (출시), Feature Flag / Toggle, Decoupling.
- Skills: 애플리케이션 코드 곳곳에
if (feature_flag.is_on('NEW_PAYMENT')) { 신규로직 } else { 기존로직 }을 감싸, 배포를 하더라도 플래그가 OFF면 고객은 100% 기존 로직만 타도록 통제하기.
- How to Learn:
- 1단계: 강결합의 공포: 전통적으로 코드 배포 = 기능 오픈입니다. 서버가 켜지는 순간 신규 기능이 세상에 노출됩니다. 에러가 나면 코드 수정, 빌드, 재배포까지 30분이 걸립니다. 고객은 30분 동안 마비됩니다.
- 2단계: 절단 (Decoupling): 피처 플래그를 달면 배포와 오픈이 완벽히 분리됩니다. 배포는 평일 낮 한가할 때 미리 100번이고 해둡니다. 스위치가 꺼져있으니 고객은 모릅니다.
- 3단계: 딸깍 (Instant Release): 약속한 론칭 시각이 되면, 개발자가 코드를 재배포하는 게 아니라 기획자가 대시보드(LaunchDarkly 등)에서 스위치를 'ON'으로 켭니다. 1밀리초 만에 신규 로직이 활성화됩니다. 문제가 생기면 즉시 'OFF'로 꺼서 1밀리초 만에 롤백하는 극강의 방어술을 해부합니다.
- Implement: 피처 플래그 분기 코드 모사.
Action:인프라(배포)의 영역이 비즈니스(출시)의 영역으로 우아하게 넘어가는 권력 이동 렌더링.JAVASCRIPTif (flagService.isEnabled('v2-ui')) { return renderNewUI(); // 스위치 ON (1초 만에 롤백 가능) } else { return renderOldUI(); // 스위치 OFF (안전지대) }
Recommended
Core Topic 02: 미완성 코드의 합병 (Trunk-based Development)
- Why to Learn: 브랜치를 수십 개씩 파놓고 3달 뒤에 합치려다 충돌(Merge Conflict)로 밤을 새우는 참사를 막고, 모든 팀원이 매일 오직
main브랜치 하나만 바라보며 개발하는 극한의 애자일을 달성하기 위함입니다. - What to Learn:
- Concepts: Trunk-based Development (트렁크 기반 개발), Feature Branching Hell, CI (지속적 통합), Dark Launch.
- Skills: 미완성된 껍데기 함수(결제 버튼 등)를 만들고 피처 플래그로 완전히 숨긴(Dark Launch) 다음, 당당하게
main브랜치에 하루에 10번씩 병합(Merge)하여 충돌을 원천 차단하기.
- How to Learn:
- 1단계: 격리의 모순: 남의 코드와 섞이는 게 두려워 브랜치를 오래 유지(Long-lived)할수록, 나중에 합칠 때 발생하는 고통은 제곱으로 커집니다.
- 2단계: 피처 플래그의 보호막: "미완성된 코드는 실서버에 나가면 안 된다"는 상식을 뒤집습니다. 스위치(Flag)로 꺼두면 그 코드는 '죽은 코드'로 취급되어 실행되지 않습니다.
- 3단계: 트렁크 기반 개발: 이제 모든 개발자는 하루 단위로 미완성 코드를
main(트렁크)에 때려 박습니다. 다른 팀원들이 짠 코드가 내 로컬에 실시간으로 반영되므로 '병합 지옥'이 수학적으로 소멸합니다. 완성되지 않은 기능을 운영 서버에 숨긴 채 점진적으로 개발해 나가는 경이로운 CI/CD 가속술을 뜯어봅니다.
- Implement: 롱 리브드 브랜치 vs 트렁크 기반 개발 렌더링.
구시대:feature/A1달 고립 → Merge 시 1,000줄 충돌 → 해결에 2일 소요.피처 플래그: 빈 깡통 함수A()작성 +Flag=OFF→ 즉시main병합. 내일은A()안에 10줄 추가 → 즉시 병합. 브랜치의 수명을 '하루 이내'로 압살해 버리는 시각화.
Practical
Core Topic 03: 4차원의 스위치 (The 4 Dimensions of Toggles)
- Why to Learn: 스위치라고 해서 다 같은 스위치가 아닙니다. 2주 뒤에 지울 스위치(Release)와 평생 안고 가야 할 킬스위치(Ops)를 구별하여 잘못된 관리를 막기 위함입니다.
- What to Learn:
- Concepts: Release Toggles (출시 스위치), Experiment Toggles (A/B 테스트), Ops Toggles (운영 킬스위치), Permission Toggles (권한 제어).
- Skills: "장바구니 로직 개편"은 Release Toggle로 짧게 쓰고 버리며, "결제 시스템 장애 시 외부 PG사 셧다운"은 Ops Toggle로 시스템 깊숙이 평생 유지하는 매트릭스 분기하기.
- How to Learn:
- 1단계: Release Toggles: 기능 출시용. 며칠 뒤 100% 유저에게 기능이 완전히 켜지면 수명이 다합니다. 즉시 코드에서
if문을 지워버려야(Cleanup) 합니다. - 2단계: Experiment Toggles: A/B 테스트용. 유저 50%는 A버튼, 50%는 B버튼을 보여줍니다. 데이터 분석이 끝나고 위너(Winner)가 결정되면 역시 수명이 다하므로 지워야 합니다.
- 3단계: Ops Toggles: 블랙프라이데이 때 트래픽이 폭주해서 서버가 터질 것 같으면, "추천 상품 연산 로직"만 일시적으로 꺼버리는(Kill Switch) 생존용 토글입니다. 이건 평생 유지됩니다.
- 4단계: Permission Toggles: VIP 유저나 관리자에게만 특정 프리미엄 기능을 열어줍니다. 유저의 속성(Attribute)에 따라 동작하며 역시 영구적으로 유지됩니다. 토글의 수명(Lifetime)과 동적 성질에 따른 완벽한 분류법을 해부합니다.
- 1단계: Release Toggles: 기능 출시용. 며칠 뒤 100% 유저에게 기능이 완전히 켜지면 수명이 다합니다. 즉시 코드에서
- Implement: 킬스위치(Ops Toggle) 방어 메커니즘 도출.
위기 상황: 결제 서버 트래픽 10배 폭증 (CPU 99%).Action:is_enabled('RECOMMENDATION_ENGINE')스위치를 대시보드에서 긴급 OFF.결과: 홈 화면에서 추천 상품을 그리기 위한 무거운 DB 쿼리들이 즉각 생략됨. 핵심 로직(결제)을 살리기 위해 부가 기능의 숨통을 코딩 없이 끊어버리는 오퍼레이션 시각화.
Advanced
Core Topic 04: 스위치 청소 거버넌스 (The Cleanup Governance)
- Why to Learn: 피처 플래그를 편하다고 막 쓰다가, 코드 안에 3년 전
if문 100개가 누적되어 아무도 건드릴 수 없는 썩은 기술 부채로 전락해 4,500억 원(나이트 캐피탈)을 날려먹는 걸 막기 위함입니다. - What to Learn:
- Concepts: Technical Debt (기술 부채), Stale Flags, Cleanup Lifecycle, Feature Flag Management System.
- Skills: 기능이 100% 릴리즈 된 지 2주가 지난 '좀비(Stale) 플래그'를 자동으로 찾아내어 슬랙(Slack)으로 삭제 경고를 날리고, 코드에서
else문구를 제거하는 리팩터링 룰 강제하기.
- How to Learn:
- 1단계: 스파게티의 탄생: 플래그를 달면 필연적으로
if (신규) else (기존)구조가 생깁니다. 분기가 2개(2차원)로 늘어납니다. 만약 플래그가 3개 겹치면? 2^3 = 8차원의 복잡도가 생겨 테스트가 불가능해집니다. - 2단계: 부채의 이자: 100% 릴리즈되어 더 이상 'OFF'로 돌릴 일이 없는 플래그는 즉시 삭제해야 합니다. 방치하면 나중에 신입 개발자가 "어? 이 조건문은 뭐지?" 하며 건드렸다가 대형 장애가 터집니다.
- 3단계: 자동화된 청소 루프: 지라(Jira) 티켓에 "플래그 청소" 하위 테스크를 의무적으로 강제합니다. 코드를 짤 때 아예 플래그 만료일(Expiration Date)을 설정하고, 기한이 지나면 빌드(CI)를 뻗게 만들어 개발자가 억지로라도 코드를 지우게 만드는 냉혹한 기술 부채 탕감 시스템을 뜯어봅니다.
- 1단계: 스파게티의 탄생: 플래그를 달면 필연적으로
- Implement: 플래그 탕감 라이프사이클 시각화.
Day 1: 브랜치 병합 (Flag = 0% 노출).Day 7: 런칭 완료 (Flag = 100% 노출).Day 21 (경고): 런칭 후 2주 경과. CI 시스템이 "Stale Flag Detected" 슬랙 알람 발송.Day 22 (청소): 개발자가if분기를 날리고 신규 로직(True)만 남긴 후 커밋. 복잡도가 다시 1차원으로 수렴하는 클린 아키텍처 렌더링.
7. Terminology
8. References
Primary
- [P1] CS2023 - Software Engineering (SE) - Software Release and Deployment (Feature toggles, CI/CD)
- [P5] SFIA - Programming/software development (PROG) - Feature flag implementation
Secondary
- [Continuous Delivery] Jez Humble - Trunk-based development and branching strategies
- [MartinFowler.com] - FeatureToggles (by Pete Hodgson)
Industry
- [LaunchDarkly Blog] - The Ultimate Guide to Feature Flags
- [GitLab Docs] - Feature flags and Trunk-based development
9. Final Checklist
Primary
- 서버에 코드를 올리는 "배포(Deployment)"와 고객에게 새로운 기능을 노출하는 "출시(Release)"의 개념을 명확히 분리하고, 피처 플래그가 이 둘의 강결합을 어떻게 도끼로 끊어내는지 논증할 수 있는가?
- 미완성된 기능 때문에 브랜치를 장기간 격리했다가 병합 지옥(Merge Hell)을 겪는 대신, 미완성 코드를 플래그로 감춰 매일
main브랜치에 합치는 '트렁크 기반 개발(Trunk-based Development)'의 속도전 원리를 설명할 수 있는가?
Secondary
- 신기능을 런칭하고 곧바로 지워버려야 하는 '출시 토글(Release Toggle)'과, 블랙프라이데이 트래픽 폭주 시 일시적으로 부가 기능을 꺼버리기 위해 영구히 유지해야 하는 '운영 토글(Ops Toggle)'의 생명주기(Lifecycle) 차이를 분기할 수 있는가?
- 카나리아 배포(Canary Deployment)가 로드밸런서를 통한 '인프라/서버 레벨'의 트래픽 라우팅 통제인 반면, 피처 플래그(Feature Flag)를 활용한 1% 점진적 롤아웃이 '로직/코드 레벨'의 유저 세그멘테이션 통제임을 명확히 구분하여 설계할 수 있는가?
Industry
- 2012년 4,500억 원의 손실을 낸 나이트 캐피탈(Knight Capital) 사태를 예시로 들어, 쓰임이 다한 오래된 피처 플래그(Stale Flag)를 삭제(Cleanup)하지 않고 방치했을 때 폭증하는 코드의 다차원적 복잡도와 기술 부채의 파국을 경고할 수 있는가?
- 100% 롤아웃된 피처 플래그의 삭제를 개발자의 양심에 맡기지 않고, 지라(Jira) 티켓과 CI/CD 파이프라인에 만료일(Expiration Date) 알람을 연동하여 강제적으로 리팩터링 및
else블록을 탕감(Cleanup)하는 팀 거버넌스를 구축할 수 있는가?
태그
feature-flagdeploymenttrunk-based-developmentexperimentationreleasesoftware-engineeringfeatureflagsoftwareengineeringtrunkbaseddev-opsreliabilitydelivery