Feature Toggles
Pete HodgsonさんというThoughtWorksの方が書かれたFeature Togglesという記事が面白かったので翻訳してみました。
「本番環境などという場所はない」マイクロソフトがSaaSの失敗と成功から学んだ、アジャイルからDevOpsへの進化(前編)。Regional SCRUM GATHERING Tokyo 2016の記事で取り上げていただいた通り、マイクロソフトの内部の開発では多くのフィーチャートグルが使われています。このことをより深く理解したいと思って個人的に翻訳したものを公開します。私的な自分が理解する用の翻訳でありますので、その辺はご考慮いただければと思います。Pull Requestは歓迎いたします!
概要
フィーチャートグルズ(Feature Toggles)は、とてもパワフルなテクニックだ。チームがコードを変更することなくシステムの振る舞いを変更することができる。それらは様々な使われ方をする。
トグルズを実装したり、管理したりする場合、カテゴリ分けを考えることは重要だ。トグルズは複雑性を孕んでいるため、私たちはスマートなトグルズ実装のプラクティスを使って、トグルズの設定の管理を適切なツールを使うことで、複雑性をコントロールをするようにしたい。
しかし、忘れてはならないのはシステムのトグルズの数を制約する方向性に向かうべきということだ。
”フィーチャートグルズ”はチームが、新しい機能をユーザに素早く安全に提供することをた助けてくれる一連のパターンだ。このフィーチャートグルズのポストの中で、私たちは、フィーチャートグルズが役立っている典型的なシナリオのショートストーリから始めることにする。その後、詳細に掘り下げ、チームがうまくフィーチャートグルズを扱うための特定のパターンとプラクティスについて説明する。
トグル化の物語
こんな場面を想像してみよう。あなたは幾つかあるうちの、一つのチームで、洗練された都市計画のシミュレーションゲームを作っている。あなたのチームはコアシミュレーションエンジンの担当だ。あなたは、Spline Reciculationアルゴリズムの効率を増すためのタスクをサインアップしている。これを実現するためには、数週間かかる実装の大きな変更が必要になってくるだろうことはわかっている。一方他のメンバーは、コードベースの関係ある箇所の作業を継続して実施するだろう。
あなたは、できることなら、この仕事のブランチを作るのを避けたいと思っている。過去に長い期間存在するブランチで苦痛を経験したことがあるからだ。その代わりに、全てのチームがトランクで作業を行って、このアルゴリズム担当の開発者たちは、フィーチャートグルを使って、他のチームに影響を与えたりコードベースを脆弱にすることを防ごうと思っている。
Spline Reticulation: http://sims.wikia.com/wiki/Reticulating_splines SimCityでこの文字がジョークとして表示されるらしいが、意味は特にないらしい。
フィーチャートグルの誕生
アルゴリズムをペアプログラミングしてできた最初の変更がある。
before
function reticulateSplines(){
// current implementation lives here
}
these examples all use JavaScript ES2015
after
function reticulateSplines(){
var useNewAlgorithm == false;
// useNewAlgorithm = true; // UNCOMMENT IF YOU ARE WORKING ON THE NEW SR ALGORITHM
if( useNewAlgorithm ){
return enhancedSplineReticulation();
}else{
return oldFashionedSplineReticulation();
}
}
function oldFashionedSplineReticulation(){
// current implementation lives here
}
function enhancedSplineReticulation(){
// TODO: implement better SR algorithm
}
ペアは現在の実装を、oldFashionedSplineReticulation()関数に移動し、reticulateSplines()をトグルポイントにした。誰かが、新しいアルゴリズムを使いたいならuseNewAlgorithm = true
をアンコメントすると使えるようになる。
トグルをダイナミック(動的)にする
数時間過ぎて、ペアは新しいアルゴリズムを、シミューレーションエンジンのインテグレーションテストを通じて、実行できる準備が整った。彼らはさらに、古いアルゴリズムも同じインテグレーションテストで実行したいと思っている。
これは、オールドファッションな、コメント / アンコメントのメカニズムから次の手に向かうタイミングであることを意味している。
function reticulateSplines(){
if( featureIsEnabled("use-new-SR-algorithm") ){
return enhancedSplineReticulation();
}else{
return oldFashionedSplineReticulation();
}
}
私たちは、新しいfeatureIsEnabled()関数を導入した。コードパスをコントロールするトグルパスは動的に制御を行う。トグルルータを実装する方法はいろいろある。シンプルなインメモリストアから高度に洗練された綺麗なUIをもった分散システムまでだ。今は、とてもシンプルなシステムから始めよう
function createToggleRouter(featureConfig){
return {
setFeature(featureName,isEnabled){
featureConfig[featureName] = isEnabled;
},
featureIsEnabled(featureName){
return featureConfig[featureName];
}
};
}
今、私たちは、ES2015のメソッド短縮を使っている。
私たちは、新しいトグルルータを使っている。これはデフォルトコンフィグレーションを元にしている。たぶんコンフィグファイルから読み込む。しかし、私たちはまた、動的にフィーチャーをon / offすることができる。これは、自動テストで両方のトグルを検証することを可能にする。
describe( 'spline reticulation', function(){
let toggleRouter;
let simulationEngine;
beforeEach(function(){
toggleRouter = createToggleRouter();
simulationEngine = createSimulationEngine({toggleRouter:toggleRouter});
});
it('works correctly with old algorithm', function(){
// Given
toggleRouter.setFeature("use-new-SR-algorithm",false);
// When
const result = simulationEngine.doSomethingWhichInvolvesSplineReticulation();
// Then
verifySplineReticulation(result);
});
it('works correctly with new algorithm', function(){
// Given
toggleRouter.setFeature("use-new-SR-algorithm",true);
// When
const result = simulationEngine.doSomethingWhichInvolvesSplineReticulation();
// Then
verifySplineReticulation(result);
});
});
リリース可能にする
さらに、時間がすぎて、チームは、新しいアルゴリズムが完成したと信じている。これを確認するために、彼らは高レベルの自動テストを変更している。フィーチャーon / off の両方のケースが実行されるように。
チームはさらに、手動の探索的テストが期待通りに働くようにしたいと思っている。Spline Reticulationは、システムの振る舞いの大変重要な部分だ。
十分にテストがされていないくて、一般公開できない機能の手動テストを実行するために、現在プロダクションの一般的なユーザに対してフィーチャーをOffにできる必要がある。
しかし、内部ユーザにはOnにでrきる必要がある。このゴールを達成するためには、幾つかの違ったアプローチがある。
- トグルルータを作る。これは、トグルコンフィグレーションを元に判断される。そして設定を環境ごとに作る。プリプロダクション環境だけに、新しいフィーチャーをonにする
- トグルのコンフェイグレーションを管理者画面のUIなどでランタイムに変更できるようにする。管理者UIでテスト環境のフラグをonにする
- トグルルータに動的な、リクエストごとのトグル判断を教え込ませる。これらの意思決定は、トグルコンテキストを考慮する。例えば、特殊なcookie か、HTTPヘッダを見る。大抵は、トグルコンテキストは、特定のユーザがリクエストしたかを特定するためのプロキシとして使われる。
(私たちは、これらのアプローチを後で詳細に掘り下げる。だから、これらのコンセプトがあなたにとって新しいことでも心配しないでほしい)
図の訳注
- 私たちはトグルポイントをコードに入れて、新しい機能の振る舞いをスイッチする
- 幾つかの機能のための、複数のトグルポイントは、状態を判断するために1つのトグルルータを使う。
- トグルルータは、トグルコンテキストを考慮する(例えばどのユーザがリクエストしたか?)これはルーティングの判断をするのに使われる
- トグルルータはトグルコンフィグレーションによりコントロールされる。とある環境のために。
チームは、リクエストごとのトグルルータの方式を採用を決める。柔軟性があるからだ。チームは、この方式が、新しいアルゴリズムを別のテスト環境を必要とすることなく、テストできることが気に入っている。その代わり、チームは単に本番環境で、アルゴリズムを内部ユーザ向けにだけonにすれば良い。そうすれば期待通りに機能が動いているかわかる。
カナリアリリース
新しいSpline Reticulationアルゴリズムは探索的テストによると、今の所いい感じに見える。しかし、これはゲームのシミュレーションエンジンの中核の部分なので、全てのユーザにこの機能を解放するのははばかられるところがある。チームは、彼らのフィーチャートグルのインフラを使ってカナリアリリースをすることにした。新しいフィーチャーをほんの小さなユーザベースにだけon にする。"カナリア"コホートだ。
コホート:共通した因子をもち、観察対象となる集団
チームは、トグルルータを拡張し、ユーザコホートの考えを教え込ませた。- 複数のグループのユーザ集団。彼らは一貫して機能のon / offの経験を共有する。カナリアユーザのコホートは、ユーザベースの1%のランダムなサンプリングによって作られる。たぶんユーザIDのmoduloを使う。このカナリアコホートは、一貫して機能をonにする。一方99%は古いアルゴリズムを使い続ける。ビジネスのキーメトリクス(ユーザエンゲージメント、収益の合計など)が両方のグループでモニタされる。それにより、新しいアルゴリズムがユーザの振る舞いにネガチィブなインパクトを与えていないことを確信させる。一度チームが、新しい機能が問題ないと確信を持ったら、トグルコンフィグレーションを変更して、全てのユーザに機能を解放する。
A/B テスティング
チームのプロダクトマネージャは、このアプローチを学んで、とても興奮していた。彼女はチームがA/Bテスティングを実施するために、似たようなメカニズムを使うのはどうかと提案した。汚染のレベルを考えるための犯罪率のアルゴリズムを変更すべきかの長いディスカッションが行われていた。※微妙な翻訳それは、ゲームのプレイヤビリティを左右する。
彼らは今ディベートにデータを使う能力を持っていた。彼らはデータの本質を捕まえるチープな実装を展開しようと計画している。これをフィーチャートグルで制御する。
彼らは、その機能を十分に大きなユーザのコホートに公開しようとしている。このアプローチはチームが白熱している製品のディベートをデータによって解決できるだろう。給料の高い人の意見の代わりに。
HiPPOs:highest paid person’s opinion.
この短いシナリオはフィーチャートグルの基本的なコンセプトを描き出すのを意図している。しかし同時にどれだけ多くの異なるアプリケーションがこのコアの可能性を持っているかをハイライトしている。
今はこれらのアプリケーションのサンプルを見て、それを深めてみましょう。
私たちは、異なるカテゴリーのトグルを探索して、その違いを理解するだろう。私たちは、どうやってメンテナンス性のよいトグルのコードを書くか、そして最終的にフィーチャートグルの落とし穴をどうやって避けるかということをシェアする。
トグルズのカテゴリ
今まで、フィーチャートグルによってもたらされる基本的な機構について、見てきた。- 1回のデプロイ可能なユニットにより代替えのコードパスを提供できること。そして、それをランタイムで選択できること。
上記のシナリオはさまざまなコンテキストでさまざまな用途で使われることを示してきた。
このことは、すべてのフィーチャートグルを同じバケツに入れたくなる誘惑にかられる。しかし、これは、とても危険な道だ。違うカテゴリのトグルを同じように使わせるデザインのフォース、そしてそれらを同じように管理することは、苦痛を伴うことを引き起こしかねない。
フィーチャートグルは、2つの主な面にカテゴライズされる。: どれぐらい長くフィーチャートグルが生存するかと、どれぐらい動的にトグル(変更)決定がなされるか? しかし、私は、長く生存することと、動的さの2つの大きな要素は、トグルズをどのように制御するのガイドになる。
トグルのいろいろなカテゴリを考えてみよう。2つのレンズを通して。そしてそれらがどこにフィットするかを見てみよう。
リリーストグルズ
継続的デリバリを実践しているチームのトランクベースの開発を可能にするトグルズがある。それらは、実装中のフィーチャーを共通のインテグレーションブランチでチェックすることを可能にする
(例えば、マスタやトランク)同時にブランチをプロダクションにいつでもデプロイできることを可能にする。リリーストグルズは、不十分と、テストされていないコードパスを本番にリリースすることを許容する。それは、隠されたコードとしてデプロイされる。それはおそらくonにならない。
プロダクトマネジャは、本番中心のバージョン管理に使う。これは、作成中のプロダクトフィーチャーがユーザーにさらされるのを防ぐ。
例えば、eコマースサイトのプロダクトマネジャは、ユーザに新しい出荷日見積もり機能を見せたくないだろう。これは、出荷パートナーのサイトの1つで使えるようにしている機能だ。機能がすべての出荷パートナーにリリースできるまで、待つ方を好むだろう。
プロダクトマネジャは、フィーチャートグルズが、完全に実装されてテストされていても、機能を公開しない他の理由もあるだろう。機能のリリースはマーケティングキャンペーンとコーディネートされるかもしれない。
例えば、リリーストグルズをこのように使うのは、継続的デリバリの原則である"機能リリースをコードのデプロイと分離する"ということのもっとも一般的な実装だ。
リリーストグルズは、遷移的な性質を持っている。それらは、1週間から2週間以上にわたって存在しない。だが、プロダクト中心のトグルズは、より長い期間にわたって存在する必要があるかもしれない。
リリーストグルの、トグル戦略の決定は、とても静的だ。
トグルコンフィグレーションの変更して新しいリリースをトグルで展開することの決定は、大抵完璧に受入れ易いものである。
実験トグルズ
実験トグルズは、マルチバリエートか、A/Bテストに使われる。その他のユーザは、コホートや、トグルルーターのランタイムが一貫して一つのコードパスか、ほかのコードパスかに特定のユーザを分岐させる。これは、どのコホートに彼らが含まれるかによって決まる。
ほかのコホートの振る舞いを集計することによって、例えば違うコホートのコードパスと振る舞いと比べることができる。このテクニックは、データ駆動の最適化(to things)例えばエコシステムのeコマースの購買フローのように。
実験トグルは、同じ設定で十分長く生存し、静的に意味のある結果を生成する。トラフィックのパターンによって、生存時間が時間か、週かの違いがでてくる。より長いものは、使いやすいとはいいがたい。
他の変更をシステムリスクに対して実験の結果としてのシステムリスクを変更する。それらの自然な実験トグルズは、とても動的だ。- 全てのやってくるリクエストは異なるユーザの代わりを代表し、前回とは違ったようにルーティングされる。
Ops トグル
これらのトグルは、システムの運用面のふるまいをコントロールするために使われる。私たちは、パフォーマンスの影響が不明確な新しい機能を展開するときに使う。それにより、システムの運用者は、必要なら本番環境で機能をデグレードさせたり、不使用にしたりできる。
大抵の Ops トグルズは生存期間が短い。- 一旦新しい機能の運用的な面について確信がもてたなら、そのトグルは引退させるべきだ。しかし、システムにとって、ごく少ない、Kill Switchesがあり、システムが高い負荷にさらされているとき、本番環境の運用者が本質的でないシステム機能を華麗にデグレードさせる。
例えば、システムが、高い負荷にさらされているとき、ホームページの推薦パネルを使用不可にしたいかもしれない。これは、比較的作成にコストがかかるものだ。
私はオンラインのリテーラーが、彼らのwebサイトのメインの購買フローをちょうど高い要求のプロダクトローンチの時のためにOpsトグルを保持していることを相談された。
これらの長く生存するOps トグルを手動で管理されるサーキットブレーカーとして見ることができる。
すでに述べたとおり、多くのOpsトグルは短い期間だけ利用されるものだが、運用者にとって重要なコントローラーがいくつかあり、それらは半永久的に残しておく。これは本番環境で極めて迅速に設定変更しなければならないような問題がおきたときに、運用者が迅速に対応できるようにするためのものだ。Opsトグルを切り替えるためだけに新しいリリース行わなければならないようでは、運用者が幸せになることはまずないだろう。
パーミッショントグル
これらのトグルは、特定のユーザのみ機能を変えたり、プロダクトのエクスペリエンスを変えたりするのに使われる。
例えば、私たちはお金を払っているユーザ向けの”プレミアム”機能があるかもしれない。もしくは、内部のユーザだけが使える”α”の機能があるだろう。そしてほかの”β”機能。これは内部のユーザと、ベータユーザに利用可能になる。
私はこのチューニングテクニックが好きだ。内部もしくはβユーザ向けの一連の機能をシャンパンブランチとして、オンにする。
シャンパンブランチは、カナリアリリースと多くの面で似通っている。2つの違いは、カナリアリリースされた機能は、ランダムに選択されたユーザのコホートに公開される。一方、シャンパンブランチでは、機能は特定のユーザの集合に公開される
プレミアムユーザにのみ公開する機能を管理する方法として使うときには、パーミッションニングトグルは、ほかのカテゴリの機能トグルに比べてとても長期間生存するものになるかもしれない。- 複数年のスケールで。パーミッションがユーザ毎なので、パーミッショントグルのトグルの
決定は、いつもリクエスト毎になる。このことは、このトグルをとても動的なものにしている。