위험한 릴리스는 보통 위험하지 않다. code은 검토를 통과했고 빌드는 성공했고 팀은 자신감으로 병합했다. 그런 다음 프로덕션 트래픽이 새로운 경로에 모두 충돌하고 지원 팀이 오류를 보고하고 당신의 유일한 롤백 옵션은 압박하에 다시 배포하는 것이다.
그런 릴리스 패턴은 더 빠르게 분해된다. 백엔드가 빠르게 움직일 수 있지만 Capacitor 또는 Electron 클라이언트는 아직 사용자가 기기에 저장한 JavaScript, UI 논리, 패키지된 자산에 의존할 수 있다. 만약 더 안전한 배포를 원한다면, “code이 존재한다”와 “사용자가 이를 본다” 사이에 런타임 제어 계층이 필요하다.
그것이 기능 플래그가 의미하는 바이다. 그것은 당신이 code을暗시하고 특정 그룹에 노출하고 현실이 테스트와 일치하지 않으면 빠르게 끄는 것을 허용한다. 만약 당신이 앱 배달에서 단계별 롤아웃과 전체 릴리스를 구분하는 중이라면 기능 플래그는 단계별 롤아웃을 구현하는 메커니즘이다.목차
소개: 위험한 릴리스에서 제어된 롤아웃까지
- __CAPGO_KEEP_0__
- 기능 플래그 아키텍처를 선택하세요
- 크로스 플랫폼 앱의 코어 구현 패턴
- 전략적 롤아웃 및 대상자 타겟팅
- 테스트 관찰성 및 플래그 위생
- CI/CD 및 Live Update를 사용하여 플래그를 자동화하고 강화하십시오.
소개: 위험한 릴리즈에서 제어된 롤아웃으로
기능 플래그를 구현하는 방법에 대한 질문은 거의 능동적으로 묻히지 않습니다. 대신, 그것은 고통스러운 릴리즈 후에 발생합니다.
A checkout rewrite goes live for everyone. A settings screen works on web but breaks on one desktop build. A mobile shell loads fine, but the client code behind a new tab has edge cases nobody saw in staging. The problem isn’t just bad code. The problem is that release and deployment were treated as the same event.
기능 플래그는 두 가지 순간을 분리하여 그것을 해결합니다. 팀은 code를 먼저 배달하고 런타임에 조건부 논리를 통해 플래그를 평가합니다. Datadog는 그 核심 패턴을 명확하게 설명합니다. 기능 플래그 구현 개요: 애플리케이션은 런타임에 구성 정보를 확인하고 사용자를 새로운 경로 또는 오래된 기본 경로로 라우팅합니다. 따라서 플래그는 점진적인 롤아웃, 계층별 대상 지정 및 즉시 비활성화가 필요하지 않아도 전체 앱을 다시 배포할 필요가 없다는 점에서 유용합니다.
실용적인 규칙: 위험한 기능을 비활성화하는 것이 다시 배포를 필요로 한다면, 아직 실제 기능 플래그 시스템을 구축하지 않았다는 뜻입니다.
이것은 특히 하이브리드 스택에서 더 중요합니다. 서버는 사용자가 어떤 기능을 볼지 결정할 수 있지만, 클라이언트는 웹, Capacitor, 및 Electron에서 일관되게 동작해야 합니다. 따라서 플래그 시스템은 무작위 컴포넌트 내부에 숨겨지지 않고 릴리스 디자인의 일부가되어야 합니다.
이러한 작업을 잘하는 팀은 플래그를 운영 도구로 다루며, 불완전한 작업을 게이트로 사용하고, 내부 사용자에게 먼저 릴리스하고, 예상치 못한 문제가 프로덕션에서 나타날 때 빠르게 복구합니다.
기능 플래그 아키텍처 선택
아키텍처를 선택하기 전에 코드베이스에 플래그를 퍼뜨리지 마세요. 그렇지 않으면 서버, 웹 앱, Capacitor 셸, 및 Electron 빌드 간의 의견 불일치로 인해 기능 자체를 debug하기보다 debug하기가 어려워집니다.
플래그의 진실은 어디에 있고, 누가 그것을 평가할 것인지에 대한 결정은 간단합니다.
릴리스 제어는 진실의 출처에서 시작됩니다
기능 플래그 시스템은 애플리케이션이 하나의 신뢰할 수 있는 출처에서 현재 결정을 얻고 일관되게 적용할 수 있는지 여부에 따라 유용합니다. 실제로 하이브리드 팀은 일반적으로 두 개의 층이 함께 작동합니다:
- 컨트롤 플레인 flag 상태, 목표 규칙, 감사 기록 및 종료 switch를 정의하는 플레인
- 배송 경로 정확한 code와 설정을 올바른 클라이언트로 빠르게 가져오는 전달 경로
그 두 번째 부분은 일반적인 플래그 튜토리얼에서 놓치는 부분입니다. 서버 측 플래그는 기능을 숨길 수 있지만 깨진 Capacitor 또는 Electron 앱에 패치된 클라이언트 번들을 배포할 수 없습니다. 하이브리드 릴리스의 경우 플래그와 라이브 업데이트 모두 작동해야 합니다. 플래그는 노출을 제어합니다. 업데이트 시스템은 플래그 뒤에 앉아야 하는 정확한 클라이언트 code를 제공합니다.
React 및 하이브리드 팀이 이미 설정을 통해 작업 중인 경우 이 React 하이브리드 앱에 대한 기능 플래그 가이드
일반적으로 세 가지 모델 중 하나가 선택됩니다.
- 내부에서 빌드
- SaaS 플랫폼을 구매
- 자체로 오픈 소스 시스템을 실행
운영 제약 조건에 따라서 결정해야 합니다. 직접적인 질문을 하세요. 서버 측 평가가 API 응답에 필요합니까? 모바일에서 오프라인 기본값이 필요합니까? 제품 및 지원이 대시보드를 필요로 합니까? 규제 변경에 대한 감사 로그가 필요합니까? 팀이 모든 클라이언트에 SDK, 캐시 무효화, 타겟팅 로직을 운영할 수 있습니까?
만들기, 구매, 또는 자체 호스팅
Capacitor 및 Electron을 포함한 웹, 모바일, 데스크톱에서 릴리즈를 계획하는 팀과 함께 결정 표를 사용합니다.
| 요소 | 만들기 (내부) | 구매 (SaaS) | 오픈 소스 (자체 호스팅) |
|---|---|---|---|
| 제어 | 스키마, 평가 규칙, 데이터 저장소에 대한 전체 제어 | 인프라스트럭처 제어에 대한 낮은 수준, 빠른 제품 성숙도 | 기존 플랫폼 모델에 대한 높은 제어 |
| 초기 설정 | 빠른 기본 boolean에 대해 좋지만, 목표 설정 및 관리를 추가하면 느려집니다. | 일반적으로 가장 빠른 경로입니다. | 중간 수준의 설정 및 통합 작업 |
| 운영 부담 | 팀이 uptime, SDK 동작, 감사성, 그리고陈舊 플래그 정리 책임을 지게 됩니다. | 벤더가 플랫폼의 대부분을 소유합니다. | 팀이 호스팅, 업그레이드, 그리고 신뢰성을 책임지게 됩니다. |
| 목표 설정의 복잡성 | 내부 롤아웃 요청 후에 종종 과소 평가됩니다. | 일반적으로 box에 포함되어 있습니다. | 사용 가능하지만, 여전히 운영 및 튜닝이 필요합니다. |
| 하이브리드 앱에 적합합니다. | 만들어진 스택과 정확히 맞춰질 수 있습니다. 만약 좋은 클라이언트 전달 경로를 구축할 수 있다면 | SDK의 품질과 오프라인 동작에 따라 달라집니다 | 클라이언트에게 적합한 플랫폼을 적응할 수 있다면 좋은 옵션입니다 |
| 장기적인 유지보수 | 릴리즈 운영에 플래그가 포함된 경우 가장 높은 단계 | 구독 비용이 플랫폼 소유권을 대체합니다 | 빌드 비용이 낮아지고, 지속적인 운영 비용이 낮아집니다 |
팀이 가장 놀라는 트레이드 오프입니다. 플래그 서비스를 구축하는 것은 어렵지 않습니다. 그러나 타겟팅, 로컬 캐싱, 환경 승격, 감사 로그, 플래그 만료, 서버와 클라이언트에서 일관된 평가를 수행하는 플래그 서비스를 구축하는 것은 실제 플랫폼 작업입니다.
6개월 후에, 그들은 QA override 논리, 환경별 드리프트 체크, 클라이언트 구성이 앱 런치 후에 안전하게 갱신되도록 custom code을 구축하는 등 관리 화면, admin 스크린, 오버라이드 논리, 환경별 드리프트 체크를 유지보수해야 했습니다. 첫 번째 버전은 불리언 값을 해결했습니다. 두 번째 버전은 릴리즈 인프라가되었습니다.
오픈 소스 및 SaaS 플랫폼은 부담을 줄여주지만, 여전히 하이브리드 특정 문제를 해결해야 합니다. 평가가 어디서 발생하는지, 클라이언트가 결과를 캐시할 수 있는 기간, 앱이 오프라인에서 어떻게 동작하는지, 클라이언트 번들을 기기에 이미 설치된 경우 복구하는 방법을 결정해야 합니다. Unleash는 feature flag 시스템 개요에서 이 움직이는 부분을 명확하게 설명합니다. feature flag 시스템 개요: 성숙한 설정은 관리 서비스, 저장소, API, SDK, 업데이트 메커니즘을 포함합니다
이러한 롤백 계획이 '플래그를 끄는 것'이라면, 클라이언트가 안전한 기본값 code을 이미 가지고 있는지 확인하세요. 그렇지 않다면, 라이브 업데이트와 플래그를 pair하여 노출을 차단하고 스토어 릴리즈를 기다리지 않고.fix를 배포할 수 있습니다.
서버 플래그는 '누구에게 보여줄 것인가?' Live update를 대답합니다. Capgo 시스템은 '그 code를 사용자가 지금 실행해야 하는지'를 대답합니다. 두 가지 모두 사용하세요. 내부 사용자에게 기능을 출시하고 플래그를 사용하여, 업데이트된 클라이언트 번들을 해당 그룹에만 푸시한 다음, 지표가 깨끗한지 확인하여 노출을 넓혀보세요. 이러한 패턴은 플래그만 사용하는 것보다 더 좁은 폭을 가진 폭파 범위 제어를 제공합니다.
내부적으로 빌드한다면, 범위는 좁고 명확해야 합니다. 플래그 스키마를 정의하고, 평가 규칙을 중앙화하고, 관리 API를 추가하고, 모든 변경 사항을 로그하고, 제거 정책을 설정하기 전에 첫 번째 플래그가 배포되기 전에 해야 합니다. 구매한다면, 나쁜 네트워크 조건과 앱 리스타트를 포함하여 SDK 동작을 테스트해야 합니다. 자체 호스팅한다면, 업그레이드, 온콜 소유권 및 클라이언트 통합 작업에 대한 엔지니어링 시간을 예상해야 합니다.
플랫폼 간 크로스 플랫폼 앱의 코어 구현 패턴
하이브리드 앱은 일반적으로 플래그 정의 자체가 아닌 경계에서 실패합니다.
일반적인 실패 모드는 익숙합니다. 웹 code은 시작 시 플래그 값을 읽고, Capacitor 플러그인은 캐시된 복사본을 나중에 확인하고, Electron 창은 동일한 플래그를 다시 평가하지만 사용자 컨텍스트가 약간 다릅니다. 이제 릴리스는 플랫폼 간에 일관성이 없고, 롤백은 추측이 됩니다.

