--- id: backend-feature-flags-deep title: Feature Flags 심화 — 점진 / A/B / 격리 category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [backend, feature-flags, ab-testing, vibe-coding] tech_stack: { language: "TS / GrowthBook / LaunchDarkly / Statsig", applicable_to: ["Backend", "Frontend"] } applied_in: [] aliases: [feature flag, ab test, gradual rollout, GrowthBook, LaunchDarkly, Unleash, kill switch] --- # Feature Flags Deep > 단순 on/off 가 아님. **% rollout / 사용자 segment / A/B 실험 / kill switch** 4종. SDK + dashboard. **GrowthBook (open) / LaunchDarkly / Statsig**. ## 📖 핵심 개념 - Targeting: 사용자 attribute 기반 (plan / country / cohort). - Rollout: 0% → 10% → 100% 점진. - A/B: variant 분배 + metric 측정. - Kill switch: emergency off. ## 💻 코드 패턴 ### GrowthBook (open source) ```ts import { GrowthBook } from '@growthbook/growthbook'; const gb = new GrowthBook({ apiHost: 'https://cdn.growthbook.io', clientKey: process.env.GB_KEY, attributes: { id: user.id, plan: user.plan, country: user.country, }, }); await gb.loadFeatures(); if (gb.isOn('new-checkout')) { // 새 flow } const variant = gb.getFeatureValue('button-color', 'blue'); // 'red' | 'blue' ``` ### LaunchDarkly ```ts import { init, type LDClient } from 'launchdarkly-node-server-sdk'; const ld: LDClient = init(process.env.LD_KEY); await ld.waitForInitialization(); const flag = await ld.variation('new-checkout', { key: user.id, custom: { plan: user.plan } }, false); ``` ### 점진 rollout ```yaml # Dashboard (GrowthBook) flag: new-checkout rules: - condition: { plan: 'pro' } rollout: 100% - condition: { country: 'US' } rollout: 10% - default: 0% ``` ### A/B 실험 ```yaml flag: button-color experiment: hypothesis: red converts higher than blue variants: - { id: blue, weight: 50 } - { id: red, weight: 50 } metric: checkout_completed ``` ```ts const color = gb.getFeatureValue('button-color', 'blue'); analytics.track('button_seen', { variant: color }); // CTA 클릭 시 analytics.track('checkout_completed', { variant: color }); ``` ### Kill switch ```ts if (gb.isOn('use-new-payment-provider')) { await stripeNew.charge(...); } else { await stripeOld.charge(...); } // 새 provider 가 깨지면 → flag off → 즉시 fallback ``` ### Stable hash (consistent variant) ```ts import { hash } from '@growthbook/growthbook'; // 같은 user.id = 항상 같은 variant const bucket = hash('exp-key', user.id, 1) * 100; const variant = bucket < 50 ? 'a' : 'b'; ``` → 사용자가 새로고침 해도 같은 variant 받음. ### Server-side vs client-side ```ts // Server: SDK 직접 호출 — 비밀 attribute 사용 가능 gb.isOn('admin-feature'); // 서버에서 // Client: rules 가 client 에 노출 → 비밀 정보 X // 또는 server-rendered (Next.js) const flags = await gb.evaluateAll(); return { props: { flags } }; ``` ### Type-safe flags ```ts type Flags = { 'new-checkout': boolean; 'button-color': 'blue' | 'red' | 'green'; 'max-items': number; }; function flag(key: K): Flags[K] { return gb.getFeatureValue(key, defaults[key]) as Flags[K]; } ``` ### Cleanup (가장 어려움) ```ts // 모든 flag = TODO 폴더 // "100% rollout 후 14일 → 코드 cleanup" // CI 가 오래된 flag 알람 ``` ```bash # .github/workflows/flag-audit.yml - run: gb-cli list-flags --age-gt 90d ``` ### Local override (dev / test) ```ts // 환경변수로 override const overrides = JSON.parse(process.env.FLAG_OVERRIDES ?? '{}'); gb.setForcedFeatures(overrides); ``` ```ts // 테스트 gb.setForcedFeatures({ 'new-checkout': true }); ``` ### Audit log - 누가 / 언제 / 무엇을 toggle 했는지. - Rollout 변화 history. - Compliance 요구. ## 🤔 의사결정 기준 | 규모 | 추천 | |---|---| | 작은 / 자체 호스트 | GrowthBook OSS / Unleash | | 큰 / 매니지드 | LaunchDarkly / Statsig | | 실험 자동 분석 | Statsig (자동 stats) | | 단순 on/off | env var + ConfigMap | | Edge runtime | Cloudflare Flags / GrowthBook Edge | ## ❌ 안티패턴 - **Flag 쌓기 + 정리 안 함**: 100+ flag = 코드 스파게티. - **Cleanup 정책 없음**: 누구도 안 지움. - **Random variant — sticky X**: 사용자가 매번 다른 variant. - **Attribute 안 정의 — global 만**: targeting 못 함. - **Flag 안에 비즈니스 결정**: dashboard 가 source of truth — 코드 의도 잃음. - **Critical path flag check 매번 fetch**: cache. - **Flag failure → 앱 다운**: default 명시 + 안전 fallback. ## 🤖 LLM 활용 힌트 - 새 feature = flag 부터. - % rollout + segment + kill switch 3종. - 정리 정책 + audit log 필수. ## 🔗 관련 문서 - [[Feature_Flags_in_Practice]] - [[Backend_API_Gateway_BFF]] - [[AI_LLM_Eval_Patterns]]