フィーチャートグル(機能フラグ)とは?4種類の使い分けと実装例・削除までの運用

フィーチャートグル(機能フラグ)とは?4種類の使い分けと実装例・削除までの運用

フィーチャートグル(Feature Toggle)は、コードを本番へデプロイしたまま、機能を有効にするかどうかを設定値で切り替える手法です。フィーチャーフラグ、機能フラグ、feature switchとも呼ばれます。仕組みはif文1つで済みますが、目的の違う種類のフラグを同じように扱うと、使い終わった分岐がコードに残り続けます。

この記事では、Pete HodgsonがMartin Fowlerのサイトで整理した4種類の分類を軸に、寿命ごとの扱い方、Pythonで動かした段階公開の実装例、OpenFeatureや各ツールの選び方、フラグの再利用が大きな損失につながった事例までを扱います。

まとめ:フィーチャートグル導入で決めておく5項目

  • 種類を決める:Release・Experiment・Ops・Permissionのどれかを作成時に決めます。寿命と、切り替えの動的さが種類ごとに違います。
  • 削除期限を決める:Release Toggleは1〜2週間程度で消す前提のものです。作成と同時に削除タスクも起票します。
  • 振り分けは決定的にする:段階公開ではユーザーIDのハッシュで振り分けます。乱数で振り分けると、アクセスのたびに表示が変わってしまいます。
  • フラグ名を使い回さない:Knight Capitalは旧機能のフラグを新機能に転用し、4億6,000万ドルの損失を出しました。
  • ツールは寿命の長いフラグの数で選ぶ:短命のフラグが数本なら設定ファイルで足ります。長く残るPermissionやOpsのフラグが増えてきたら、管理画面と監査ログのある仕組みへ移します。

以下では、定義、種類、実装、ツール、失敗事例、運用ルールの順に説明します。

フィーチャートグルの定義と別名

Pete Hodgsonは、フィーチャートグルをコードの変更なしにシステムの振る舞いを切り替える手法として説明しています。日本語版Wikipediaは別名として、feature switch(機能スイッチ)、feature flag(機能フラグ)、feature flipper、conditional featureが挙げられています。呼び方が違っても指すものは同じで、このサイトでは主にフィーチャートグルと書きます。

デプロイとリリースを分ける仕組み

フィーチャートグルを使うと、コードを本番環境に置くこと(デプロイ)と、利用者に機能を見せること(リリース)が別の操作になります。フラグがOFFの間、新しいコードは本番にあっても実行されません。設定を実行中に再読み込みできる仕組みなら、フラグをONにするだけで公開でき、再デプロイは不要です。起動時に設定を読み込む方式では再起動が、設定を成果物に含める方式では再デプロイが必要になる場合があります。問題が見つかった場合は、旧処理とデータの互換性が保たれていれば、フラグをOFFにして以後の処理を旧経路へ戻せます。すでに生じたデータ変更や外部への副作用は取り消せません。

Martin FowlerのBliki記事「FeatureFlag」も、開発に時間のかかる機能をメインラインへ統合し続けながら、未完成の部分を利用者に見せない方法としてこの仕組みを説明しています。実行中のアプリケーションが、設定されたフラグを見て新機能を出すかどうかを決めます。

フィーチャーブランチとの違い

フィーチャーブランチでは、未完成の機能をGitのブランチで隔離します。フィーチャートグルでは、未完成の機能もメインブランチへマージし、実行時の条件分岐で隔離します。ブランチが長く分かれたままだとマージ時の衝突が大きくなりますが、トグルを使えばこの問題は起きにくくなります。代わりに、コードの中に分岐が残るという負担を抱えます。ブランチの種類と運用の基本はGitブランチの種類とブランチ戦略の解説で扱っています。

両者はどちらか一方を選ぶものではありません。併用の例として、1〜2日で終わる作業は短命のブランチで進め、数週間かかる機能のうち先に本番へ配置する部分をトグルで隠す運用が考えられます。

フィーチャートグル4種類の寿命と動的性