간단하게 시작하고 빠르게 중앙화하세요
모든 기능 플래그는 처음에는 if/else:
if (flags.newCheckout) {
renderNewCheckout();
} else {
renderLegacyCheckout();
}
첫 번째 커밋에서 괜찮습니다. 하지만 같은 플래그가 5곳에 체크인되고 각层에서 다르게 해석되면 더 이상 괜찮지 않습니다.
마틴 파울러의 기능 토글 패턴의 기사 아직도 올바른 기준을 제공합니다. 평가 로직을 중앙화하고, 조건문을 흐름의 가장자리에 가까운 곳에 두세요. 저수준 컴포넌트를 통해 퍼뜨리지 마세요.
크로스 플랫폼 앱에서 유용한 평가 지점은 일반적으로 다음과 같습니다:
- 서버 요청 설정 SSR, API 형성, 또는 초기 구성 전달
- 클라이언트 부트스트랩 사용자 식별, 장치, 및 환경 컨텍스트를 로드한 후
- 라우트 또는 화면 경계선 플래그 상태에 따라 전체 흐름이 다르다
깊은 컴포넌트, 네이티브 브리지, 헬퍼 유틸리티에서 플래그를 평가하는 패턴은 빠르게 드리프트를 발생시킨다.
결정을 전달하라, 플래그 자체를 전달하지 마라
성숙한 구현은 벤더 플래그 값을 애플리케이션 결정에서 분리한다.
플래그 제공자는 다음과 같은 저수준 질문에 답한다. newCheckout=true앱은 다음과 같은 고수준 결정만을 소비해야 한다. showNewCheckout, enableDesktopSidebar, 또는 allowBackgroundSync이 레이어는 비즈니스 규칙, 플랫폼 제약조건, FALLBACK 동작을 인코딩한다.
이 추가적인 간접성은 빠르게 보상을 한다.
이것은 리액트 컴포넌트를 깨끗하게 유지한다. 하나의 SDK에 대한 결합을 줄인다. 또한 팀이 지속적으로 마주치는 질문에 답할 수 있는 장소가 하나 더 생긴다: 이 사용자가 플래그와 올바른 클라이언트 code를 모두 가지고 있는지 여부를 확인하는 것이다.
마지막 점은 Capacitor와 Electron에 중요하다. 서버는 노출을 즉시 변경할 수 있지만 클라이언트는 안전하게 렌더링할 수 있는 클라이언트 code를 가지고 있어야 한다. 플래그 평가를 대상화된 번들 전달과 pair하는 것이 이 간격을 닫는 방법이다. Capgo의 가이드를 실시간 업데이트와 사용자 구분 운영 모델을 보여준다. 사용자 그룹이 특정 기능을 받을지 평가하고, 앱 스토어 리뷰를 기다리지 않고 그 그룹에 맞는 클라이언트 업데이트만 제공한다.
실용적인 TypeScript 패턴
여기에는 컴포넌트에서 직접적인 체크보다 더 확장 가능한 패턴이 있다.
type UserContext = {
userId?: string;
country?: string;
plan?: 'free' | 'pro' | 'enterprise';
platform: 'web' | 'capacitor' | 'electron';
isInternal?: boolean;
};
type RawFlags = {
newCheckout: boolean;
desktopSidebarRedesign: boolean;
smartSync: boolean;
};
class FeatureFlagService {
constructor(private flags: RawFlags, private user: UserContext) {}
get decisions() {
return {
showNewCheckout: this.flags.newCheckout && this.user.plan !== 'free',
showDesktopSidebar: this.user.platform === 'electron' && this.flags.desktopSidebarRedesign,
enableSmartSync: this.flags.smartSync && this.user.country !== undefined,
};
}
}
앱의 상단에서 한 번만 평가하라:
async function bootstrapApp() {
const user = await getUserContext();
const flags = await fetchFlagsForUser(user);
const featureService = new FeatureFlagService(flags, user);
const decisions = featureService.decisions;
startApp({ user, decisions });
}
그런 다음 UI는 지능이 없다:
type AppProps = {
decisions: {
showNewCheckout: boolean;
showDesktopSidebar: boolean;
enableSmartSync: boolean;
};
};
function App({ decisions }: AppProps) {
return (
<>
{decisions.showDesktopSidebar ? <NewSidebar /> : <LegacySidebar />}
{decisions.showNewCheckout ? <CheckoutV2 /> : <CheckoutV1 />}
</>
);
}
이 구조는 화면 간 일관성을 유지하고, 단순한 테스트를 하며, 롤아웃이 끝난 후 제거하는 경로를 깨끗하게 유지한다.
플랫폼과 업데이트 준비를 결정层에 추가하라
하이브리드 앱은 일반적인 플래그 튜토리얼이 자주 생략하는 한 가지 더 체크가 필요하다. 특정 기능이 원격 플래그가 yes라고 말하는 것만으로 활성화되지 않아야 한다. 그것은 설치된 또는 라이브 업데이트된 클라이언트가 그것을 지원할 수 있는지 확인할 때만 활성화되어야 한다.
당신의 결정层가 종종 raw 플래그 이외의 입력이 필요할 때가 있습니다.
- 결정层는 일반적인 플래그만으로는 충분하지 않다:
- 현재 앱 버전
- 플랫폼
- 오프라인 상태
- 네이티브 기능 사용 가능성
결정 객체는 직접 표현할 수 있습니다:
type RuntimeContext = {
appVersion: string;
bundleVersion?: string;
isOffline: boolean;
hasNativeBiometrics: boolean;
};
function buildDecisions(flags: RawFlags, user: UserContext, runtime: RuntimeContext) {
return {
showNewCheckout:
flags.newCheckout &&
user.plan !== 'free' &&
runtime.bundleVersion === 'checkout-v2',
enableSmartSync:
flags.smartSync &&
!runtime.isOffline,
enableBiometricUnlock:
flags.smartSync &&
runtime.hasNativeBiometrics &&
user.platform === 'capacitor',
};
}
이것은 실제적인 트레이드 오프입니다. 결정层이 복잡해지지만 앱이 안전하게 작동할 수 있습니다. 이 단계를 생략하는 팀은 롤백 중에 발견하는 경우가 많습니다. 플래그가 꺼져 있지만 호환되지 않는 code이 이미 기기에서 실행 중이거나, 플래그가 켜져 있지만 필요한 번들을 받은 사용자에게는 플래그가 켜져 있지 않습니다.
결정적 배포를 위한 버킷을 사용하십시오.
퍼센티지 배포 논리는 한 곳에 있어야 합니다. 사용자를 랜덤으로 할당하지 말고, 사용자에게 고정된 식별자와 결정적 해싱을 사용하여 동일한 사용자가 동일한 버킷에 머물 수 있도록 하십시오.
function isInRollout(featureName: string, userId: string, rolloutGate: number): boolean {
const bucket = stableHash(`${featureName}:${userId}`) % 100;
return bucket < rolloutGate;
}
해시 함수의 정확한 값은 중요하지 않습니다. 동일한 입력이 항상 동일한 버킷에 들어가야 합니다. 라이브 업데이트도 제공하는 경우, 버킷 입력을 배포할 때 사용한 규칙과 일치시켜야 합니다. 그렇지 않으면, 지원하는 code을 받은 사용자에게도 기능 플래그를 노출할 수 있습니다.
재사용 가능한 리프 컴포넌트에서 플래그 체크를 제외하는 마지막 규칙은 후에 많은 청소 작업을 피할 수 있습니다. 컴포넌트가 실험에만 존재하는 경우를 제외하고, 컴포넌트에서 플래그 체크를 제외하십시오. 경로, 화면 또는 서비스 경계에 분기를 두고, 나머지 tree는 단일 선택된 경로를 렌더링하십시오.
전략적 배포 및 대상 설정
A rollout plan이 처음으로 프로덕션에서 사용자 한 명과 다른 사용자와 다른 방식으로 작동하는 경우 테스트됩니다. 체크아웃 흐름은 데스크톱 Electron에서 작동하지만 더 오래된 Android WebView 빌드에서 실패하고, 지원 팀은 현재 노출된 사용자를 알아야 합니다. 그 때 boolean flag이 더 이상 충분하지 않습니다.

