Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Comparators―比べてみればわかること

第3回ブランチvs.フラグ

とっておきの変更

ソフトウェアをいつでもリリースできるようにしろと求める継続的デリバリの広まりにより、毎日のようにソフトウェアがリリースされるようになりました。早いうちからコードを野にさらせば、隠れた問題を前もって見つけることができるからです。

短いリリース間隔に身を置くと気づくことがあります。⁠リリースできること」「リリースしたいこと」は、必ずしも一致しないのです。たとえば大規模なビジュアルデザインの変更やとっておきの新機能を想像してみましょう。こうした粒度の大きい変更は、たとえ動作する、つまりリリース可能な状態でも、そのまま衆目にさらしたいとは限りません。期待を裏切らない形でお披露目したい、とっておきの変更があります。息を飲む新しい体験がもたらすユーザの驚きや喜びも、ソフトウェアにとっては大切な財産だからです。

とっておきの変更を仕上げるには時間がかかります。一方で、その仕上げが終わるまでソフトウェア全体のリリースを先送りするわけにはいきません。すでにリリースされた部分を少しずつ直していく日々の変更は、できるだけ早くユーザに届けたいからです。⁠とっておきのバグ修正」なんてありません。

日々の変更をこまめにリリースしつつ、舞台裏でとっておきの変更を仕立て上げたい図1⁠。継続的デリバリを行う開発チームにはそんな要望があります。ブランチとフラグは、この欲張りをかなえる代表的なテクニックです。

図1 日々の変更ととっておきの変更
図1 日々の変更ととっておきの変更

ブランチとフラグ

とっておきの変更を開発する古典的な方法がブランチです。バージョン管理システムの上に新機能開発用のブランチを作り、変更はブランチに加えます。そしてブランチが仕上がると、それをトランクにマージするのです。フィーチャーブランチとも呼ばれるパターンです。

ブランチを作らず、トランクだけでとっておきの変更を開発する流儀もあります。それがフラグです。コマンドラインフラグなど、外部から設定可能なグローバル変数をフラグと呼びます。あるフラグの値が有効なときだけ動作するよう新機能を実装すれば、未完成なとっておきの機能をフラグで無効化したままリリースできます。フラグの裏にコードを隠すのです。フィーチャートグルと呼ぶこともあります。

ブランチの利点とフラグの欠点

ブランチの利点は、その隔離度の高さです。ブランチで開発をしている限り、トランクにある既存の機能に影響を与えてしまう心配はありません。トランクだとそうはいきません。うっかりフラグを有効にしたままコードをリリースするだけで、せっかくのとっておきが台なしです。うっかりせずとも、コードがリバースエンジニアリングされてしまうことだってあります。

もう一つ、ブランチには潔さ(いさぎよさ)という利点があります。ブランチを使うと、新しい機能で置き換えられる古い機能のコードを消すことができます。おかげでコードをシンプルに保てます。フラグを使った開発では、古い機能を残しつつ新しい機能を追加します。そのためコードは複雑になりがちです。消され損ねた古いコードが少しずつ積み重なり、ソフトウェアの首を締めます。チームによってはFixitsなどと呼ばれる大掃除で不要コードのクリーンアップに取り組むこともあります。

ブランチの欠点とフラグの利点

ブランチの欠点は、マージ作業の難しさです。まず日ごろから、トランクの変更をブランチに取り込む必要があります。そうしてトランクからの乖離(かいり)を減らすのです。

マージには衝突がつきものですが、衝突の解決は必ずしも簡単ではありません。2つ以上のブランチがあると、事態はさらにややこしくなります。2つの新機能ブランチAとブランチBを持つソースツリーを考えましょう。AもBもトランクの変更は取り込みますが、互いの変更は取り込みません。AとBは大きく離れていきます。

あるときブランチAがトランクにマージされたとしましょう。ブランチBの開発者には地獄が待っています。巨大な変更が、突然トランクにやってくるからです。乖離を避けようと日ごろこまめにトランクをとりこんできた、そんな苦労は台なし。ここでもし3つ目のブランチCがマージされたら……、ぞっとしますよね。フィーチャーブランチは並列性が低いのです。

