フィーチャーフラグ入門


タイトルどおり、このガイドではフィーチャーフラグについて説明したいと思います。  フィーチャーフラグとは何なのか?  どのように使えばよいのか?  どのように始めればよいのか?  これらのトピックをすべてカバーしたうえで、ほかの話題にもいろいろ触れていきます。

フィーチャーフラグが興味深いのは、簡単そうでいて奥が深いという点です。  「フィーチャーフラグとは何なのか」という質問に対しては、2つ3つのセンテンスで答えることも、本をまるまる一冊書くこともできます。  コンテキストによって、どちらの答えも適切でしょう。  ですから、基礎を全部カバーできるよう、できるだけ簡単なところから始め、だんだんに詳細に入っていくことにしましょう。

フィーチャーフラグとは何か?必要最小限の定義

ソフトウェアでフラグと言えば、「バイナリ値の格納に使用される1またはそれ以上のビット」です。つまり、trueまたはfalseのブール値です。  これはif文でチェックできます。  同じくソフトウェアのコンテキストでは、フィーチャーとは何らかの価値を提供する機能のかたまりです。

つまり、フィーチャーフラグとは、ごく簡単に言えば、ソフトウェアの何らかの機能のかたまりを囲むif文です。

もちろん、ほかにも微妙な意味合いはいろいろとあります。  そうでなければ、私がこれをテーマに長々とガイドを書くようなこともなかったでしょう。  しかし、てっとりばやい定義をお探しであれば、このとおりです。

フィーチャーフラグとは:必要最小限のサンプル

最小限の定義がよくわかるよう、次の疑似コードで簡単なサンプルを見てみましょう。

if(configFile["IsHoliday"] == true) {
writeGreetingMessage("Happy holidays!");
}

ここで行われている3つのことは、かなり基本的ですが、どれも重要です。

  1. 実行中のソフトウェアから外部のファイルにアクセスして設定情報を取得しています。
  2. 設定情報が今日は祭日だと言っていれば、問題の機能を処理します。
  3. 機能は祝日のあいさつをするものです。

これが究極に単純化したフィーチャーフラグです。  今日が何らかの祝日なら、楽しい祝日を、というあいさつのメッセージをユーザーに表示します。  祝日でなければ、処理は行いません。

フィーチャーフラグとは:もう少しだけ本格的な定義

サンプルには、私が最初の究極に簡単な定義では触れなかったものが忍び込んでいることにお気づきになるでしょう。  私はファイルから何かを読み取ると言いました。  理由を説明するために、定義を少し拡張してみましょう。

フィーチャーフラグとは、コードを変更したり再デプロイしたりせずにソフトウェアの機能を変えるための方法です。

どちらの定義も妥当ですが、こちらは状況を少しだけ一般化しています。  根本的には、フィーチャーフラグとは、ひとかたまりのソースコードを囲むif文を置くことです。  しかしその背景はもう少し複雑です。  つまり、ソフトウェアの動作を実行時に変更する柔軟性が欲しいということなのです。

またサンプルに戻って当てはめると、ファイルから読み取るという動作が重要な理由もそれです。  単にローカル変数を定義し、それを読み取る場合、if文と条件付き機能は実現できますが、実行中に変更することはできません。  それができることが重要なのです。

サンプルで何をやっているかを考えてみれば、納得できるでしょう。  何かを実行するソフトウェアの一部分があります。  今日が祝日かどうかをその場で判断し、それに合わせてユーザーにあいさつしたいと思います。  しかし、祝日が来るたびにコードをデプロイし、祝日が終わったらまたデプロイしなおすのは嫌でしょう。  そんなのはばかげています。  そこで、なんとかして再デプロイなしで機能をオン/オフする機能が欲しいのです。

フィーチャーフラグの別名: フリッパー、トグル、コントロール、などなど