A 새로운 체크아웃 흐름의 롤아웃 스토리
shipping하는 경우 new-checkout Capacitor 앱에서 데스크톱 Electron 빌드를 통해 UI 변경을 배포하고 있습니다. 변경은 서버 측 플래그 뒤에 숨겨져 있지만, 일부 지원 로직은 클라이언트 code로 배포됩니다. 두 시스템이 동기화되지 않으면 사용자는 플래그를 받기 전에 패키지를 받거나, 패키지를 받기 전에 기능을 볼 수 있습니다.
staff 계정과 QA 장치에서 시작하여, 한 플랫폼, 예를 들어 Electron만을 위해 옵티드인 베타 사용자로 이동합니다. 그 다음으로, 모바일은 이전 경로를 유지합니다. 그 다음으로, 계층과 백분율을 확장하여 오류율, 결제 실패, 지원 티켓을 감시합니다. 롤아웃이 각 지원 플랫폼에서 실제 트래픽을 견뎌낸 후에 오래된 체크아웃 흐름이 계속 사용 가능해야 합니다.
해당 기능의 실용적인 정책은 다음과 같습니다:
- 내부 계층부터: 개발자, QA, 지원, 데모 계정
- 플랫폼별 베타 사용자: 신뢰할 수 있는 앱 버전과 런타임에서만 early-access 사용자
- 프로덕션 단계: 작은 단계로 노출을 증가시키고 regressions에 대한 일시적인 중단
- 기본값이 유지되며 live 상태: 새로운 경로가 프로덕션에서 안정적일 때까지 이전 경로가 호출 가능합니다.
하이브리드 앱의 경우 rollout 정책에도 배포 정책이 필요합니다. Live update 사용자 세그먼테이션을 위한 Capacitor 앱 이것은 사용자 그룹과 플래그 시스템이 목표하는 동일한 그룹에 맞춤형 클라이언트 번들을 배포하는 방법을 보여줍니다. 이 연결은 중요합니다. 플래그와 배포된 code가 다른 사용자 규칙을 따르지 않으면 릴리스 제어가 약해집니다.
프로덕션에서 유지되는 목표 규칙
좋은 목표는 평가 시간에 사용할 수 있고 감사 및 지원을 위해 안정적이면서도 설명할 수 있는 속성을 사용합니다. 플랫폼, 앱 버전, 지역, 계정 등급, 내부 사용자 상태 및 베타 등록은 일반적입니다.
나쁜 목표는 늦게 나타나거나 자주 변경되는 값을 사용합니다. 세션 로컬 상태, 부분적으로 동기화된 프로필 필드 또는 클라이언트 전용 속성은 서버가 의도한 것과 앱이 렌더링한 것 사이의 일관성이 깨지는 어려운 일관성을 만듭니다.
팀이 3개의 대시보드를 열지 않고 읽을 수 있는 규칙을 사용하십시오. internal, beta_mobile및 enterprise_desktop_v2 익명 세그먼트 ID보다 쉽게 운영할 수 있습니다. 지원 팀은 한 질문에 즉시 답변할 수 있어야 합니다: 이 사용자가 이 기능을 받은 이유는 무엇입니까?
서버가 관리하는 타겟팅은 정책을 중앙 집중화하지만, 하이브리드 앱은 여전히 네트워크가 느리거나 사용할 수 없는 경우에 안전한 로컬 FALLBACK을 적용하기 위해 충분한 클라이언트 컨텍스트가 필요합니다. 일반적인 패턴은 서버가 노출을 결정하고 클라이언트가 런타임, 번들 버전, 또는 네이티브 기능과 같은 호환성 검사를 강제하는 것입니다.
Kill Switch는 디자인의 일부입니다.
Kill Switch는 출시 설계의 일부입니다. 이는 나중에 청소 작업이 아닌 처음부터입니다.
고객과 대면하는 기능의 경우 이전 경로를 이전 경로가 실제로 주요 계층군에서 실시간으로 통과하기 전까지 유지하세요. 하나의 지역 또는 하나의 런타임에서 체크아웃 실패가 급증하는 경우, 해당 대상에게 기능을 즉시 비활성화할 수 있어야 합니다. 앱 스토어 리뷰를 기다리지 않고.
Hybrid apps add another layer. A server-side flag can hide a broken path, but it cannot repair code already on devices. Live update systems such as Capgo close that gap. You can turn the feature off, then push a corrected bundle to the affected cohort instead of waiting on the next full release cycle.
이 combination이 rollout을 실제로 작동시키는 것입니다. 플래그는 노출을 제어합니다. 타겟팅은 폭파 반경을 제한합니다. Live Update는 런타임 동작과 shipped code가 분리될 때 클라이언트를 빠르게修復합니다.
테스트 관찰성 및 플래그 위생
A code 플래그는 code 경로, 타이밍 문제 및 현재 상태를 프로덕션에서 추론해야 합니다. 만약 직접 상태를 관찰하지 않고 테스트하지 않는다면 플래그는 위험을 줄이지 않고 오히려 위험을 옮기는 것입니다.
테스트를 의도적으로 양쪽 branch에 수행하십시오.
모든 플래그를 두 개의 릴리스로 간주하십시오. 코드베이스 내에서 오래된 경로도 보호가 필요하며 새로운 경로가 출시되는 동안 새로운 경로가 올바르게 작동하는지 실제 앱 조건 하에서 증명해야 합니다.
단위 수준에서 플래그 결정을 주입하여 테스트가 결정적이 되도록 하십시오. 통합 및 종단 간 수준에서 QA 및 CI에 제어된 오버라이드 제공하십시오. 테스트 실행 중에 라이브 타겟팅 규칙에 의존하지 마십시오. 규칙이 변경되고 캐시가 만료되어 suddenly 불안정한 테스트가 롤아웃 타이밍에 대한 정보를 더 많이 알려주게 됩니다.
하이브리드 앱의 경우 플래그 상태가 앱 상태에서 이탈할 수 있는 순간을 테스트하십시오:
- 활성화 및 비활성화 경로: 양쪽에 커버리지 유지할 때까지 플래그가 제거될 때까지.
- 경계 집단: 직원, 베타, 유료, 지역, 익명 사용자 규칙을 별도로 검증하십시오.
- 런칭, 재개, 리프레시 흐름: 많은 Capacitor 및 Electron 앱이 그 점에서 상태를 재평가합니다.
- 오프라인 FALLBACK 동작: 네트워크가 불안정할 때 클라이언트가 마지막으로 잘 작동한 결정을 사용하거나 안전한 기본값을 사용하도록 확인하세요.
- 호환성: 서버에서 특정 code를 전달하는 경우 플래그가 노출되면, 앱이 현재 버전으로 설치된 live update를 지원하지 않는 UI를 활성화하지 않도록 확인하세요.
마지막 점은 쉽게 놓치기 쉬운 점입니다. 서버는 사용자가 특정 기능을 볼 수 있도록 결정할 수 있지만, 클라이언트는 설치된 버전과 네이티브 런타임이 기능을 안전하게 실행할 수 있는지 확인해야 합니다.
플래그를 관찰하라, 기능만 관찰하지 마라
인스트루먼테이션은 세 가지 질문에 빠르게 답할 수 있어야 합니다. 어떤 플래그를 보았나요? 어떤 code 경로가 실행되었나요? 어떤 버전의 배포본이 실행되었나요?
팀들은 플래그를 설정하고 그만두곤 합니다. 그런 다음 프로덕션에서 오류가 발생하고 nobody가 오류가 플래그된 code에서 오류가 발생했는지, 특정 사용자 그룹에서 오류가 발생했는지, 또는 오래된 클라이언트 배포본에서 오류가 발생했는지 알 수 없습니다. 해결책은 간단합니다. 분석 이벤트, 로그, 추적, 오류 보고서에 평가된 플래그 상태를 추가하지 마세요. feature=new_checkout로그하지 마세요.
. 실제 결정, 규칙 또는 계층을 로그하지 마세요. 그리고 클라이언트 버전을 로그하지 마세요.
{
"event": "checkout_started",
"flag_new_checkout": true,
"flag_rule": "beta_users_us",
"app_version": "5.4.1",
"bundle_version": "2026.06.13-2",
"platform": "capacitor-ios"
}
단순한 이벤트 형태는 일반적으로 충분합니다:
이 구조는 프로덕션 디버깅을 훨씬 빠르게 만듭니다. 나쁜 롤아웃 규칙과 나쁜 배포본을 분리할 수 있고, 한 플랫폼이 실패하는지 다른 플랫폼이 건강한지 확인할 수 있습니다. 실시간 업데이트 메트릭을 위한 Capacitor 앱 release 제어와 런타임 증거 사이의 격차를 줄이기 위해 도움을 주세요. 기능 노출 데이터와 배달 채택 데이터를结合하면, 회귀가 플래그 결정, 배포된 자바스크립트, 또는 두 가지 사이의 상호작용에서 오는지 알 수 있습니다.
관찰 가능성이 없는 플래그는 대시보드 체크박스를 달고 있는 숨겨진 복잡성입니다.
구현의 일부는 청소입니다.
플래그 부채는 code 부채로 빠르게 변합니다.
성공한 플래그 중 가장 나쁜 것은 nobody가 제거하지 않은 플래그입니다. 그들은 죽은 branch를 살리고, 온보딩 엔지니어를 혼란시켜, 롤아웃 결정이 끝난 후에도 테스트 매트릭스를 확장합니다. 하이브리드 앱에서, 그들은 live update가 더 많은 노력을 기울여야 하는 이유입니다. 왜냐하면 compatibility 로직을 상태가 더 이상 중요하지 않은 것에 대해 유지해야 하기 때문입니다.
플래그가 생성될 때는 다음 규칙을 설정하세요:
- 담당자 assignment
- 제거 조건을 기록하세요.
- 청소 작업을 즉시 열세요.
- 배포가 완료되면 죽은 code를 삭제하세요.
- 플래그 항목을 지원 및 엔지니어링이 여전히 활성화로 간주하지 않도록 아카이브 또는 제거하세요.
서버 사이드 플래그와 라이브 업데이트로 배포하는 팀에게는 하나의 실용적인 규칙을 추천합니다. 만약 플래그가 오래된 클라이언트 배달과 새로운 클라이언트 배달 사이의 짧은 이주를 보호하기 위해 존재한다면, 짧은 만료 날짜를 부여하고, 일반 백로그 청소와는 다르게, 릴리즈 소유자와 함께 리뷰하세요. 임시 플래그는 Capacitor와 Electron 앱에서 빠르게 증가합니다. 특히, 프로덕션 동작을 패치할 때, 풀 스토어 릴리즈를 기다리지 않고.
CI/CD와 Live Update를 이용한 Flag 자동화
수동 플래그 워크플로우는 확장성이 좋지 않으며, 특히 핫픽스 시점에 실패합니다.
성숙한 플래그 설정은 빌드, 테스트 및 배포 프로세스와 동일한 배포 프로세스에 플래그를 연결합니다.