フラグにこうした問題はありません。フラグが増えるほどコードは複雑になりますが、その複雑さはコードの中に溶け込んでいるため、マージのように複雑さが一度に打ち寄せる危険が少ないのです。

実験志向とフラグ

ブランチもフラグもそれぞれファンがいるものの、継続的デリバリの世界に限ればフラグが人気を高めつつあるようです。特にリーンスタートアップ[1]に類する実験志向のソフトウェア開発で、フラグは避けて通れません。

実験志向の開発では、大半の開発中コードをフラグで隠します。開発中の機能を一部ユーザだけに公開して反応を見る「実験」のためです。実験するコードはとっておきの変更に限りません。フラグを使えばA/Bテストも簡単です。開発者はさまざまなフラグの組み合わせで評価を集め、機能の取捨選択や改善を行います。従来のベータ版よりもっと早い段階から、頻繁に、小さな単位で、さまざまな相手に、機能をリリースして評価を集めます。フラグはこうした実験の舞台を支えています。

Webベースのソフトウェア開発に使われるフラグの実装にはまだ決定版がなく、ソフトウェアやサービスごとに開発されているのが現状のようです。以降ではいくつかの実装を眺めながら、それぞれの個性を紹介します。

Flickr Feature Flippers

Flickrの開発チームはアンチブランチ主義で知られています。書籍『スケーラブルWebサイト』注2ではその一端を見ることができます。そんなFlickrはブランチの代わりに、Feature Flippersと銘打った内製のフラグ実装を使っています。Flickrのコードベースに埋め込まれ、フラグの操作画面までを備えるスクリーンショットからは、Feature Flippersが開発プロセスの一部である様子が窺(うかが)えます図2⁠。

Feature Flippersのアイデアは多くのWeb開発者を刺激したようです。Webを検索するとさまざまなフレームワーク用の実装を見つけることができました。

図2 Feature Flippersの管理画面
図2 Feature Flippersの管理画面
※出典:http://www.flickr.com/photos/rossharmes/4153769740/

Facebook Gatekeeper

FacebookもFeature Flippersに類するしくみを持つことが知られています。同社のリリースエンジニアリングに関する講演では、Gatekeeperと呼ばれるフラグのフレームワークを紹介していますリスト1⁠。講演によると、Gatekeeperはユーザのプロフィール情報に応じてフラグの値を設定できると言います。Facebookの広告の設定と似ているかもしれません。講演の中では、ハイテクニュースブログTechCrunchの社員だけにフェイク機能をリリースして間違った記事を書かせた逸話が披露されています。

リスト1 Gatekeeperの疑似コード
if (gatekeeper_allowed('my_project_name', $viewing_user_or_application)) {
  run_this_tested_code();
} else {
  run_this_old_code();
}

Cookpad Chanko

Cookpadは、Ruby on Rails向けの拡張機能としてフラグを実装しています。Chankoと呼ばれるそのフレームワークはオープンソースで公開されています。Chankoでは、フラグに隠された各機能をunitと呼ばれる独立したモジュールとして扱います。各unitにはそれぞれ別のディレクトリが与えられます。

Chankoのデザインは、実験支援としてのフラグを強調しています。unitはクリーンに分離されるため、失敗した実験を削除するのが簡単です。またunitでエラーが起こった際に規定の動作へフォールバックできるなど、手荒な実験を許す堅牢さも備えています。フラグのアイデアを推し進めた先進的な実装です。

Google gflags

これまでに紹介したフラグは、Webのフレームワークと一体になった実装でした。次に紹介するgflagsは、コマンドラインから渡されたフラグ引数をパースするC++のライブラリです。Rubyのoptparseライブラリなどを想像すればよいでしょう。

gflagsの特徴は、フラグをコード内で分散管理できることです。optparseを始めとする従来のフラグパーサは、フラグの定義を1ヵ所にまとめて定義する必要がありました。gflagsを使うと、宣言を書くだけでプログラム内のどのファイルからも簡単にフラグを追加できます。宣言されたフラグは自動的にパースの対象になりますリスト2⁠。

