バッドシグナル通信 - 歴史的理由

最終更新日: 2009-03-23

WEB+DB PRESS Vol. 50 に向けて書いた記事の元の原稿です。


今月号から「バッドシグナル通信」と題して連載することになった高林と申します。今回の連載ではソフトウェア開発の中でみられる「バッドシグナル」について書いていきたいと思います。

バッドシグナルとは?

ソフトウェア開発を行っていると、「何かいやな予感がするなー」と直感が働いて、それが的中することがままあります。いやな予感には何かしらの原因があり、そこから発せられる危険信号を人は読み取っているのではないかと思います。

筆者の周りではこの危険信号を、バッドであることが予想されるシグナルという意味で、「バッドシグナル」と呼んでいます。筆者はこの言葉を使い始めてからは、いやな予感がするきは「このバッドシグナルは何だ?」と考えるようになり、いやな予感の原因を特定する習慣がつきました。

本連載ではありがちなバッドシグナルを取り上げて、その対処法などを検討していきたいと思います。第一弾のバッドシグナルは「歴史的理由」です。

歴史的理由

ソフトウェアのソースコードや文書を読んでいると For historical reasons (歴史的理由により) という言葉によく出くわします。試しに「Googleソースコード検索」 *1で For historial reasons を検索してみると 95,100件もヒットしました。最初の方の何件かを読んでみると、こんなものがありました。

linux-2.4.34/include/asm-sparc/uaccess.h

"For historical reasons, these macros are grossly misnamed." -Linus

「歴史的理由により、これらのマクロにはおぞましく名前をつけ間違えている。」 - Linus

これは歴史的理由の典型的な例です。パブリックなAPI に変な名前をつけてしまうと、後から変えようと思っても変えられません。すでにそれらのAPI を使っているクライアントコードが無数にあるためです。

もし下手に変えてしまうと、クライアントコードのコンパイルが通らなくなって「勝手に変えるんじゃねー」と怒った開発者が大挙して押し寄せてくる恐れがあります。他人の変更のせいでコンパイルが通らなくなるのは腹立たしいものです。

名前が変わってコンパイルが通らないだけなら対処は比較的簡単ですが、Python などの動的言語では、実行するまでエラーがわからない場合があるので、問題はより深刻です。

こういった API の問題に対しては、新しいクリーンな API を追加して、古い API は deprecated (非推奨) という印をつけて、一定期間後に削除するという方法があります。完全な解決策ではありませんが、いきなり変更するよりはダメージを防げます。

安易な仕様

歴史的理由がはびこるのは API だけではありません。安易に設計した設定ファイルやコマンドラインオプションは歴史的理由が好んで生息する危険ゾーンです。

ありがちなのはこんなケースです。

「よし --input というコマンドラインオプションで入力のファイル名を指定できるようにしよう。」

(数日後)

「複数の入力ファイルを読み込めるともっと便利だよなー。しかし、どうやって複数のファイル名を渡そう。とりあえずカンマで区切って渡すことにするか」

(数か月後)

「うわ、なんかユーザから苦情が来た。カンマを含むファイル名を読み込めないって?そんなファイル名つけるなよ。んー、どうしてもその名前を変えられないの?あー、歴史的理由かー。とりあえず、カンマを \ でエスケープできるようにしとくよ。」

(数か月後)

「うわ、またファイル読めないって怒ってるユーザ来たー。これ、ファイル名に \ を含んでいるじゃん。これは \\ にしないと。というかなんで \ なんか使ってるの?あー、Windows なのか。\\ がキモイといわれても困るなあ。今更、挙動変えられないすよ。」

このケースの場合、「とりあえずカンマ区切り」と「とりあえず \ でエスケープ」という2つの歴史的理由が重なって Windows ユーザがえらい目にあっています。今となっては --input の挙動を変えるわけにもいかず、厄介です。

敗因は --input というオプションで複数のファイルを指定できるようにしたことでしょうか。grep コマンドの構文

grep [options] PATTERN FILE...

と同様に、コマンドライン引数の後ろの部分 (FILE...) を使って任意の数の入力ファイル名を指定できるようにすれば、このような問題は起こらなかったはずです。

手抜き実装

APIや設定ファイルは外から見える仕様ですが、実装の内部にも歴史的理由はよく潜んでいます。手抜きの実装が将来に渡って禍根を残し続ける場合が多々あります。

先ほどのプログラマ氏ならこんなことになりがちです。

