バッドシグナル通信

最終回 バッドなコーディング

ソフトウェア開発における危険信号「バッドシグナル」についての本連載、最終回の今回はコーディングをバッドなものにする要因について検討してみたいと思います。

バッドなコーディング

三度の飯よりコーディングが好き! という人でも、気乗りのしないコーディングというものもあると思います。コードを書くという作業自体はそれほど変わらないはずなのに、何が原因で退屈だったり苦痛だったりするバッドな作業になってしまうのでしょうか。

何をバッドと感じるかは個人差があると思いますが、ここでは筆者がバッドと感じる要因を見ていきたいと思います。プロジェクトがそもそも好きじゃない、メンテナと仲が悪いといった人間的な要因は今回は除外しました。

待ち時間長過ぎ

待ち時間の長いコーディングはいやなものです。たとえば、ビルドに何十分もかかるようなプログラムです。初回のビルドに時間がかかるのは許せますが、1ファイルいじっただけで長々と待たされるようなビルドはいただけません。

「ちょっといじったからビルドするかな。makeっと」

「なかなかコンパイル始まらないなー。これなぜか、のろいんだよな。メールでもチェックするか」

「お、新年会やるのかー。って店はどこだろ。うわ、なんかいけてない店だなあ。って幹事Tさんか。なんとか他の店に変えてもらう方法ないかなあ。失礼にならないようにメールで聞いてみるかなあ」

「こういうメール書くの意外と疲れるなあ。送信っと」

「で、何やってたんだっけ。うわ、コンパイルエラーで止まっちゃってるじゃん...」

同様に、実行に時間がかかるプログラムも、いやなものです。実行して結果が出るまで数時間もかかるようなプログラム(本番のでかいデータではなく、小さなデータでテストできるとグッド)や、リモートのサーバで実行するための準備作業に時間がかかるようなプログラム(ローカルでテストできるとグッド)です。

一度途切れた集中力を取り戻すには20~30分くらい余裕でかかります。これは、コンテクストスイッチのコストなどと呼ばれています。ビルドが速くて、手元でサクサクとテストできるプログラムが理想的です。

調べもの多過ぎ

ライブラリのAPIを調べたり、サンプルコードを探したりといった調べものはコーディングに不可欠です。が、こればかりに時間を食っているとだんだん飽きてきます。とりわけ、1回限りしか使わないような技術だと身が入りません。

「うわ、このプログラム、なんかXSLT[1]を駆使してがんばってるなあ。テンプレートファイルみたいのたくさんあるけど、さっぱり読めん...とりあえず検索してみるかな。お、英語のWikipediaにXSLTのサンプル発見。って、これだけじゃ単純すぎて役に立たんなあ」

「しょうがないから仕様書でも見てみるか」

「でか! これ印刷すると200ページくらいあるじゃん。どうせ二度と使わんし、こんなの真面目に読んでられんなあ。必要そうなところだけ目を通しとくかな」

「その前にメールでも読むか。あ、新年会の店、変わったっぽい。よかったよかった。返事書いとくかな」

「今度こそ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;

struct _MamanBar
{
  GObject parent_instance;

  /* instance members */
};

<以下略>

これはMamanBarというクラスを、GObjectというライブラリを使ってC言語で実装するコードの一部です[2]⁠。上記は一部なので、実際にはもっとコードが必要です。

ここまで複雑になってくると、いくら慣れてもすらすら書けるという域を超えています。クラスを1つ作るのがこれだけ大変だと、クラスを作るべきところでも作らずに手抜きをしてしまいそうです。おまじないなしで、コピー&ペーストに頼らずにコードを書きたいものです。

無駄に複雑過ぎ

簡単にできるはずのことが、無駄に複雑になってしまうコーディングはストレスの元です。複雑性には多くの場合、歴史的理由[3]が存在しますが、単なる設計ミスという場合もあります。

「えーと、サーバに実験的な機能を入れてみたんだけど、いきなりこれ全サーバで動かすの危ないよなあ。サーバの起動オプションを1つ増やして、開発用サーバだけでオンにすればいっか。オプション追加っと」

「あれ、これ、このオプションの値をオレのPenguin Massageクラスで参照するにはどうすればいいんだ」

「うげ、起動オプションはグローバルに参照可能になってないのか。ってことはmainからZooServer→RequestHandler→PenguinWorker→Penguin Keeper→PenguinMassageまでいちいち、えんやこらとオプション渡せってこと? なんか他のオプションも律儀にそうやってるっぽいなあ。面倒くせー」

「なんでこうなってるのか元の作者に聞いてみるか。って新年会のTさんか。えー、グローバル変数は悪だからだって? グローバル変数だって適材適所なんじゃないですかねー。はあ、ダメなものはダメだと(ダメなのはお前の店選びだろ⁠⁠。はいはい、じゃあ、ちまちまオプション渡すだけのコードを書けばいいんでしょ」

「と言いつつ、起動オプション追加するんじゃなくて、こっそり環境変数を見るようにしちゃうもんね」

この場合、グローバル変数は悪、という思い込みが強過ぎる開発者のせいで、簡単にできるはずのことが複雑になっています。同様に、APIの設計が悪いライブラリを使う場合も、簡単にできるはずのことが難しくなります。やりたいことが簡単に追加できるということは、いいコードの一つの条件だと思います。

まとめ

今回はコーディングをバッドなものにする要因について考察しました。バッドバッドと文句を言うだけでなく、ときにはバッドな問題の解決に果敢に挑戦することも大切だと思います。

1年間、6回にわたってソフトウェア開発における危険信号「バッドシグナル」について書きました。筆者の場合、ソフトウェア開発の経験を積むにつれて、バッドシグナルの嗅覚がだいぶ養われてきたと思っていましたが、いまだに「思い返せば、あれがバッドシグナルだった」と後から気づくこともしばしばです。今後も地道に修行を続けていきたいと思います。

まだまだ甘いのう...

おすすめ記事

記事・ニュース一覧