フィーチャーフラグを掘り下げようとするところですが、その前に、重要なことをクリアにしておかなければなりません。  おそらく、フィーチャーフラグを表す他の名前を目にしたことがあるでしょう。  私自身、これまで次のような名前を見たことがあります。

  • フィーチャートグル (Feature toggles)
  • フィーチャーフリッパー (Feature flippers)
  • フィーチャーコントロール (Feature controls)
  • ロールアウトフラグ (Rollout flags)

おそらくほかにもあるでしょう。

これらは微妙に違うコンセプトだというような議論を見ることもあるかもしれませんが、このガイドでは、これらすべて交換可能なものとして扱います。  ですから、トグルまたはフリッパーの情報を求めて見に来られた方も、ここで正解です。ただし、この記事ではフィーチャーフラグ(Feature flags)という呼び方を通します。

Facebookと製品の柔軟性を求めたパイオニアたち

最近ではあまり芳しくない理由でニュースになっているFacebookですが、おそらくソフトウェア業界では、デプロイメント技術の最先端を行っていることで最もよく知られているでしょう。  10年以上前から巨大なソーシャルネットワークを構築し、その稼働時間に対する要求やスケールは、従来のサイトメンテナンスのアプローチでは十分に対応できないものでした。  言い換えれば、10年前でさえ、次のようなメッセージを見ることは絶対になかったはずです。

FacebookはすばらしいFacebook V3.0のリリースのため、次の木曜に一晩オフラインになります!

Facebookは、ただ黙って、ファンファーレもなく、きりもなく続くアップデートをロールアウトしてきたのです。  日々、サイトは微妙に変化し、機能が追加され、改善されました。  しかしそれは決してイベントではありませんでした。

これは舞台裏でのエンジニアリングのすばらしい偉業です。  Facebookはデプロイメントの洗練とオペレーション化を進め、この論文で述べられているとおり、新しく入ったエンジニアが勤務の初日か次の日にはコードを運用環境にデプロイしているほどです。  テック業界の他の巨人たちも似たようなデプロイメント能力を開発し、現代のデプロイメントの標準を作り上げました。

ところで、わたしはなぜフィーチャーフラグのガイド記事でこのようなことに言及しているのでしょうか?  それは、フィーチャーフラグがこのような発展の哲学的基礎だったからです。

フィーチャーフラグは単にあいさつメッセージをランダムに切り替えるようなものではありません。  ソフトウェア開発における、より大きな重要性のある動きの一部なのです。  だからこそ定義は簡単でもあれば……非常に、非常に複雑でもありえるのです。

運用にフォーカスしたユースケース

次に、フィーチャーフラグのユースケースを考えてみましょう。  もっとも、正確に言うなら、ここで紹介するのはフィーチャーフラグ管理システムという、より広い概念のユースケースです。フィーチャーフラグ管理システムはアプリケーション全体で使用するすべてのフィーチャーフラグの集合を表します。  フィーチャーフラグ管理についてもう少し説明します。

Facebookなどの企業は、ランダムなごちゃまぜの製品フラグから莫大な価値を実現したわけではありません。  フィーチャーフラグを使用して次のようなユースケースに対処したから価値を実現できたのです。

フィーチャーのロールアウトからデプロイメントを分離する

すぐにはピンとこないかもしれませんが、コードをデプロイする際のリスクと、フィーチャーをデプロイする際のリスクは微妙に違います。  私たちの大半にとっては―特にこの業界が長い開発者にとっては―奇妙な言説に思えるかもしれません。  どうすればこの2つを分けられるのでしょうか?  フィーチャーすなわちコードであり、リスクもすべていっしょではないのでしょうか。

それが違うのです。  コードのデプロイに伴うリスクを、ここでは技術的リスクと呼ぶことにします。  ソフトウェアはクラッシュすることがありますし、バグが発見されることもあります。  フィーチャーのデプロイにはユーザー関連リスクがあります。  ユーザーは新しいフィーチャーが気に入らないかもしれませんし、アカウント管理の問題などがあるかもしれません。

従来のデプロイメントでは、これらすべてのリスクを一度に吸収するしかありませんでした。  しかし、フィーチャーフラグ管理システムを使えば、これらのリスクを分離し、個別に対処できるのです。  新しいコードを運用環境に投入し、経過を見て、技術的な観点からは落ち着いたときにフィーチャーをオンにします。

