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が同じではありません。マーティン・ファウラーは、4種類のフラグを分類しています。これらは使用目的、存続期間、管理要件が異なります。適切なフラグ分類は、適切なインフラストラクチャを選択し、一般的な問題を回避するのに役立ちます。
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は4つの段階を経ます:作成、使用、安定化、削除です。作成段階では、フラグキー、タイプ、デフォルト値が定義されます。使用中は、チームが誰がどのような目的でどのオーディエンスに対してフラグを有効にしたかを監視します。安定化後(機能が完全に準備されテスト済み)、フラグはコードから削除されなければなりません。削除プロセスはコードレビューを通じて自動化されます。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%のフラグが不要になった後もコードに残り続けています。解決策:“1つのフラグ — 1つのタスク”ルールを実装します。フラグを作成する際、タスクトラッカーに期限付きの削除タスクを作成します。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アプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。