Feature Flag는 새로운 코드를 배포하지 않고 런타임에 조건부 스위치를 통해 애플리케이션 기능을 활성화 또는 비활성화하는 개발 기술입니다. 기존의 “commit — deploy” 방식 대신, feature flags를 사용하면 배포 시점과 기능 활성화 시점을 분리할 수 있습니다. LaunchDarkly (2024)에 따르면, feature flags를 사용하는 팀은 새로운 기능의 롤아웃 시간을 40% 단축합니다. Feature flags는 현대 모바일 및 웹 애플리케이션을 위한 CI/CD의 필수 요소가 되었습니다.
핵심 요점
Feature Flag(피처 토글)는 코드를 수정하지 않고 애플리케이션 동작을 변경할 수 있는 메커니즘입니다. 가장 간단한 형태로, 새로운 기능을 실행하기 전에 플래그 값을 확인하는 조건문입니다. 플래그는 구성 파일, 데이터베이스 또는 외부 서비스에 저장될 수 있으며 실시간으로 변경될 수 있습니다. 이 접근 방식은 팀이 개발이 완료되기 전에 사용자에게 도달할 걱정 없이 미완성 코드를 메인 브랜치에 커밋할 수 있는 능력을 제공합니다.
Feature flags의 주요 목적은 배포와 릴리스를 분리하는 것입니다. 배포는 서버나 앱 스토어에 코드를 배치하는 프로세스입니다. 릴리스는 기능이 사용자에게 제공되는 순간입니다. Feature flags가 없으면 이러한 이벤트가 일치합니다. 코드가 프로덕션에 들어가면 사용자가 이를 보게 됩니다. Feature flags를 사용하면 코드를 릴리스보다 몇 주 일찍 프로덕션에 배포하고, 내부 테스트용으로 활성화하거나 점진적으로 사용자에게 롤아웃할 수 있습니다. 이는 trunk-based development와 지속적 전달에 중요합니다.
모바일 Kotlin 애플리케이션의 기본 feature flag 구현을 고려해 보세요. 플래그는 Firebase Remote Config에 저장되며 앱 시작 시 로드됩니다. 플래그 값에 따라 이전 또는 새 프로필 화면이 표시됩니다. 이 구현을 통해 App Store 업데이트를 게시하지 않고도 새 버전의 프로필을 릴리스할 수 있습니다. Firebase 콘솔에서 값을 변경하기만 하면 됩니다.
class ProfileFeature {
private val flags = FeatureFlagProvider()
private val profileFlag = FlagKey("new_profile_enabled")
fun getProfileScreen(): Screen {
return if (flags.isEnabled(profileFlag)) {
NewProfileScreen()
} else {
LegacyProfileScreen()
}
}
}
class FeatureFlagProvider {
fun isEnabled(key: FlagKey): Boolean {
val raw = Firebase.remoteConfig.getString(key.name)
return raw.toBoolean()
}
}
모든 feature flags가 동일하지는 않습니다. 마틴 파울러의 분류는 네 가지 유형의 플래그를 식별하며, 사용 목적, 수명 및 관리 요구 사항이 다릅니다. 올바른 플래그 분류는 적절한 인프라를 선택하고 일반적인 문제를 피하는 데 도움이 됩니다.
Release toggles는 가장 일반적인 유형의 플래그입니다. 프로덕션에서 미완성 기능을 숨기는 데 사용됩니다. 개발자는 플래그로 감싼 코드를 메인 브랜치에 커밋하고 점차적으로 기능을 완성합니다. 완료 및 테스트 후 플래그는 모든 사용자에 대해 활성화됩니다. 이러한 플래그의 수명 주기는 며칠에서 2주까지입니다. 전체 롤아웃 후 플래그는 코드에서 제거됩니다. Release toggles는 trunk-based development의 기초입니다.
Experiment toggles는 A/B 테스트와 함께 작동합니다. 단순히 기능을 켜거나 끄는 것이 아니라 사용자를 실험 그룹 중 하나로 안내합니다. 이러한 플래그는 종종 복잡한 타겟팅 규칙(지역, OS 버전, 구독별)과 분석 시스템과의 통합을 지원합니다. Ops toggles는 운영 제어에 사용됩니다 — 예를 들어, 높은 부하에서 무거운 기능을 비활성화하거나 즉시 배포 없이 문제가 있는 모듈을 일시적으로 끕니다. Ops toggles는 가능한 한 빠르고 안정적이어야 하며, 서비스 안정성이 이에 달려 있습니다.
| 유형 | 기간 | 동적성 | 목적 |
|---|---|---|---|
| Release | 일-주 | 정적 | 미완성 코드 숨김 |
| Experiment | 일-개월 | 동적 | A/B 테스트 및 롤아웃 |
| Ops | 시간-일 | 동적 | 운영 제어 |
| Permission | 개월+ | 정적 | 액세스 제어 |
Feature flags 관리는 플래그의 저장, 구성, 모니터링 및 감사를 포함하는 별도의 분야입니다. 관리 시스템 없이 플래그는 통제 불가능한 기술 부채로 변하여 개발을 지연시킵니다. 프로덕션 시스템을 예로 들어 관리의 주요 측면을 살펴보겠습니다.
각 feature flag는 네 단계를 거칩니다: 생성, 사용, 안정화 및 제거. 생성 단계에서는 플래그 키, 유형 및 기본값이 정의됩니다. 사용 중에는 팀이 누가 어떤 대상과 목적으로 플래그를 활성화했는지 모니터링합니다. 안정화 후(기능이 완전히 준비되고 테스트됨) 플래그는 코드에서 제거되어야 합니다. 제거 프로세스는 코드 리뷰를 통해 자동화됩니다. CI는 100% 사용자에 대해 활성화된 모든 플래그에 제거 작업이 있는지 확인합니다.
Feature flags는 각 서비스의 구성 파일에 분산되지 않고 중앙에 저장되어야 합니다. 이상적으로는 UI가 있는 전용 서비스(LaunchDarkly, Unleash)입니다. 최소한으로 허용되는 옵션은 변경 사항에 대한 코드 리뷰가 있는 리포지토리의 JSON 구성입니다. 플래그 저장을 위한 데이터베이스는 별도의 관리 인터페이스가 필요하므로 덜 선호됩니다. 각 플래그에는 소유자(팀 또는 특정 개발자), 설명 및 수명(TTL)이 있어야 합니다. 오래된 플래그의 정기적 감사는 필수 관행이며, N일 이상 변경되지 않은 플래그를 확인하는 CI 작업을 통해 자동화됩니다.
Feature flags 관리 도구 시장에는 완전한 관리 주기를 갖춘 상용 플랫폼과 자체 배포를 위한 오픈 소스 솔루션이 모두 포함됩니다. 도구 선택은 팀 규모, 지연 시간 요구 사항 및 규정 준수에 따라 달라집니다.
LaunchDarkly는 모든 인기 언어 및 플랫폼(iOS, Android, Web, Backend)용 SDK를 갖춘 시장 선두주자입니다. 다중 환경, 규칙 기반 타겟팅, A/B 실험 및 자동 플래그 제거를 지원합니다. Split은 엔터프라이즈 기능에 초점을 맞춘 대안으로, 역할 기반 액세스, 감사 로그 및 규정 준수(SOC2, HIPAA)를 제공합니다. ConfigCat은 더 가볍고 저렴한 솔루션으로 소규모 팀에 적합합니다. 모든 플랫폼은 값 캐싱과 애플리케이션 지연 시간에 최소한의 영향을 미치는 SDK를 제공합니다.
Unleash는 UI, API 및 모든 주요 플랫폼용 SDK를 갖춘 가장 인기 있는 오픈 소스 솔루션입니다. 활성화 전략, 사용자 정의 컨텍스트 및 모니터링을 위한 Prometheus와의 통합을 지원합니다. Flagsmith는 내장 A/B 테스트 및 환경 관리를 갖춘 대안입니다. 오픈 소스 솔루션은 인프라 배포 및 유지 관리가 필요하지만 데이터에 대한 완전한 제어를 제공하고 라이선스 제한이 없습니다. 모바일 애플리케이션의 경우 두 솔루션 모두 오프라인 플래그 값 캐싱이 있는 네이티브 SDK를 제공합니다.
Feature flags는 강력한 도구이지만, 규율 없이는 기술 부채를 만들고 코드를 복잡하게 만듭니다. 마틴 파울러와 LaunchDarkly 엔지니어들은 부정적인 결과 없이 feature flags의 최대 혜택을 얻는 데 도움이 되는 일련의 관행을 공식화했습니다. 프로덕션 시스템을 위한 주요 권장 사항을 살펴보겠습니다.
롤아웃 완료 후 제거되지 않은 각 feature flag는 기술 부채가 됩니다. LaunchDarkly (2024)의 연구에 따르면 평균 30–40%의 플래그가 더 이상 필요하지 않은 후에도 코드에 남아 있습니다. 해결책: “하나의 플래그 — 하나의 작업” 규칙을 구현합니다. 플래그를 만들 때 작업 추적기에 마감일이 있는 제거 작업이 생성됩니다. CI는 30일 이상 100% 활성화된 플래그가 없는지 확인합니다. 코드 리뷰에서는 플래그 추가뿐만 아니라 제거도 확인해야 합니다.
Feature flags는 테스트에 조합 복잡성을 만듭니다. 각 플래그는 애플리케이션의 가능한 상태 수를 두 배로 늘립니다. 이 복잡성을 관리하기 위해 모든 플래그 조합을 확인하는 매트릭스 테스트와 플래그 토글링 통합 테스트가 사용됩니다. CI 파이프라인에 다양한 플래그 값 조합으로 테스트를 실행하는 단계가 추가됩니다. 중요한 플래그(ops toggles)의 경우 플래그 전환으로 인해 지연 시간 급증이나 오류가 발생하지 않는지 확인하기 위한 부하 테스트가 필수입니다.
class FeatureFlagService:
def __init__(self, storage):
self.storage = storage
def is_enabled(self, flag_key, user_context):
flag = self.storage.get(flag_key)
if not flag:
return False
for rule in flag["rules"]:
if self._match_rule(rule, user_context):
return rule["value"]
return flag["default"]
def _match_rule(self, rule, context):
return (
rule["percentage"] > self._hash(context.user_id)
)
자주 묻는 질문
이 용어들은 종종 동의어로 사용되지만, 미묘한 차이가 있습니다. Feature flag는 일반적으로 중앙 집중식 관리, UI 및 SDK를 갖춘 더 성숙한 시스템을 의미하는 반면, feature toggle은 코드의 간단한 이진 스위치입니다. 마틴 파울러는 feature toggle을 일반 용어로 사용하지만, 업계에서는 feature flag가 상용 플랫폼(LaunchDarkly, Split)과 더 자주 연관됩니다.
올바르게 구현하면 성능에 미치는 영향은 미미합니다. 모범 사례: 30–60초 TTL로 메모리에 플래그 값을 캐시하고, 플래그 확인 시 동기 HTTP 호출을 피하며, 로컬 캐시 및 백그라운드 동기화가 있는 SDK를 사용합니다. LaunchDarkly에 따르면 SDK의 p99 지연 시간은 5ms 미만으로 대부분의 애플리케이션에서 무시할 수 있는 수준입니다.
Feature flags는 어떤 코드가 실행되고 있는지 정확히 알아야 하는 중요한 금융 작업에서 비즈니스 로직을 변경하는 데 권장되지 않습니다. 또한 보안 기능(권한 부여, 암호화)에 대한 플래그도 피해야 합니다. 이러한 플래그를 비활성화하면 취약점이 발생합니다. 인프라 변경(데이터베이스 마이그레이션, 새 아키텍처로 마이그레이션)의 경우 feature flags는 유용하지만 특히 철저한 테스트가 필요합니다.
주요 접근 방식은 매트릭스 테스트입니다. 모든 플래그 조합으로 테스트를 실행합니다. CI/CD의 경우 비용이 너무 많이 들 수 있으므로(2^n 조합), 실제로는 모든 플래그를 개별적으로 두 상태(켜기/끄기)에서 테스트하고 중요한 조합만 테스트합니다. 단위 테스트는 플래그 값을 모의해야 합니다. 통합 테스트는 알려진 플래그 값으로 특정 시나리오를 확인합니다. E2E 테스트는 가장 가능성 있는 조합을 다룹니다.
제거 프로세스: 1) 플래그가 모든 사용자에 대해 100% 활성화되어 있고 실험 모드에서 사용되지 않는지 확인합니다. 2) 코드에서 플래그의 모든 조건부 검사를 제거하고 “새” 브랜치만 남깁니다. 3) 관리 시스템에서 플래그 정의를 제거합니다. 4) 제거된 플래그에 대한 모의를 제거하여 테스트를 업데이트합니다. CI를 통해 이 프로세스를 자동화하는 것이 좋습니다. N일 이상 변경되지 않은 플래그는 오래된 것으로 표시되고 제거 확인이 필요합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.