Pete Hodgsonがmartinfowler.comで公開し、2017年10月9日に更新した「Feature Toggles (aka Feature Flags)」は、フラグを目的別に4種類へ分けています。種類によって、どれだけ長く残るか(寿命)と、どれだけ細かく判定が変わるか(動的性)が大きく違います。

種類 主な用途 寿命 動的性
Release Toggle 未完成機能を隠す 1〜2週間程度 非常に静的
Experiment Toggle A/Bテスト 数時間〜数週間 非常に動的
Ops Toggle 障害時の機能停止 多くは短命・一部は無期限 即時変更が必要
Permission Toggle 有料・社内向け機能 複数年に及ぶ 非常に動的

Release Toggleは「transitionary by nature」、つまり移行期間のためのもので、原則として1〜2週間程度より長く残すべきではないとされています。ただし、プロダクト側の都合で公開時期を決めるトグルは、それより長く残ることもあるとHodgsonは補足しています。判定は全利用者で同じ値になることが多く、切り替えもリリースのときだけです。

Experiment Toggleは、統計的に有意な結果が出るまでの数時間から数週間だけ使います。リクエストごとに、利用者がどの群に属するかで結果が変わります。

Ops Toggleの多くは、新機能の運用面に確信が持てた時点で役目を終えます。ただし、負荷が高いときに重い処理を止めるキルスイッチのように、ほぼ無期限に残すものもあります。これらは障害時にすぐ切り替えられる必要があります。

Permission Toggleは、有料プランの機能を制御する場合など、複数年にわたって残ることがあります。権限は利用者ごとに違うため、判定は常にリクエスト単位です。

この表から導ける実務上の判断は1つです。寿命の短いReleaseやExperimentのフラグと、長く残るOpsやPermissionのフラグを、同じ期限ルールで管理してはいけません。LaunchDarklyも公式ドキュメントで、目的を果たしたら削除するtemporaryフラグと、機能がある限り残るpermanentフラグを区別しています。

フィーチャートグルの構成要素

Hodgsonの記事は、フィーチャートグルの実装を次の4つの要素に分けて説明しています。

  • Toggle Point:コードの中で、フラグを見て処理を分岐させる箇所です。
  • Toggle Router:フラグがONかOFFかを実際に判定する部品です。
  • Toggle Context:判定に使う情報です。ユーザーID、プラン、国などがあたります。
  • Toggle Configuration:どの条件でONにするかの設定です。

Toggle Pointに判定ロジックを直接書くと、同じ条件がコードのあちこちに散らばり、あとで削除するときに漏れが出ます。判定はToggle Routerにまとめ、Toggle Pointでは「このフラグは有効か」を問い合わせるだけにします。これが、フラグを消しやすいコードにするための基本です。

実装例:Pythonで作る段階公開つきトグルルーター

次のコードは、Toggle Routerを最小限の形で実装したものです。フラグ全体のON/OFF、特定ユーザーの許可リスト、全体の何%に公開するかの3つを扱います。設定はプロセス内のメモリに保持する例であり、複数プロセス間の同期や外部からの設定更新は含みません。Python 3.14.6で実行しました。

import hashlib

FLAGS = {
    "new-checkout": {"enabled": True, "rollout_percent": 10, "allow_users": {"qa-001"}},
}

def bucket(flag_key: str, user_id: str) -> int:
    digest = hashlib.sha256(f"{flag_key}:{user_id}".encode()).hexdigest()
    return int(digest[:8], 16) % 100

def is_enabled(flag_key: str, user_id: str) -> bool:
    flag = FLAGS.get(flag_key)
    if flag is None or not flag["enabled"]:
        return False
    if user_id in flag["allow_users"]:
        return True
    return bucket(flag_key, user_id) < flag["rollout_percent"]

if __name__ == "__main__":
    users = [f"user-{i}" for i in range(10000)]
    print("ON:", sum(is_enabled("new-checkout", u) for u in users), "of", len(users))
    print("user-7 bucket:", bucket("new-checkout", "user-7"),
          "results:", {is_enabled("new-checkout", "user-7") for _ in range(100)})
    FLAGS["new-checkout"]["rollout_percent"] = 50
    print("ON at 50%:", sum(is_enabled("new-checkout", u) for u in users))
    FLAGS["new-checkout"]["enabled"] = False
    print("kill switch, qa-001:", is_enabled("new-checkout", "qa-001"))