各モジュールの開発者が簡単に設定項目を追加できるしくみは、巨大なソフトウェアを開発する際に重宝するのでしょう。

リスト2 gflagsを使ったフラグの宣言
DEFINE_bool(big_menu, true, "Include 'advanced' options");
DEFINE_string(languages, "english,french,german",
                         "comma-separated list of languages");

※出典:http://google-gflags.googlecode.com/svn/trunk/doc/gflags.html

Branch By Abstraction

乱雑に散らばったフラグはコードの見通しを下げがちです。フラグを使いつつ、ブランチくらいきっぱりとコードを切り離せないか。リファクタリング技法のBranch By Abstraction(BBA)は解決策の一つです。BBAではフラグに隠したい新旧のバージョンをインタフェースに隠し、実装をサブクラスに切り出します図3⁠。

図3 Branch By Abstraction
図3 Branch By Abstraction

BBAもフラグを使います。ただし使い方には強い規律を求めています。コード内にランダムな条件分岐を埋め込むのではなく、リファクタリングで抜き出したクラスのうちどちらを使うか選ぶところだけでフラグを見るのです。

フラグを使うプログラマはBBAに従うべきなのでしょうか。BBAの出典では、ORMObjectrelational mappingフレームワークの置き換えにBBAを使っています。このように大規模な修正ではBBAが助けになります。

一方、もっと小さく実験的な変更はどうでしょう。たとえば画面のレイアウトを調整して反応を見たくなったとき、BBAは有用でしょうか。テンプレートにフラグの条件分岐を書き足すほうが早そうです。

実験志向とBBA

ORMの置き換えと画面レイアウト調整の違いはなんでしょう。

一つは規模です。大規模な変更には秩序が必要です。良識あるプログラマなら、名前は知らなくてもBBAと似たデザインを選ぶでしょう。

もう一つは投機性です。実験主義者の変更はそれぞれが実験です。そして実験には失敗がつきもの。日々の失敗を小さくとどめるために、開発者は変更を小さくまとめようとします。そうした変更にBBAは大げさ過ぎます。

たとえば実験が終わったあと、開発者はフラグを取り除きます。しかしBBAはフラグ以外に間接化のリファクタリングを持ち込んでいます。フラグ単体と違い、間接化を取り消すのはそう簡単でもありません。結果として不要な間接化がコードの中に残り、見通しを損ねます。そのため規模が小さい実験志向のフラグには、BBAより素朴な条件分岐がうまく働きます。素朴な分岐は不格好ながら取り除くのが簡単なのです。

東京駅vs.新宿駅

継続的デリバリにおけるコード変更が都心の工事だとしたら、BBAはビルを覆う足場とシート。条件分岐は足元注意の標識です。一方は長期戦の下準備、他方はその場限りの仮止めです。

実験志向が支配するソフトウェアは新宿駅に似ています。いつもどこかは工事中で、駅を通り抜けるといつも標識に出くわします。ごちゃごちゃしていて完成が見えません。けれどその混沌はやがて日常に溶け込んでいきます。

BBAを好む手堅いソフトウェアは東京駅に似ています。建物が立派で、たまに始まる大工事では完成予想図をプリントしたシートが駅舎を包みます。人々は完成の予感に胸を踊らせながら、薄暗い駅舎を足早に通りすぎます。

どちらが望ましいかは舞台しだいです。銀行や新聞社、権威ある企業が立ち並ぶ丸の内には秩序が求められます。新興企業から歓楽街まで、雑居ビルひしめく新宿には混沌と変化が似合います。はっきりとした正しさを目指す大きな変更にはBBAが相応しいでしょう。出たとこ勝負で手直しを続ける実験志向には素朴なフラグがお似合いです。街に似合う駅を。目的に合う変更戦略を。私たちのソフトウェアはどんな街に建つのでしょうか。

おすすめ記事