フィーチャーフラグが技術的負債になるとき

フィーチャーフラグを使って新機能をリリースした。うまくいった。ユーザーに受け入れられた。フラグは全ユーザーに対して有効のままになった。数ヶ月が経った。今、そのフラグはまだコードの中にあり、前四半期の他の3つのフラグ、6ヶ月前の2つのフラグ、そして誰も何を制御しているか覚えていないフラグの隣に座っている。

これは珍しいことではない。多くのチームは良い意図を持ってフィーチャーフラグを使い始める。より安全なリリース、段階的なロールアウト、緊急時のキルスイッチ。しかし、決して削除されないフラグは、徐々に別の種類の問題に変わっていく。それらはリリース制御ツールではなくなり、全員の速度を落とす技術的負債になり始める。

放置されたフラグの本当のコスト

コードに残されたフラグはそれぞれ、判断ポイントを追加する。開発者が関数を読むとき、彼らは自問しなければならない。この分岐はまだ使われているのか?あれは安全に削除できるか?古いコードパスを削除してもいいのか、それともまだ誰かが使っているのか?

1つか2つのフラグなら、これは管理可能だ。数十個になると、コードを読むことは推測ゲームになる。結局、誰もどのパスが生きているか確信が持てないif-elseブロックができあがる。かつては単純だったコードが、誰もが触るのを恐れる条件ロジックの迷路と化す。

実行時のコストもある。アプリケーションが実行されるたびに、各フラグが評価される。1回のフラグチェックは軽い。しかし、ホットコードパスでの何百ものフラグチェックは積み重なる。常に同じ値を返すフラグの評価に費やされるCPUサイクルは無駄だ。決して変わらないフラグ設定を保存するために使われるメモリは無駄だ。時間が経つにつれて、このオーバーヘッドは、特に高トラフィックのサービスでは測定可能になる。

すべてのフラグにはライフサイクルが必要

解決策はフィーチャーフラグの使用をやめることではない。解決策は、すべてのフラグを最終的に削除しなければならないものとして扱うことだ。フィーチャーフラグには、作成された瞬間から明確なライフサイクルがなければならない。

次の図は、フィーチャーフラグの意図されたライフサイクルと、削除がスキップされた場合に何が起こるかを示している。

flowchart TD A[フラグ作成] --> B[内部テスト] B --> C[段階的ロールアウト] C --> D[フルロールアウト] D --> E[機能安定] E --> F[フラグ削除] E -.-> G[フラグ未削除] G --> H[技術的負債蓄積] H --> I[コード複雑性増加] H --> J[実行時オーバーヘッド] H --> K[開発者の混乱] F --> L[クリーンなコードベース]
  1. 新しい機能の作業が始まるときにフラグが追加される。
  2. 内部テストのために有効化される。
  3. ユーザーの一部に段階的にロールアウトされる。
  4. 全ユーザーに対して有効化される。
  5. 機能が本番環境で安定していることが確認される。
  6. フラグが削除される。

ステップ6は、ほとんどのチームがスキップするものだ。機能は動作している。誰もが使っている。フラグはまだ有効なので、なぜわざわざ削除するのか?フラグが残っている日ごとに、摩擦が増える。コードは読みにくくなる。次の変更にはより時間がかかる。どのコードパスが実際にアクティブなのか誰も確信が持てないため、バグを導入するリスクが高まる。

フラグを削除するタイミング

フラグを削除する適切なタイミングは、そのフラグが制御する機能が安定し、完全にロールアウトされた直後だ。チームによっては、機能が100%のユーザーに到達してから1〜2スプリント以内にフラグを削除するという厳格なルールを設定している。他のチームは、一定期間以上アクティブな設定キーにフラグを立てる自動リマインダーを使用している。

フラグを削除することは、条件チェックを削除するだけではない。フラグが保護していた古いコードもクリーンアップする必要がある。新しい機能が古い機能を置き換えた場合は、古いコードパスを完全に削除する。デッドコードを残してはいけない。デッドコードは無害ではない。開発者を混乱させ、ビルド時間を無駄にし、誰かが後でまだ使われていると思って修正した場合に微妙なバグを引き起こす可能性がある。

設定側では、フラグ管理システムからもフラグを削除する。コードから削除されたが、ダッシュボードや設定ファイルにまだ表示されているフラグは混乱を引き起こす。誰かが最終的にそのフラグがまだ必要かどうか尋ねることになるが、誰も明確な答えを持っていない。

削除をプロセスの一部にする

フラグが積み重なるのを防ぐ最も効果的な方法は、フラグが作成されたときに削除計画を必須にすることだ。開発者が新しいフィーチャーフラグを追加するプルリクエストを開くとき、そのPRにはフラグをいつ、どのように削除するかに関するメモを含めるべきだ。これはコード内のコメント、プロジェクト管理ツールのタスク、またはフラグシステム自体の自動有効期限にすることができる。

さらに進んで、プログラムでフラグの有効期限を強制するチームもある。フラグシステムは、必須の有効期限日を含まない新しいフラグを拒否する。日付が過ぎると、システムは通知を送信するか、自動的にフラグを無効にする。これにより、チームはフラグを削除するか、正当な理由を添えて明示的に有効期間を延長することを余儀なくされる。

これは、月に1つの機能をリリースする小規模チームにとってはオーバーヘッドに聞こえるかもしれない。しかし、このパターンはスケールする。複数のチームが並行して複数の機能をリリースするようになると、手動のフラグ管理は持続不可能になる。早期に構築した規律が、後で苦しいクリーンアップからあなたを救うだろう。

フラグクリーンアップの実践的チェックリスト

今日からフラグのクリーンアップを始めたいなら、ここにシンプルなプロセスがある。

  • 現在コードベースと設定システムにあるすべてのフラグを特定する。
  • 各フラグについて、そのフラグが制御する機能が完全にロールアウトされ、安定しているかどうかを判断する。
  • 機能が安定している場合、コードからフラグを削除し、古いコードパスを削除する。
  • 設定またはフラグ管理システムからフラグを削除する。
  • フラグを参照しているドキュメントやランブックを更新する。
  • 新しいフラグについては、それを導入するプルリクエストに削除計画を追加する。

これは一度きりの作業ではない。定期的なプラクティスにしよう。四半期に一度のスプリントをフラグクリーンアップに充てるチームもある。すべての機能の完了条件にそれを追加するチームもある。あなたのチームに合ったリズムを見つけて、それを守ろう。

結論

フィーチャーフラグはリリースを制御しリスクを減らすための強力なツールだ。しかし、それらは無料ではない。有用な期間を超えて保持されたすべてのフラグは、複雑性を追加し、開発を遅らせ、ミスの可能性を高める。目標はフラグを避けることではない。目標は規律を持ってそれらを使用し、目的を果たしたら削除することだ。

フラグを積み上げたままにすると、それらはリリース制御メカニズムではなくなり、チームが毎日背負う重荷になる。それらをクリーンアップしよう。将来の自分、そして来月あなたのコードを読まなければならない開発者が感謝するだろう。