実行結果は次のとおりです。

ON: 1020 of 10000
user-7 bucket: 63 results: {False}
ON at 50%: 4933
kill switch, qa-001: False

ハッシュで振り分けを固定する理由

10%に設定すると、1万人中1,020人がONになりました。user-7のバケット値は63なので、100回判定しても結果は毎回Falseです。乱数で振り分けると、同じ人がページを開くたびに新しい画面と古い画面を行き来してしまいます。フラグ名とユーザーIDを連結したものをハッシュにかけるのは、これを防ぐためです。フラグ名も含めているので、別のフラグでは同じ人が別のバケットに入ります。

公開範囲を50%に広げるとONは4,933人になりました。別途確かめたところ、10%の段階でONだった1,020人は全員、50%の段階でもONのままでした。バケット値は変わらず、しきい値が上がるだけなので、一度新機能を見た人が段階を進めた途端に古い画面へ戻ることはありません。

最後の行は、enabledをFalseにすると、許可リストに入っているqa-001も含めて全員がOFFになることを示しています。障害時のキルスイッチは、許可リストより先に判定しないと効きません。

OpenFeatureの評価APIとProviderによるベンダー依存の分離

OpenFeatureは、フィーチャーフラグを評価するAPIを標準化するプロジェクトです。2022年6月17日にCNCFに採択され、2023年11月21日にIncubatingへ移行しました。アプリケーションはOpenFeatureのAPIだけを呼び、実際のフラグ管理システムとの間はProviderが仲介します。対応するProviderへ差し替えることで、アプリケーションの評価API呼び出しを維持しやすくなります。ただし、移行先でのフラグ定義、評価条件、認証設定、Evaluation Contextの対応付けは別途確認が必要です。仕様には、判定に使う情報を渡すEvaluation Contextと、評価のbefore・after・error・finallyの4段階に処理を差し込むHooksも定められています。

次のコードは、openfeature-sdk 0.10.0に含まれるInMemoryProviderで動かした例です。実行するPython環境に、python -m pip install openfeature-sdk==0.10.0で依存パッケージを導入してから実行します。

from openfeature import api
from openfeature.evaluation_context import EvaluationContext
from openfeature.provider.in_memory_provider import InMemoryFlag, InMemoryProvider

api.set_provider(InMemoryProvider({
    "new-checkout": InMemoryFlag(
        default_variant="off",
        variants={"on": True, "off": False},
    ),
}))
client = api.get_client()
ctx = EvaluationContext(targeting_key="user-42")

details = client.get_boolean_details("new-checkout", False, ctx)
print(details.value, details.variant, details.reason)

missing = client.get_boolean_details("typo-flag", False, ctx)
print(missing.value, missing.reason, missing.error_code)
False off STATIC
False ERROR FLAG_NOT_FOUND

注目したいのは2行目です。存在しないフラグ名を渡しても例外は発生せず、呼び出し側が指定した既定値のFalseが返ります。フラグ名を打ち間違えると、機能は黙ってOFFのままになります。OpenFeatureを使う場合は、呼び出し後に戻り値のreasonとerror_codeを確認するか、errorフックで渡された例外を記録します。あわせて、フラグ名を定数にまとめて文字列を直接書かないようにします。

フィーチャートグル管理ツールの選び方

管理ツールを選ぶときの目安は、長く残るフラグの数と、エンジニア以外の人がフラグを切り替えるかどうかです。短命のReleaseフラグが数本しかないなら、上の実装例のように設定ファイルや環境変数で十分です。

ツール 形態 版・提供状況(2026年9月時点)
Unleash OSS(AGPL-3.0) v8.2.0(2026年9月8日)
flagd OpenFeatureのOSS評価エンジン v0.16.3(2026年9月10日)
Flipper Ruby gem(MIT) 1.4.2(2026年5月11日)
GitLab Feature Flags GitLabの機能 Free・Premium・Ultimate
LaunchDarkly SaaS booleanとmultivariateに対応
App Lifecycle Manager Google Cloud Preview

