フィーチャーフラグ

コードをデプロイした後に、機能の有効/無効を動的に切り替える仕組み

デプロイ運用

フィーチャーフラグとは

フィーチャーフラグ (Feature Flag / Feature Toggle) は、コードをデプロイした後に、設定値の変更だけで機能の有効/無効を切り替える仕組みである。未完成の機能をメインブランチにマージしつつ本番では無効にしたり、特定のユーザーにだけ新機能を公開したりできる。

Martin Fowler が 2010 年 10 月に自身の bliki で「Feature Toggle」として取り上げたのが広まりの起点で、後述する 4 分類や実装パターンを含む体系的な整理は Pete Hodgson が 2017 年 10 月に martinfowler.com へ寄せた記事による。Fowler は 2023 年 7 月の追記で、呼称は当時の「toggle」より「flag」が定着したと書いている。今ではトランクベース開発カナリアリリースの基盤技術として広く使われている。

基本的な実装

基本的な実装のコード例を示す。

// シンプルなフィーチャーフラグ
if (featureFlags.isEnabled('new-checkout-flow', { userId })) {
  return renderNewCheckout();
} else {
  return renderLegacyCheckout();
}

フラグの 4 分類

フラグの 4 分類を以下に整理する。

種類寿命動的性用途
リリースフラグ短命 (1〜2 週間)静的未完成機能を隠す
実験フラグ短命 (数時間〜数週間)動的A/B テスト
運用フラグ短命〜長命動的キルスイッチ、サーキットブレーカー
パーミッションフラグ長命 (年単位)動的ユーザーごとの機能制御

この 4 分類は Hodgson の整理 (Release / Experiment / Ops / Permissioning Toggles) に対応し、上表の寿命も同記事の見積もりに沿っている。リリースフラグは 1〜2 週間を超えて残すものではなく、機能が安定したら削除する (公開をマーケティング施策に合わせるなど、プロダクト都合の場合だけ長引く)。実験フラグは統計的に有意な結果が出るまで同じ設定で置く必要があり、目安は数時間から数週間である。それより長く置いても、その間の他の変更が実験結果を汚すので利点は薄い。運用フラグも多くは短命で、運用面の確信が持てた時点で削除する。長期に残るのは、高負荷時に重い非中核機能を落とすキルスイッチのような少数の制御だけだ。パーミッションフラグは有償ユーザー向け機能のように提供が続く限り残るため、年単位になることもある。寿命が違うものを同じ管理方法で扱うと、消し忘れたリリースフラグが分岐だけ増やして残るので、分類ごとに削除の期限を決めておく。

AWS での実装パターン

SSM Parameter Store (シンプル)

import { SSMClient, GetParameterCommand } from '@aws-sdk/client-ssm';

const ssm = new SSMClient({});
let cachedFlags: Record<string, boolean> | null = null;
let cacheExpiry = 0;

async function isEnabled(flagName: string): Promise<boolean> {
  if (Date.now() < cacheExpiry && cachedFlags) return cachedFlags[flagName] ?? false;

  const result = await ssm.send(new GetParameterCommand({
    Name: '/myapp/feature-flags',
  }));
  cachedFlags = JSON.parse(result.Parameter!.Value!);
  cacheExpiry = Date.now() + 60_000; // 1分キャッシュ
  return cachedFlags![flagName] ?? false;
}

AWS AppConfig (高機能)

AppConfig はフィーチャーフラグ用の構成タイプを持ち、デプロイ戦略 (対象割合を線形または指数的に増やす)、CloudWatch アラームと連動した自動ロールバックを設定できる。ただし既定の段階デプロイが増やすのは「値を取りに来た呼び出し側の割合」であって、同じユーザーが常に同じ値を受け取る保証はない。ユーザーやセグメント単位で値を固定したい場合は、AppConfig Agent のエンティティ単位の段階デプロイを使う。Lambda Extension として組み込めば、Lambda 関数から低レイテンシでフラグを取得できる。

段階的ロールアウト

新機能を全ユーザーに一斉公開するのではなく、段階的に公開する。

Day 1: 社内ユーザーのみ (1%)
Day 3: ベータユーザー (10%)
Day 5: 全ユーザーの半分 (50%)
Day 7: 全ユーザー (100%)

各段階でエラー率やパフォーマンスを監視し、問題があればフラグを無効化して即座にロールバックする。デプロイのロールバックより圧倒的に速い。

フラグの技術的負債

フィーチャーフラグの最大の問題は、不要になったフラグが削除されずに残ること。フラグが増えると条件分岐が複雑化し、取り得るフラグ状態の組み合わせも指数的に増える。ただし全組み合わせを検証する必要はない。多くのフラグは互いに干渉せず、1 回のリリースで切り替えるフラグも通常 1 個なので、本番で想定する構成 (現行の構成 + 今回 On にするフラグ) と、その切り戻し構成の 2 通りを押さえるのが基本になる。

対策

  • フラグ作成時に「削除予定日」をメタデータに設定する
  • CI で期限切れフラグを検出して警告する
  • フラグの数に上限を設ける (例: アクティブなフラグは 20 個まで)
  • リリースフラグは機能安定後 1 週間以内に削除する

フィーチャーフラグについては関連書籍でも詳しく扱われている。

この記事は役に立ちましたか?

関連用語

関連する記事