最終更新日: 2009-11-03
WEB+DB PRESS Vol. 52 に向けて書いた記事の元の原稿です。
ソフトウェア開発における危険信号「バッドシグナル」についての本連載、3回目の今回はソフトウェア開発の現場で発生しがちな「チキンレース」的な状況について考察したいと思います。
チキンレースとは、度胸試しのゲーム一般を指すのに使われる言葉です。ネットで調べると、ジェームズ・ディーン主演の映画『理由なき反抗』に登場するシーンが有名とのことで、気になったので DVD を買って観てみました。
2人の若者が度胸を競うため、崖に向かって車を走らせるのが問題のシーンです。先に車から飛び降りた方がチキン (臆病者) です。どうせ主人公のジムが勝つのだろうと思っていたところ、思わぬ展開が待っていました。この結末については後で触れます。
ソフトウェア開発は度胸試しのゲームとは一見、無関係にみえますが、チキンレース的な状況はいたるところで待ち構えています。たとえばこんな状況はどうでしょうか。
(Aさん)「文字列内の半角数字を全角数字にする関数が必要なんすか?簡単に実装できますよ」「電光石火でチェックイン!ユニットテスト書いてないけどまあ単純だからいっか」 (この時点でこの関数は 20行)
(Bさん)「アルファベットとASCIIの記号も対応しようよ。あー、これ、記号は文字コードの単純な演算だけじゃダメっぽいなあ。まあ全部、テーブルで変換すればいいよね。テストは、まあ、あいつの書いたコードにないからいっか」(この時点で 100行)
(Cさん)「半角カナ文字の変換もあると便利じゃない?しかもガはガにしないとね。まあ適当に if 文連発でやっときゃいっか。テスト書こうと思ったけど、元のコードにないからやーめた」(この時点で 200行)
(新人プログラマ氏) 「あれ、この関数、ア゙みたいな入力があるとクラッシュするなあ。ン゚とかもそうか。何でだろう。直してみるかなー。うわ、なんだこの関数、200行もあるぞ。しかもぜんぜんテストがねー!」
バグを見つけてしまった以上、直したいのはやまやまですが、200行に膨れ上がった関数を理解して修正を加えるのは苦痛です。しかも、テストがないので下手にいじると余計に壊してしまう可能性があります。
「リファクタリング」などの書籍に感化された新人プログラマ氏としては、この関数を修正する前にまずユニットテストを書くことが先決だと考えます。しかし、それと同時に「なんでオレがあいつらの尻拭いをしないといけないんだ?」という気持ちもふつふつとわいてきます。
この状況はチキンレースと似ています。先人たちはテストを書くことを多少は考慮はしつつも、先延ばしにしていました。つまり、最初にテストを書く人がチキンというわけです。いやな役を誰かが引き受けないといけないという点で「ババ抜き」とも似ています。
さて、この場合の取るべき行動はどのようなものでしょうか。
1. は手間はかかるものの、この関数が今後も使われ続けるなら、長期的にはメリットの大きそうな戦略です。しかし、他人の尻拭いをするようで、あまり気乗りがしません。
2. は手間は少ないものの、前述のとおり、テストがないので下手にいじると余計に壊してしまう可能性があります。まじめな人なら、テストを書かないことに後ろめたさを感じるかもしれません。
3. は手間はゼロですが、このバグが将来的な製品の致命的な欠陥につながる恐れがあります。良心の呵責に苛まれそうです。
4. は元の作者に責任をとってもらう方法です。これはひとまず試してみる価値のある戦略です。しかし、場合によっては元の作者が別のプロジェクトに移っているなどの理由により、直してくれない可能性があります。これは歴史のあるコードではよくあります。
4. を試してみて駄目だった場合は、テストを書く手間に見合う見返りがありそうか、直さずに放置した場合の問題はどのくらい大きいか、といった事柄を勘案してどうするべきか決める必要があります。網羅的なテストは書かずに、修正点と影響がありそうな周辺だけをカバーする最小限のテストを書くというのはひとつの手です。
この状況について知人に話したところ、「流し台にたまたま皿をもって行ったら、洗い物が大量にたまっているのを見つけてしまった。このとき、たまっているものを全部洗うか、自分が持っていった分だけを洗うか、そういう話?」と指摘されました。確かにこれはいい譬えです。
このような「たまたま自分が気づいてしまったが、自分ではできればやりたくない」という状況は恒常的に発生します。気乗りのしないときは、誰か他の人に押し付けたくなるものです。こんな状況はどうでしょうか。
「なんかこのファイルいじらないといけないっぽいんだけど。うわ、これ、20,000行以上あるじゃん。でかすぎ。なんでもかんでもつめこむなよなー。ちょっといじるだけでもコンパイルで待たされまくり」「あーこれ、いろんな人が少しコードを足してきたから歴史的にこうなったのか。誰かこうなる前に分割してればよかったのに。。」
このような、秘伝のタレのように継ぎ足されて肥大化したコードは、いつか誰かの手によってリファクタリングされる運命にあります。しかし、目下、ほかの事で忙しいあなたなら、自分の番でその役を引き受けることは避けたいでしょう。
「というわけで、ここちょっと修正したんだけど、見てもらえる?」「え、このファイル長すぎるって?だってこれもとから長いよ。俺のせいじゃないよ」「でもついでだからリファクタリングしろって?」「そりゃ確かにリファクタリングするべきだと思うよ。でもさ、リファクタリングは別々にやった方がよくない?下手に一緒にやると後で見たときに何の変更だったかよくわからなくなっちゃうし」「うん、じゃあまずはこの変更をチェックインしよう。ありがとね」(といって、リファクタリングは結局やらない)
リファクタリングは別々にやった方がいい、と言っておきながらやらないのは、ずるいような気がしますが、やるとは明言していないので、嘘はついていません。ときにはこのような方法でチキン役を回避するのも有効な手段です。
チキンレース的な状況では往々にして、正直者が損をする危険性をはらんでいます。複数のチームで開発するプロジェクトでは、次のような囚人のジレンマ*1的なケースが起こりえます。
「ふー、マイルストーンが近づいてるのにいまいち進まんなあ。想定外のトラブル多すぎ。ってそろそろ進捗会議の時間か」「まあ他のチームも遅れてるっぽい様子だし、俺たちが遅れてることはとりあえず黙っておくか」
(マイルストーンがさらに近づく)
「深刻にやばー。マイルストーン間近なのにぜんぜん安定しねー。何かこれほっとくと落ちるなあ。って午後は進捗会議か。これはさすがに隠してて後でばれたらやばいよなあ。正直に言っとくか」
(進捗会議にて)
「えーと、正直にいうと実はまだぜんぜん安定してません」「わ、そういうことはもっと早く言えって?いえ、すぐ直ると思っていたんですが。。」「プロジェクトが遅れたのはお前のチームのせいだって?いや、それはどうでしょう。他のチームだって遅れてるようですよ」「ひえっ、そんなの言い訳にならないと。はい、猛省します。。」
(会議の後で)
「うわ、あっちのチーム、実はまだ安定どころか起動すらしてなかったの?ひでー、なんであいつらはお咎めなしでこっちだけ怒られないといけないのよ」「はあ、最初に白状したのが負け、と。世の中そういうもんですか」
上に挙げたのは極端な例ですが、なかなか先に言い出しづらいという場面は周囲の状況が不透明なときに発生しやすいと思います。最初からオープンに情報交換をしていれば避けられる問題かもしれません。
話は変わって、「理由なき反抗」のチキンレースに戻りたいと思います (映画の展開が気になる方はこの節を飛ばしてください)。
主人公のジムと悪役のバズが乗るそれぞれの車は崖をめがけて疾走します。そして、崖がギリギリまで迫った瞬間に、バズがたまらず飛び降ります。すかさずジムも飛び降り、ジムが僅差で勝利者となります。
ここまでは予想通りですが、バズには臆病者となる以上の悲劇が待ち構えていました。バズは先に飛び降りたものの、革ジャンがドアに引っかかって脱出することができず、崖に転落してしまいます。つまり、不名誉な上に命まで失ってしまったのです。
バズの悲劇からは何か学べる教訓があるような気がします。ソフトウェア開発者が避けたい悲劇とは、こんなケースでしょうか。
今回はチキンレースというバッドシグナルを取り上げました。チキンレース的な状況に陥らないのが一番幸せですが、陥ったときにはバズのようにならないよう気をつけたいものです。
*1Wikipedia に詳しい解説があります。
http://ja.wikipedia.org/wiki/囚人のジレンマ