OSSを自社で運用するなら、Unleashとflagdが候補になります。UnleashのリポジトリはAGPL-3.0なので、改変して外部に提供する場合はライセンス上の義務を確認してください。GitLab Feature FlagsはUnleash互換のAPIを提供しているため、アプリケーション側ではUnleash互換のクライアントライブラリをそのまま使えます。すでにGitLabを使っているなら、Freeプランでも追加の基盤なしで始められます。

RailsアプリならFlipperが手軽です。フラグの状態をActiveRecordやRedisに保存できるので、アプリを動かしたまま切り替えられます。

LaunchDarklyのようなSaaSが向くのは、プロダクト担当者が管理画面から公開範囲を操作し、変更履歴を監査する必要がある場合です。LaunchDarklyのフラグは、true/falseの2値を持つbooleanと、文字列・数値・JSONで2つ以上の値を持てるmultivariateの2種類です。モバイルアプリの条件配信を扱うなら、Firebase Remote Configの条件配信と段階ロールアウトも選択肢に入ります。Google CloudのApp Lifecycle Managerにも機能フラグがありますが、概要ページの表示はPreviewのため、本番で使う前に提供条件を確認してください。

どのツールを選ぶ場合でも、アプリケーションからはOpenFeatureのAPIを呼ぶ形にしておくと、後で乗り換えるときに評価APIの呼び出し部分の変更を抑えられます。ただし、対応Providerの有無と、フラグ定義・評価条件・認証設定の移行は別途確認します。

フィーチャートグルのデメリットと失敗事例

テストすべき組み合わせの増加

フラグが1本増えるたびに、理論上の設定の組み合わせは2倍になります。フラグが10本あれば1,024通りで、すべてを試すのは現実的ではありません。Hodgsonは、少なくとも本番で有効になる予定の設定、つまり現在の本番設定に、これからONにするフラグを加えた組み合わせをテストするよう勧めています。あわせて、公開予定のフラグをOFFに戻したフォールバック設定もテストします。全フラグをONにする追加テストは、OFFが既存動作、ONが新動作という規約にそろえ、同時にONにできるフラグを対象にします。

フラグの再利用が招いた4億6,000万ドルの損失

米証券取引委員会(SEC)の命令文(Release No. 34-70694)によると、Knight Capitalは2012年8月1日、ニューヨーク証券取引所のRetail Liquidity Program(RLP)に対応する新しいコードを有効にするために、廃止済みの機能「Power Peg」に使っていたフラグを再利用しました。ところが、8台のサーバーのうち1台には新しいコードが配置されておらず、Power Pegの古いコードが残っていました。フラグをONにした結果、そのサーバーで古い機能が動き出し、大量の意図しない注文が出されました。Knightはこのポジションで4億6,000万ドルの損失を計上しています。

この事例からわかることは2つあります。1つは、使い終わったフラグの分岐を削除していなかったことです。もう1つは、同じ名前のフラグに別の意味を持たせたことです。フラグ名は一度使ったら再利用しない。廃止した機能のコードは、フラグと一緒に削除する。この2点をルールにしておけば、同じ種類の事故は防げます。

フィーチャートグルを残さない運用ルール

Hodgsonは、フラグを保有コストのかかる在庫として扱うよう勧めています。以下では、原典の削除タスク・期限・本数上限の提案に、本記事の期限設定と命名の運用例を加えています。

  • 作成時に削除タスクを起票する:Release Toggleなら、公開予定日から2週間後を期限にします。
  • 期限切れでテストを失敗させる:期限を過ぎたフラグが残っているとテストが落ちる、時限爆弾(time bomb)型のチェックを入れます。
  • 本数に上限を設ける:チームごとに有効なフラグの上限を決め、新しく作るには既存のフラグを1本消す必要がある運用にします。
  • 名前に種類を入れ、担当者を別途記録する:たとえば release.checkout-v2 のように種類を接頭辞にすると、一覧を見るだけで削除期限のあるフラグかどうかがわかります。
  • 削除の完了を分岐の削除で判定する:管理画面でフラグを消しても、コードのif文が残っていれば削除したことにはなりません。