「メールのアドレス帳を作るぜー。表示用の名前 Taro Yamada とメールアドレス taro@example.com があれば十分かな。こういうのはクラスにして display_name と address と 2つのフィールドを持たせればいいんだよな 。でもクラス書くの面倒くせー。待てよ、これ、 "taro@example.com Taro Yamada" みたいに、ひとつの文字列に空白で区切っていれとけばいいのでは?どうせアドレスは空白を含まないんだし。急いでるからこれでいいやろ。メモリも節約できてクールだぜ。」

(数か月後)

「なんか苦情きたー。うわ、メールアドレスって"taro yamada"@example.com みたいなやつありなの?これって空白含んでいるじゃん。RFC *2 読むかなー。うわ、やっぱこれありなのかよ。しかし今更どうしろっていうの。データベースにこの形式でもう保存しちゃってるし、今更、変えられないぜ。仕方ないから "taro yamada"@example.com みたいなメールアドレスをちゃんとパーズするコードを書くか。面倒くさー。」

このケースの場合、またもや変な区切り文字のルールの導入という歴史的理由で悲惨な目に遭っています。さすがに2度も痛い目に遭うと「区切り文字」と聞いただけでバッドシグナルを嗅ぎ取ることができるようになります。

地雷ハック

ある特殊な条件で起きるバグを直したい場合など、その場しのぎのハックで対処したくなるときがあります。このようにして入れたハックが地雷となり後々になって災いを及ぼすことがあります。

また例のプログラマ氏に登場してもらいましょう。

「うげ、なんかうちのサイトのレイアウトが IE のときだけ崩れるなー。いったい俺の時間は IE のためにどれだけ浪費しているんだ。さっさと片付ける方法ないかなー。んー、なんか CSS のアンダースコアハックなる技を発見!これを使えば、IEだけに適用できるスタイルを書けるのかー*3。これはバッドだけど使える!」

(数年後)

「うわ、なんか苦情がきたー。IE でレイアウトが崩れるって?おかしいなあ。確か数年前に直したような記憶が。あれ、このアンダースコアハックって IE7 だと無効なの?聞いてないよそんなの。かといってこれ今更削ると IE6 でのレイアウトが崩れるからなあ。これ入れたまま IE7 のレイアウト直すのはどうすればいいいんだろう。おや、 IE はエレメントに hasLayout という隠しプロパティがあるの?*4もしかしてこの情報を使えばなんとかなるっぽい?あ、なんかよくわからんけど、できたよ。やれやれだぜ。俺はもう燃え尽きたよ」

(数年後、後任者登場)

「最初のプロジェクトは IE8 でのテストですか?いいですよ。ちょっと、試してみますね。あ、レイアウトが崩れますね。ちょっとコードを見てみます。うわ、なんなんですかこれ。このアンダースコアは何?この hasLayout という謎のプロパティは?これもハックなんですか?しかもいまどき何で EUC-JP*5 なんか使っているんですか。誰ですかこんなの書いたの。あ、辞めちゃった Tさんですか。しかしこれ、ハックだらけでコードぐちゃぐちゃですよ。これ、どうやって IE8 対応したらいいんですかね。え、私がやるんですか?」

これはまさに泥沼の状況です。前任者はすでにいないのでハックの真相はわかりませんし、後任者にとっては悪夢です。特定のブラウザだけで使えるハックは問題を抱えているときには非常に魅力的な解決策ですが、このように将来に禍根を残す危険性があります。こうしたハックにできるだけ頼らずに問題を解決したいところです。

歴史的理由により空は飛びません
歴史的理由により空は飛びません

まとめ

今回は歴史的理由というバッドシグナルを取り上げました。一度、判断を誤って変なコードをいれてしまうとそれを取り除くのが非常に困難になることが多々あります。このような歴史的理由を作らないよう、常日頃から気をつけたいものです。


*1<http://www.google.co.jp/codesearch>
*2Request For Comments の略。メールアドレスのフォーマットは RFC 5322 で定義されています。 http://tools.ietf.org/html/rfc5322 で読むことができます。
*3_font-family のようにプロパティの前にアンダースコアをつけると IE だけが解釈して他のブラウザは無視するという挙動を利用したハック。IE7 から使えなくなりました。
*4エレメントのレイアウト方法を表す読み込み専用のプロパティ。 <http://msdn.microsoft.com/en-us/library/bb250481.aspx> に詳しい情報があります。IE8 からなくなりました。
*5日本語の文字エンコーディングのひとつ。現在は Unicode の UTF-8 を使うのが主流となっています。