カナリアランチ

リスクの低減について言えば、フィーチャーフラグは、上で説明したスキームをさらに改善することもできます。  上で説明したのは、コードをデプロイし、その後いっぺんに新しい機能のスイッチを入れるというやり方でした。  これだけでも上出来ですが、カナリアリリースによってさらにリスクを低減できます。

カナリアリリースでは、新しいコードを一部のユーザーから漸次的に公開していきます。  変更を最初に目にするユーザーは、ことわざに言う炭鉱のカナリアです。  もし問題があっても、一部のユーザーしか遭遇していないときに発見できるので、だれもかもがいっせいにサポートを求めて押し寄せてくることはありません。  もちろん、すべてうまくいっていれば、新しい機能をより多くのユーザーに公開してゆき、最後にはすべてのユーザーまで更新されます。

運用環境におけるテスト

従来、有効な金言として常に言われてきたのは、「運用環境でテストをするな」です。  そのためにQAグループ、サンドボックス環境、その他ありとあらゆる内部環境があるのです。  これらはリハーサルのようなもので、運用環境は実際のショーです。

ところがFacebook、Netflixその他の企業は、上で述べたように、この常識をひっくり返したのです。  これらの企業では、どうあがいてもテスト用に運用環境を再現するのは不可能なので、運用環境でQAを施行せざるをえません。  その過程で、運用環境でのQAには多大な利点があることを証明しました。

フィーチャーフラグを使うと、運用環境での動作が不明な機能のデプロイのリスクを削減できます。  もちろん、常にあらゆるものをできるだけ早くテストするのがよいでしょう。  それでも、他の選択肢があるのはよいことです。

キルスイッチで対象をオフにする

フィーチャーフラグは、フィーチャーを公開するユーザーの数を増やすだけでなく、反対の方向にも利用できます。  概念的なキルスイッチを使って、ただちにユーザーをゼロにすることも含め、フィーチャーを公開するユーザー数を減らすことができます。

これはもちろん、不正な動作をするフィーチャーをロールアウトしてしまった場合に便利です。  フィーチャーをオフにし、ユーザーには元通りの機能を使ってもらい、改めて挽回すればよいのです。  さらに、フィーチャーを徐々に引退させ、廃止するのにも役立ちます。

実験の実施

ここで紹介する運用にフォーカスしたユースケースの最後は、運用実験の実施です。  わかりやすい例の1つがA/Bテストです。

A/Bテストでは、2つのバージョンを運用に出し、どちらがよいかを確認します。  たとえば、Eコマースサイトを運営していて、「購入」ボタンが緑の場合と赤の場合とで、どちらのほうが好まれるかを調べたいとします。  両方のボタンをデプロイし、フィーチャーフラグを使ってユーザーを半分ずつに分け、どちらのボタンが良い結果を出すかを見ます。

このように、ありとあらゆる理由から、ありとあらゆる実験を構想し、実施できます。事実上、フィーチャーフラグの使い方は無限であり、試験を行って得たデータをどのようにアプリケーションの改善に活かすかにも制限はありません。

インフラおよびプロセス関連のユースケース

当然ながら、フィーチャーフラグ管理システムはソフトウェア製品と密接なかかわりがあります。  いっぽうで、インフラや内部プロセス寄りの利用方法もあります。  いくつか例を見てみましょう。

移行

第一に、移行です。  Webサービスの新しいバージョンに切り替えようとしてはいませんか?  あるいは、長らく使っていたデータベースを移行している最中であるとか?

従来、このような場合に悲惨なフォークリフトアップグレードが行われがちです。  大量のコードを新しい外部サービスを使うように書き換え、一括で移行を実施しますが、ロールバックはできたとしても大変で、最悪の場合は不可能ですらあるため、失敗が許されません。

