最終更新日: 2010-01-10
WEB+DB PRESS Vol. 55 に向けて書いた記事の元の原稿です。
ソフトウェア開発における危険信号「バッドシグナル」についての本連載、最終回の今回はコーディングをバッドなものにする要因について検討してみたいと思います。
三度の飯よりコーディングが好き!という人でも、気乗りのしないコーディングというものもあると思います。コードを書くという作業自体はそれほど変わらないはずなのに、何が原因で退屈だったり苦痛だったりするバッドな作業になってしまうのでしょうか。
何をバッドと感じるかは個人差があると思いますが、ここでは私がバッドと感じる要因を見ていきたいと思います。プロジェクトがそもそも好きじゃない、メンテナと仲が悪いといった人間的な要因は今回は除外しました。
待ち時間の長いコーディングはいやなものです。たとえばビルドに何十分もかかるようなプログラムです。初回のビルドに時間がかかるのは許せますが、1ファイルいじっただけで長々と待たされるようなビルドはいただけません。
「さてちょっといじったからビルドするかな。makeっと」「なかなかコンパイルはじまらないなー。これなぜかのろいんだよな。メールでもチェックするか」「お、新年会やるのかー。って店はどこだろ。うわ、なんかいけてない店だなあ。こんな店選ぶなよ。って幹事Tさんか。なんとか他の店に変えてもらう方法ないかなあ。失礼にならないようにメールで聞いてみるかなあ」「ってこういうメール書くの意外とつかれるんだよなあ。送信っと。」「で、何やってたんだっけ。うわ、コンパイルエラーで止まっちゃってるじゃん。。」
同様に、実行に時間がかかるプログラムもいやなものです。実行して結果が出るまで数時間もかかるようなプログラム(本番のでかいデータではなく、小さなデータでテストできるとグッド)や、リモートのサーバで実行するための準備作業に時間がかかるようなプログラム(ローカルでテストできるとグッド)です。
一度途切れた集中力を取り戻すには20-30分くらい余裕でかかります。これは、コンテクストスイッチのコストなどと呼ばれています。ビルドが速くて、手元でサクサクとテストできるプログラムが理想的です。
ライブラリのAPIを調べたり、サンプルコードを探したりといった調べものはコーディングに不可欠です。が、こればかりに時間を食っているとだんだん飽きてきます。とりわけ、1回限りしか使わないような技術だと身が入りません。
「うわ、このプログラム、なんか XSLT *1 を駆使してがんばってるなあ。テンプレートファイルみたいのたくさんあるけど、さっぱり読めん。。とりあえず検索してみるかな。お、英語の Wikipedia に XSLT のサンプル発見。ってこれだけじゃ単純すぎて役に立たんなあ」
「しょうがないから仕様書でも見てみるか」「でか!これ印刷すると200ページくらいあるじゃん。どうせ2度と使わんし、こんなの真面目に読んでられんなあ。必要そうなところだけ目を通しとくかな」「ちょっとその前に、メールでも読むか。あ、新年会の店、変わったっぽい。よかったよかった。なんか返事書いとくかな」「よし今度こそ XSLT やるぞー。ってこの処理系を手元で動かすにはどうすればいいんだっけ。うわ、なんだこの複雑な設定ファイルは。これの書き方も調べないといかんのか。。」「とりあえずコーヒーでもゲットしてくるかな」
この場合、気乗りしない調べもののせいで、集中力が乱れています。別のパターンとしては、調べものをしているうちに、いつのまにか全然関係ないことを調べて無駄に時間が過ぎていた、ということもよくあります。調べものはコーディングに不可欠と割りきって、さっさと片付けたいところです。
おなじないが多すぎるコーディングも厄介です。コーディングには多かれ少なかれおまじないがつきものですが、これが大量にあると、コードを見ても何をやっているのか、わからなくなります。
何をもっておまじないとするかは人によって異なります。プログラミング未経験の人にとっては下のプログラムはほとんどすべてがおまじないに見えると思います。一方、Java 経験者にとっては、いたって明快なコードです。
public class HelloWorld { public static void main (String[] args) { System.out.println("hello, world"); } }
Javaを知らなくても、オブジェクト指向言語の経験があれば、 public や class といったキーワードの意味はわかります。hello, world と表示するだけで5行も要するのは少し長い気もしますが、このくらいなら慣れればすらすら書けそうです。
では、こんなコードはどうでしょうか。
#define MAMAN_TYPE_BAR \ (maman_bar_get_type ()) #define MAMAN_BAR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ MAMAN_TYPE_BAR, MamanBar)) #define MAMAN_IS_BAR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ MAMAN_TYPE_BAR)) #define MAMAN_BAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ MAMAN_TYPE_BAR, MamanBarClass)) #define MAMAN_IS_BAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ MAMAN_TYPE_BAR)) #define MAMAN_BAR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ MAMAN_TYPE_BAR, MamanBarClass)) typedef struct _MamanBar MamanBar; typedef struct _MamanBarClass MamanBarClass; (以下省略)
これは MamanBar というクラスを、GObject というライブラリを使って C言語で実装するコードの一部です *2。これは一部なので、実際にはもっとコードが必要です。
ここまで複雑になってくると、いくら慣れてもすらすら書けるという域を超えています。クラスをひとつ作るのがこれだけ大変だと、クラスを作るべきところでも作らずに手抜きをしてしまいそうです。おまじないなしで、コピーアンドペーストに頼らずにコードを書きたいものです。
簡単にできるはずのことが、無駄に複雑になってしまうコーディングはストレスの元です。複雑性には多くの場合、歴史的理由*3が存在しますが、単なる設計ミスという場合もあります。
「えーと、サーバに実験的な機能を入れてみたんだけど、いきなりこれ全サーバで動かすの危ないよなあ。サーバの起動オプションをひとつ増やして、開発用サーバだけでオンにすればいっか。オプション追加っと。」「あれ、これ、このオプションの値をオレの PenguinMassage クラスで参照するにはどうすればいいんだ」
「うげ、起動オプションはグローバルに参照可能になってないのか。ってことは main から ZooServer -> RequestHandler-> PenguinWorker -> PenguinKeeper -> PenguinMassage までいちいち、えんやこらとオプション渡さないといけないってこと?なんか他のオプションも律儀にそうやってるっぽいなあ。面倒くせー」
「なんでこうなってるのか元の作者に聞いてみるか。って新年会のTさんか。えー、グローバル変数は悪だからだって? グローバル変数だって適材適所なんじゃないですかねー。はあ、ダメなものはダメだと(ダメなのはお前の店選びだろ)。はいはい、じゃあ、ちまちまオプション渡すだけのコードを書けばいいんでしょ」「と言いつつ、起動オプション追加するんじゃなくて、こっそり環境変数を見るようにしちゃうもんね」
この場合、グローバル変数は悪、という思い込みが強すぎる開発者のせいで、簡単にできるはずのこと複雑になっています。同様に、APIの設計が悪いライブラリを使う場合も、簡単にできるはずのことが難しくなります。やりたいことが簡単に追加できるということは、いいコードのひとつの条件だと思います。
今回はコーディングをバッドなものにする要因について考察しました。バッドバッドと文句を言うだけでなく、ときにはバッドな問題の解決に果敢に挑戦することも大切だと思います。
一年間、6回に渡ってソフトウェア開発における危険信号「バッドシグナル」について書きました。私の場合、ソフトウェア開発の経験を積むにつれて、バッドシグナルの嗅覚がだいぶ養われてきたと思っていましたが、いまだに「思い返せば、あれがバッドシグナルだった」と後から気づくこともしばしばです。今後も地道に修行を続けていきたいと思います。
*1XSL Transformations - XMLを変換する技術のひとつ。
*2<http://library.gnome.org/devel/gobject/stable/howto-gobject.html> のコードを抜粋。誌面の都合で一部、改行を入れています
*3バッドシグナル通信の第1回「歴史的理由」を参照のこと。