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