フィーチャーフラグを使えば、こんな神経をすり減らすようなアプローチを避けられます。  ただ新しいサービスやデータベースの呼び出しを既存のアプリケーションに組み込み、大々的な告知もなくデプロイします。  そしてリスクの低い時間に新しい接続を個別にテストし、動作するかどうかを確認します。

完全に移行する準備が整ったときには、コードはすでに長期間にわたって運用環境に存在し、テスト済みの状態になっているでしょう。  スイッチを入れるのはたいしたことではありません。

開発者のコラボレーションフィーチャーブランチかフィーチャーフラグか?

最後に、フィーチャーブランチかフィーチャーフラグかというソフトウェア開発プロセスの問題があります。  この問題について、こちらでウェビナーを視聴し、詳細を読むことができます。  簡単に言えば、これらはソフトウェア開発チームがコラボレーションに取り組むにあたって選択できる2つのやり方に相当します。

フィーチャーブランチを採用した場合、チームはそれぞれコードのコピーで作業し、比較的長い周期ごとにすべての変更をまとめてマージすることで、後になるまでうまく複雑さを回避できます。  フィーチャーフラグを採用した場合、他のメンバーが作業しているフィーチャーを簡単にオフにできるので、すべての開発者がそれぞれの変更をより継続的にマスターブランチに統合できます。

フィーチャーブランチには欠点やリスクもあります。そのため、多くのチームはフィーチャーフラグのほうが好ましい選択肢だとみなしています。

より現実的なサンプル

フィーチャーフラグのユースケースを理解したところで、サンプルを拡張して、もう少し現実を反映したものにしてみましょう。  Eコマースアプリケーションを想像してください。  ユーザーへのあいさつを表示するのは一か所だけではないでしょうし、一回きりのファイルの内容であいさつを表示するかどうかを決定することもないでしょう。

そうではなく、おそらくページのトップに次のような構文があり

if(feature.isActive("holiday-greeting")) {
print("Happy holidays," + user.name + "!");
}

また、ページの最後には次のような構文を置くのではないでしょうか。

if(feature.isActive("holiday-greeting")) {
printLink("Click to see more holiday deals", "~/holidayDeals");
}

つまり、祝日だと判断したら、祝日モードとして異なる動作をする個所が複数あるのではないでしょうか。  ひょっとすると、そういった個所は何十にもなるかもしれません。  それぞれの場所のために別々のフィーチャーフラグを定義したくはないでしょうし、あちこちに同じ実装を繰り返すのも嫌かもしれません。

さらに、フィーチャーフラグをオンにする決定要因という問題もあります。  誰かが管理する手動の設定でholiday-greeting フィーチャーをアクティブ化したいでしょうか?  それとも、特定の日の特定の時間になったら、自動的にアクティブ化したいでしょうか?  あるいは、両方の組み合わせでしょうか?

現実の世界では、「どのように」フィーチャーフラグを管理するかを決める際には、計画と設計が必要です。  それはささいな決定ではなく、アプリケーションがより複雑になるにつれて、大きくなる問題でもあります。

フィーチャーフラグの構造

何が問題になっているかを理解するために、フィーチャーフラグ管理スキームの構造について、もう少し詳しく見てみましょう。  冒頭で述べたとおり、フィーチャーフラグは、ごく簡単に定義することもできますが、非常に複雑になる場合もあります。  より複雑なレベルで起こることを理解するために、以下の用語が役に立ちます。

  • トグルポイント—サンプルの例では、feature.isActive(“holiday-greeting”) をチェックする各個所が、1つのトグルポイントを表します。  フィーチャーがほんの数行のコードで足りることはめったにないため、1つのフィーチャーをオンまたはオフにするのに非常に多数のトグルポイントが必要になる場合もあります。
  • トグルルーター— feature.isActive(string)メソッドはトグルルーターです。  トグルルーターはトグルポイントをフィーチャーフラグの状態にマッピングします。  こうして多くのトグルポイントにわたってフィーチャーの状態を表す整合性のある単一のポイントを維持します。
  • トグルコンテキスト—トグルコンテキストはコンテキストルーターがフィーチャーの状態を計算するときに考慮するコンテキスト情報を表します。  たとえば、先に“holiday-greeting” フィーチャーは日付に依存する可能性があると述べました。  現在日付はコンテキストの一例です。  他の例としては、ログインユーザー、ユーザーの地理的情報、参照元URLなどが挙げられます。
  • トグルコンフィギュレーション—環境コンテキストに加えて、単純な設定に基づいてフィーチャーのトグルルーターの結果を制御することもできます。  サンプルでは、環境コンテキストに基づいて祝日のあいさつをオンにするかもしれませんが、それを手動でオフにすることもできます。