長寿命のOpsやPermissionのフラグは、この期限ルールの対象外として別の一覧で管理します。短命のOpsフラグには、運用上の確認が完了した時点で削除する条件を設定します。期限のない長寿命のフラグにまで削除期限を課すと、必要なキルスイッチまで消されてしまいます。

フィーチャートグルを使うべきでない場面

Martin FowlerはBliki記事で、Release Flagの有用性を認めつつも、「they should be your last choice」、つまり最後の選択肢にすべきだと書いています。先に検討すべきなのは、機能を小さく分割して1つずつ公開できるようにする方法と、Keystone Interfaceです。Keystone Interfaceは、裏側の実装を先に作って本番に置き、利用者が触れる入口(画面やAPIの公開部分)を最後に追加するやり方です。入口が無いうちは、裏側のコードに利用者は到達しません。

次の条件に当てはまる場合は、トグルを使わない方が安全です。

  • 作業が1〜2日で終わり、ブランチを短く保てる
  • データベースのスキーマ変更を伴い、ONとOFFで互換性のないデータが書き込まれる
  • 入口を最後に作る設計が取れる(Keystone Interfaceで足りる)
  • チームにフラグを削除する担当と期限の運用がまだ無い

スキーマ変更については、フラグをOFFに戻してもデータは元に戻りません。フラグで戻せるのはコードの経路だけです。この点を誤解したままキルスイッチを当てにすると、障害時に役に立ちません。

段階公開・A/Bテストへの応用

上の実装例のrollout_percentを1%、10%、50%、100%と上げていけば、利用者単位の段階公開になります。サーバー単位でトラフィックを振り分けるカナリアリリースの仕組みと他方式との違いは代表的な実装例です。カナリアリリースは利用者単位でも実現でき、フィーチャートグルもその手段になります。この実装例ではユーザーIDで出し分けるため、ログイン済みの利用者に対して一貫した体験を保てます。

メトリクスを見ながら公開範囲の拡大と切り戻しを自動で判断する運用は、プログレッシブデリバリーの自動分析と昇格判断で詳しく扱っています。新しい処理を利用者に見せずに本番トラフィックで動かすだけなら、ダークローンチによる裏側の検証も選択肢になります。

A/Bテストに使う場合は、Experiment Toggleとして扱い、結果が出たらフラグと負けた側のコードを両方削除します。

よくある質問

フィーチャートグルとフィーチャーフラグは違うものですか?

同じものを指します。Feature Toggle、Feature Flag、機能フラグ、feature switchはいずれも、コードを変えずに設定値で機能のON/OFFを切り替える手法の呼び名です。

フィーチャーフラグの種類は?

Pete Hodgsonの分類では、Release・Experiment・Ops・Permissionの4種類です。Releaseは1〜2週間程度の短命なフラグ、Permissionは複数年残ることもある長寿命のフラグで、種類によって削除期限の決め方が変わります。

フィーチャーフラグのデメリットは?

コードに条件分岐が増え、テストすべき設定の組み合わせも増えることです。使い終わったフラグを消さずに残すと技術的負債になります。Knight Capitalの2012年の事故のように、古いフラグを再利用して大きな損失を出した例もあります。

キルスイッチとは何ですか?

障害や高負荷のときに、特定の機能をすぐ止めるためのOps Toggleです。多くのOps Toggleは短命ですが、キルスイッチは長く残すことが多いため、削除期限のあるフラグとは別に管理します。判定では、許可リストより先にキルスイッチを評価します。

フィーチャートグルは自前で実装すべきですか?

短命のフラグが数本なら、設定ファイルと数十行のコードで足ります。長寿命のフラグが増えた場合や、エンジニア以外の人が切り替える場合は、UnleashやLaunchDarklyなどのツールに移します。アプリケーション側でOpenFeatureのAPIを使っておくと、移行時の書き換えが少なく済みます。

関連記事

資料請求

RELATED POSTS 関連記事