コードをデプロイすることと機能を有効化することは、異なる判断です。しかし多くのPHPアプリケーションでは、両者が同時に行われます。新しいバージョンが本番環境へ届くと、すべてのユーザーベースに対して利用可能になります。このモデルは小規模で元に戻せる変更には機能しますが、マイグレーション、新しいビジネスルール、外部連携、あるいは限定グループで検証すべき体験が関わる場合には、リスクを高めます。
PHPのfeature flagにより、これら二つの判断を切り離せます。コードはデプロイ済みで、テスト済みかつ準備完了のまま、機能は無効にしておくか、定義済みのセグメントに対してのみ有効化できます。利点はスイッチを蓄積することではなく、影響範囲を縮小し、新バージョンをリリースせずに有効化を元に戻せることです。
コストは存在します。各flagは状態、可能な組み合わせ、およびガバナンスの責務を増やします。そのため有用な実装では、flagを一時的かつ運用上のプロダクト要素として扱い、担当者、目的、レビュー日、撤去計画を持たせる必要があります。
問題:デプロイは全員への有効化を意味すべきではない

ソフトウェアのリリースには、すぐに公開すべきでない変更を含めることがあります。たとえば、新しい割引計算方法は少数の組織での確認を必要とする場合があります。決済プロバイダーは技術的には統合済みでも、商業上の検証待ちかもしれません。あるいは、再設計した画面は全般的に有効化する前にサポート部門によるレビューを必要とする場合があります。
flagがなければ、代替策は通常、効率的ではありません。長期存続ブランチを維持する、準備済みの変更のデプロイを遅らせる、または問題のある有効化を取り消すために緊急修正を公開することになります。分岐したブランチは統合コストを高めます。デプロイの延期は無関係な変更を混在させます。そしてバージョン全体をリバートすると、必要な修正まで取り除く可能性があります。
適切に適用したflagでは、まず現在の振る舞いをデフォルト値としてデプロイできます。次にチームは新しい振る舞いを限定セグメントに対して有効化し、その影響を観察して、公開範囲を拡大または戻します。重要なのは、flagがテスト、コードレビュー、データのロールバック計画に代わるものではない点です。これは有効化判断の範囲を縮小するだけです。
feature flagを使う場合と別の方法を選ぶ場合
有効化が段階的、可逆的、かつ対象指定である必要がある場合にflagを使用してください。機能上のリスクを伴う変更、組織単位のリリース、権限に依存する有効化、二つのフローが一時的に共存するマイグレーション、または負荷の制限や連携の無効化を可能にする運用メカニズムでは、特に合理的です。
すべての設定オプションがfeature flagに値するわけではありません。内部URLやユーザー単位で管理しない技術的な上限値など、環境の安定した特性を表すなら、単純な設定のほうが適しています。維持コストを負担する前提であれば、意図的に恒久化するバリアントにはプロダクトブランチが適切な場合があります。コンポーネントごとにライフサイクル、権限、スケーリング要件が独立している場合は、個別のデプロイが適合します。
また、期限のないプロダクト判断を隠すため、変更しにくいアーキテクチャを補うため、あるいは要件への合意を避けるためにflagを使うべきではありません。ある条件がドメイン内に無期限で残るなら、暫定スイッチではなく明示的なビジネスルールとしてモデル化すべきです。
flagの種類と目的を混在させるリスク
- リリースflag:検証完了まで新しい機能の利用可能性を制御します。
- セグメンテーションflag:特定のユーザー、組織、プラン、または権限に対して機能を有効化します。
- 運用flag:インシデント発生時に、コストの高いプロセスまたは外部依存を一時的に無効化します。
- 実験flag:定義済みの指標で仮説を評価するため、バリアントを配分します。
分類が重要なのは、誰がflagを変更できるか、どの証拠が必要か、いつ撤去すべきかを決めるためです。運用flagには、制限されたアクセスと即時対応が求められることがあります。実験flagには、ユーザーがリクエスト間でバリアントを変えないよう、安定した割り当てが必要です。リリースflagには、全体有効化へ移行する明確な基準が必要です。
一つのキーに目的を混在させないでください。機能をリリースし、バリアントを選択し、緊急スイッチも兼ねるflagは、解釈が困難になります。障害が発生した場合、割合を調整すべきか、条件を変更すべきか、フローを完全に停止すべきか、誰にも分からなくなります。
flagの最小モデルとガバナンス
flagは単なるキーと値の組であってはなりません。少なくとも、安定したキー、判断に焦点を当てた説明、所有者、種類、デフォルト値、許可される範囲、有効化条件、作成日、予定レビュー日または撤去日を記録してください。
checkout.new_payment_flowのようなキーは、flag_42より目的を明確に伝えます。安定性は重要です。非公式にキー名を変更すると、設定、管理パネル、自動化が壊れます。ドキュメントは、リポジトリの履歴を探さなくても、そのflagが何を変えるか、どのユーザーに影響し得るか、どの指標を監視するか、安全な状態へ戻す方法を答えられなければなりません。
リスクに応じて権限を定義してください。プロダクトはリリースの対象者と予定を提案できます。開発は依存関係と振る舞いを検証すべきです。運用またはオンコール担当の役割には、インシデント時に連携を無効化する能力が必要になる場合があります。変更は、実行者、時刻、実施した変更、理由とともに監査記録へ残す必要があります。すべてのロールに、機微な機能をグローバルに有効化する能力を与えないでください。
PHPでの技術設計:評価を一元化する
一般的な誤りは、コントローラー、テンプレート、コマンド、サービスにチェックを分散させることです。
if ($config['new_checkout']) {
// 新フロー
} else {
// 現行フロー
}このパターンは単純に見えますが、同じ判断が異なる形で適用され得る箇所を増やします。ドメインまたはアプリケーションのインターフェースの背後に評価を一元化してください。残りのコードは、具体的な設定ソースではなく、能力について問い合わせます。
interface FeatureDecider
{
public function enabled(string $feature, FeatureContext $context): bool;
}
if ($features->enabled('checkout.new_payment_flow', $context)) {
return $newCheckout->start($order);
}
return $currentCheckout->start($order);FeatureContextには、たとえば組織識別子、ユーザー識別子、権限、環境など、必要な属性だけを含めるべきです。実装は環境変数、データベース、設定サービスを読み取れますが、その判断がアプリケーション全体に漏れてはなりません。テストでは、インメモリ実装により外部インフラに依存せず状態を宣言できます。
共存が一時的である場合は二つの経路を近くに保ち、条件分岐を選択地点に限定してください。フローの細部をすべてflagで囲んではなりません。そうするとロジックが読みにくくなり、古い経路の削除が困難になります。両フローがステップを共有する場合は、そのステップを抽出し、flagには実際に変わる戦略だけを選択させてください。
安全なセグメンテーションと組み合わせのテスト
セグメンテーション基準は決定的で一貫していなければなりません。ユーザーまたは組織には安定した識別子を使用してください。割合指定では、組織識別子のような安定キーに決定的関数を適用し、リクエストごとに割り当てがランダムに変わらないようにします。ユーザーが組織に所属する場合は、どのIDを優先するかを定義してください。通常、組織を優先すると、同じチームのメンバー間で矛盾した体験を避けられます。
権限には明示的なルールが必要です。flagが特権を付与してはなりません。まず認可を検証し、その後で当該コンテキストに対して能力がリリース済みかを判断します。同様に優先順位を決定してください。たとえば個別除外は割合による包含より優先でき、グローバルな運用上の無効化はあらゆるセグメントより優先すべきです。
有効化前に最小マトリクスをテストしてください。flagがオフ、オン、コンテキストが含まれる、コンテキストが除外される、コンテキストがない、ルールが競合する、というケースです。評価器だけでなく、完全な処理経路が期待する状態に応答することを確認する統合テストも追加してください。デフォルトの振る舞いには専用テストが必要です。設定を利用できない、またはルールが無効な場合、アプリケーションは定義済みの安全な状態を採用し、問題を記録しなければなりません。
デプロイ、ロールバック、可観測性
- 安全なデフォルト値と既存フローをそのままにしてflagを導入します。
- コードをデプロイし、flagがオフの場合に振る舞いが変わらないことを確認します。
- 制御された環境または許可済みの内部セグメントに対して有効化します。
- 機能面および技術面の指標を確認しながら、定義した段階で対象範囲を拡大します。
- インシデント発生時は、それで一貫した状態へ戻るならflagを無効化します。不可逆なデータ変更がある場合は、固有の復旧計画を実行します。
- 判断が確定したら、flagと不要になった経路を削除します。
不要な個人属性を保存せず、重要な評価を記録してください。flagキー、結果、適用したバージョンまたはルール、コンテキストの仮名化した技術識別子、リクエストとの相関を保持すると有用です。これにより、エラーがコード、想定外の設定、誤ったセグメンテーションのどれに起因するかを区別できます。量も制御してください。高トラフィック経路ですべての評価を記録すると、ノイズとコストが生じる可能性があります。状態変更、エラー、追跡可能なサンプリングを優先してください。
計画的な撤去と最終チェックリスト

目的を終えた後も残るflagは技術的負債になります。レビューを予定し、期限切れのflagを可視化された保守作業として扱ってください。撤去では最終的な振る舞いを決定し、代替ブランチを削除し、破棄する振る舞いに関連するテストを削除し、管理ルールと権限を取り除き、ドキュメントを更新する必要があります。その後、コード、スケジュールタスク、テンプレート、自動化に参照が存在しないことを確認してください。
新しいflagを作成する前に、次を確認してください。
- デプロイと有効化を分離する具体的な理由がありますか。
- flagの種類と所有者は明確ですか。
- デフォルト値は安全で、テストされていますか。
- セグメンテーションは決定的で、認可済みであり、優先順位が定義されていますか。
- 指標、記録、有効化を拡大または停止する基準がありますか。
- データやプロセスを不整合な状態に残さずロールバックできますか。
- レビュー日と検証可能な削除計画がありますか。
これらの条件により、PHPのfeature flagは分散した条件分岐ではなく、制御されたデリバリーの仕組みになります。プロダクトに有用で、開発に理解しやすく、リスクを伴う変更にも運用可能です。