フィーチャーフラグ入門:実装

ここまできて、アプリケーションのささいな1つの機能をオン・オフするだけにしては、過剰なエンジニアリングなのではないかとお考えかもしれません。  結局、これ以上ないくらい簡単な手引きを探してこの記事にたどりつき、何かおまけの情報がないかと思い、また記事を面白いと思ったから読み進めてくださったのでしょうし。

ほんとうに、これらすべてを理解する必要があるでしょうか?

答えは、「最初はありません」です。  しかし、熟知するようになるまでには、理解する必要があるでしょう。

アプリケーションログについて考えてみてください。  まったくのプログラミング初心者だったり、ちょっとした実装を簡単に作成するくらいだったら、本格的なログフレームワークをインストールしたり設定したりするより、単に言語のファイルAPIを使用してランダムなテキストをファイルに出力するほうが簡単かもしれません。

しかし、それでどのくらいのあいだしのげるでしょうか?  ログレベルについて考えざるをえなくなるときまで我慢するつもりでしょうか?  あるいは、さまざまなスタイルのアペンダー、  あるいはマルチスレッドについて考える必要が出てくるまで?  遅かれ早かれ、自力でやっていくのが困難になり、引き返して確立されたソリューションを使うほうが楽だという時が来ます。

フィーチャーフラグ管理の場合も同じです。  フィーチャーフラグに触れるのが初めてで、少し試してみているところなら、手で一から実装することをお勧めします。  動作の仕組みについて理解が深まり、後でよりよい決定を下すのに役立つでしょう。  しかし、ある程度進んでからここに引き返し、これらの定義を調べているところで、大規模な独自の実装を続けていくかどうか迷っているなら、そうすべきではありません。

成熟した、サードパーティ製のフィーチャーフラグ管理システムが存在するので、それを使用するべきです。

フィーチャーフラグと技術的負債

よくあるフィーチャーフラグに対する非難は、技術的負債を作るというものです。  フィーチャーフラグを手で実装すると、膨大な、ごちゃごちゃに絡み合った条件ロジックにつながる場合があるので、非難したくなるのにも一理あります。  まったくひどいことにもなりかねないのです。

これも、私がサードパーティ製管理システムを選ぶよう唱えている理由の1つです。  これらのシステムを使えば、技術的負債から逃れられるいっぽう、独自に構築されたソリューションは技術的負債の原因になる可能性があります。  ただし、システムを利用する場合にも注意が必要です。

一般的に、コードは無秩序に向かいがちです―  つまり、積極的に整理していなければ、劣化しがちです。  フィーチャーフラグ管理の実装においても何ら変わりはありません。  できるだけトグルポイントを近くにまとめ、フィーチャーがアプリケーション全体に広がることがないようにします。  SOLID 原則に従うとともに、コード(およびフィーチャーフラグのロジック)ではDRY原則に従うとよいでしょう。  そして不要になったトグルポイントおよびルーターを厳しく選別し、フィーチャーフラグを廃止する計画をたててください。

リソースリンク(各言語)

この記事は、フィーチャーフラグとは何か、目的、使い方など、基礎から応用まで豊富なガイドとなるはずです。  最後に、記事全体の中で紹介したもののほかに、詳しいリソースへのリンクを提示しておきます。  以下は、フィーチャーフラグの入門として役立つ、詳細な技術スタックごとのガイドです。

Rollout.ioについて

(この記事は、CloudBees社 「An Introduction to Feature Flagsの翻訳です)