まずは一部のユーザーに機能を公開する

新しいレコメンドエンジンが完成した。チームは自信を持っている。テストはパスした。コードレビューも終わった。しかし、全ユーザーに一斉にスイッチを入れるのをためらっている。ステージングでは問題なく動いた新ロジックが、本番トラフィックの下で異なる挙動を示したらどうしよう? ユーザーの回線が遅い場合にページが遅くなったら? あるいは、何か気まずいレコメンドをしてしまったら?

このためらいは健全な反応だ。機能をリリースする最も安全な方法は、まず少数のユーザーだけに公開することだ。問題なければ範囲を広げる。何か壊れても、影響を受けるのはその少数のグループだけだ。このパターンを**段階的ロールアウト(プログレッシブロールアウト)**と呼び、本番環境におけるフィーチャーフラグの最も実用的な使い方の一つである。

最もシンプルな方法:パーセンテージベースのロールアウト

露出を制御する最も簡単な方法は、トラフィックの割合に基づく方法だ。新しいレコメンド機能をテストしたいとする。フィーチャーフラグのダッシュボードを開き、フラグを5%に設定する。100リクエストのうち5つだけが新しいレコメンドを表示し、残りの95は旧バージョンを表示する。

このパーセンテージは徐々に増やせる。5%から始め、エラー率、応答時間、ユーザーフィードバックを監視する。すべてが良好なら10%、次に25%、50%と増やす。機能が安定したと確信できたら100%に設定し、古いコードを削除する。

このアプローチの利点は、即座に逆戻しできることだ。25%でエラー率が急上昇したら、パーセンテージを10%に下げるか、フラグを完全にオフにする。ロールバックも再デプロイも不要。設定変更だけで済む。

パーセンテージだけでは不十分な場合

単純なパーセンテージ以上の制御が必要な場合もある。特定のユーザーに最初に機能を試してもらいたいかもしれない。社内テスター、QAチームメンバー、ベータテストに同意してくれた協力的な顧客などだ。この場合、フィーチャーフラグにはターゲティングルールが必要になる。

最も一般的なターゲティングルールは、ユーザーIDに基づくものだ。新機能を表示してもよいユーザーIDのリストを管理する。それ以外のユーザーは旧バージョンを表示する。これは制御されたベータテストに便利だ。一部のユーザーを招待して早期に機能を試してもらい、残りのユーザーベースにはその機能の存在すら知らせない。

もう一つのターゲティングルールは地域によるものだ。まずインドネシアのユーザーに機能を公開し、他の国のユーザーは旧バージョンのままにする。これは、機能が地域の規制に準拠する必要がある場合や、特定のネットワーク状況やユーザー行動パターンの下でのパフォーマンスを確認したい場合に役立つ。

アカウントタイプ、アプリバージョン、デバイスモデル、システムがユーザーについて知っている任意の属性でターゲティングすることもできる。属性が多ければ多いほど、誰に何を表示するかをより正確に制御できる。

一貫性の問題

パーセンテージベースのロールアウトを使用する場合、一貫性を確保しなければならない。同じユーザーがセッション中に常に同じバージョンを表示されるようにする必要がある。あるページロードで新機能が表示され、次のロードで旧バージョンが表示されると、ユーザーは混乱する。機能がランダムに表示されたり消えたりする。

解決策は、安定した識別子に基づいてパーセンテージ計算を行うことだ。ユーザーIDまたはセッションIDをハッシュ化し、そのハッシュを使ってユーザーがどのグループに属するかを決定する。ユーザーIDが変わらない限り、ハッシュ結果も変わらず、ユーザーは一貫した扱いを受ける。

これが、パーセンテージベースのロールアウトに乱数生成器を使ってはいけない理由だ。乱数はコードが実行されるたびに変化する。安定した識別子のハッシュを使えば、決定論的な動作が得られる。

段階的ロールアウト vs. カナリアリリース

カナリアリリースについて聞いたことがあるかもしれない。カナリアリリースでは、アプリケーションの新バージョンを一部のサーバーにデプロイする。ロードバランサーのルールに基づいて、トラフィックがそのサーバーにルーティングされる。カナリアサーバーに問題が発生した場合は、トラフィックをそこから遠ざける。

フィーチャーフラグを使った段階的ロールアウトはこれとは異なる。すべてのサーバーが同じコードを実行する。フラグが誰に新機能を表示するかを決定する。サーバールーティングやロードバランサーの設定を管理する必要はない。フラグの値を変更するだけでよい。

次のフローチャートは、2つのアプローチを対比している。

flowchart TD A[開始: ユーザーの5%] --> B[メトリクスを監視] B --> C{エラーや問題は?} C -->|なし| D[10%に増加] D --> E[再度監視] E --> F{安定している?} F -->|はい| G[25%, 50%, 100%へ継続] F -->|いいえ| H[前のレベルにロールバック] C -->|あり| I[0%にロールバック] I --> J[調査して修正] J --> A K[カナリアリリース: 一部サーバーにトラフィックをルーティング] --> L[サーバーメトリクスを監視] L --> M{正常?} M -->|はい| N[カナリアトラフィックを増加] M -->|いいえ| O[トラフィックを別の場所へリダイレクト]

この違いは、多数のサーバーにデプロイするチームやコンテナオーケストレーションを使用するチームにとって重要だ。フィーチャーフラグを使えば、本番環境でアプリケーションの複数バージョンを維持する必要がない。すべてのサーバーが同じバイナリを持つ。フラグだけが唯一の違いとなる。

心理的効果

段階的ロールアウトは技術的なプラクティスだけではない。チームがソフトウェアリリースに対して持つ感覚を変える。悪い機能が影響するのはユーザーの5%だけだと分かっていれば、リリースに対する心理的ハードルが下がる。リリースを高リスクなイベントとして扱うのをやめ、徐々に進める実験として扱うようになる。

最初のグループに偶然入ったユーザーは、騙されたとは感じない。彼らは何か新しいものを試していると理解している。一部のユーザーはアーリーアダプターであることを楽しむことさえある。そして、何か問題が発生した場合も、パニックにならずにフラグをオフにできる。緊急ロールバックも、全員招集のインシデントも不要。設定変更と調査メモだけで済む。

段階的ロールアウトの実践チェックリスト

機能を一部のユーザーに公開する前に、次のチェックリストを確認しよう。

  • ユーザーを一貫して識別できるか? パーセンテージ計算には、ユーザーIDやセッションIDのような安定した識別子を使用する。
  • 監視体制は整っているか? 監視すべきメトリクス(エラー率、応答時間、ユーザー報告の問題)を把握しておく。
  • フラグを即座にオフにできるか? フラグシステムが迅速に応答し、再デプロイを必要としないことを確認する。
  • ロールアウトの段階を定義したか? パーセンテージ(5%、10%、25%、50%、100%)を計画し、各段階にどれだけ留まるかを決めておく。
  • ロールバック計画はあるか? どのメトリクスのしきい値でフラグをオフにするか? 誰がその判断をするか?

まとめ

段階的ロールアウトは、機能リリースを「全か無か」のギャンブルから、制御された実験へと変える。小さなパーセンテージまたはターゲットグループから始め、メトリクスを監視し、確信が持てたら範囲を広げ、問題があれば即座に閉じる。このパターンは、リスクが常にユーザーのごく一部に限定されるため、チームがより頻繁にリリースする自信を与える。