배포와 함께 플래그 생성
기능 branch가 병합될 때 pipeline은 이미 플래그를 생성하거나 유효성 검사를 수행할 수 있어야 합니다. 그러나 모든 커밋에 새로운 스위치가 필요하지는 않습니다. 이는 릴리스 제어가 시스템화되어야 하며, 마지막으로 병합한 사람의 지식이 아닌 시스템화된 제어가 되어야 합니다.
유용한 자동화에는 다음이 포함됩니다:
- 플래그 스키마 검사: 병합 전에 이름, 소유자 및 만료 계획을 확인합니다.
- 환경 기본값: 새로운 위험한 기능은 프로덕션에서 비활성화되어야 하며, 명시적으로 승인되지 않는 한.
- 릴리스 노트에 플래그 상태를 포함합니다. 지원 및 QA 팀이 빌드에 게이트된 기능을 알 수 있도록 해야 합니다.
- 정리 알림: 기존 플래그가 엔지니어링 워크플로우에서 나타나기 전에 영구적인 잡음이 되지 않도록 해야 합니다.
모바일 및 하이브리드 배포 PIPELINES에 이 기능을 통합하는 경우 Capacitor 앱에 대한 CI/CD 설정 운영 측면의 동일한 문제입니다.
라이브 업데이트에서 등식이 바뀝니다.
하이브리드 앱은 웹 앱만큼의 플레이북이 필요합니다.
서버 측 플래그가 특정 기능을 누구에게 보여줄지 결정합니다. 하지만 때로는 그 기능의 code이 앱 바이너리가 이미 사용자들의 손에 있는 상태에서 변경되어야 하는 경우가 있습니다. Electron 및 Capacitor에서 이 경우 릴리스 간격이 생깁니다. 플래그는 숨기거나 노출할 수 있지만 자체적으로 클라이언트 번들을 다시 작성할 수는 없습니다.
이런 이유로 live update 시스템은 기능 플래그와 잘 어울립니다. 플래그는 누구에게 기능을 보여줄지 결정하고 업데이트 채널은 누구 기능을 보여줄지 결정합니다. 어떤 클라이언트 code 그 사용자들이 받는 것. 예를 들어, 팀은 런칭 다크리(LaunchDarkly)나 언리시(Unleash)를 사용하여 런타임 타겟팅을 사용하고 __CAPGO_KEEP_0__ Capgo 업데이트된 자바스크립트, CSS, 복사본, 설정, 및 자산을 특정 채널에 전달하여 Electron 앱이나 Capacitor의 특정 채널에 전달할 수 있습니다.
그 combination은 특히 타겟팅된 롤아웃을 위한 하이브리드 환경에서 효과적입니다:
- 서버 사이드 타겟팅: 런타임에 사용자들을 선택합니다.
- 클라이언트 사이드 전달: 기능을 지원하는 정확한 번들을 푸시합니다.
- 운영 회복: 기능을 비활성화하거나 고정된 번들을 배포하거나 둘 다합니다.
- 플랫폼 일관성: 웹, 데스크톱 및 모바일 릴리스 로직을 일치시켜 유지하기 위해 배달 메커니즘의 차이에도 불구하고.
이 walkthrough은 실제로 팀이 그 워크플로를 처리하는 방법에 대한 구체적인 시각을 제공합니다:
serious한 팀은 hybrid 스택에서 기능 플래그를 implement하는 방법에 대해 생각하는 layer를 생각해야합니다. 하나의 layer는 노출을 결정합니다. 다른 layer는 code를 전달합니다. 세 번째 layer는 발생한 것을 관찰합니다. 그 layer가 분리되어도 조정되면 릴리스가 irreversible 베팅으로 느껴지지 않고 controlled 운영으로 행동합니다.
Capgo는 CapacitorJS 및 Electron 앱을 shipping하는 팀에게 두 번째 layer를 제공합니다. 그것은 live updates, 채널 기반 타겟팅, 롤백 제어, 관찰성 및 CI/CD 통합을 제공하여 웹 번들 배달을위한 web bundle delivery를 제공합니다. 이것은 런타임 제어 및 빠른 클라이언트 측 수정에 의존하는 릴리스 전략에 따라 서버 측 기능 플래그 시스템의 실용적인 보완입니다.