プログラマが知るべき97のこと/いったんコンピュータから離れてみる

何時間も集中して考えているのに、問題があまりに難しくなかなか解決策が思いつかない。仕方がないので、散歩に出てみたり、自動販売機まで何かを買いに行ったりしたら、帰りに突然答えがわかった。そういう経験をしたことのある人は案外多いのではないでしょうか。

どうしてこんなことが起きるのでしょうか。コーディング中は脳の論理を司る部分だけがはたらいていて、創造を司る部分がはたらいていないためではないかと私は考えています。発想の飛躍が求められるような場面では、論理を司る部分が休まない限り、解決策が見つからないということなのかもしれません。

実例を挙げましょう。私は以前、レガシーコードの改修中に面白いメソッドを見つけました。それは、文字列の中に"hh:mm:ss :xx"という形式の適切な時刻情報が含まれているか検証するメソッドでした。hhには時間、mmには分、ssには秒、:xxにはAMあるいはPMが入ります。

そのメソッドでは、次のようなコードで、(時間を表す)2文字を数値に変換し、値が適切な範囲内にあるか検証していました。

try {
    Integer.parseInt(time.substring(0, 2));
} catch (Exception x) {
    return false;
}
if (Integer.parseInt(time.substring(0, 2)) > 12) {
    return false;
}

その後には、分と秒の情報を検証するための同様のコードがありました。もちろん、文字列オフセットと、数値の上限値は上のコードとは違います。メソッドの最後は、AMとPMの情報を検証する次のようなコードでした。

if (!time.substring(9, 11).equals("AM") &
    !time.substring(9, 11).equals("PM")) {
    return false;
}

検証により、いずれかの情報が適切でなければfalseが返され、すべて適切であればtrueが返されます。

冗長でわかりにくいコードだと,思った人も多いと思います。確かにそのとおりです。私もそう思ったので、改修することにしました。メソッドをリファクタリングし、ユニットテストをいくつか書いて、正しく機能することを確認しました。

改修結果にはとても満足していました。改修後のバージョンは読みやすいだけでなく、サイズも半分になり、加えてより確実な検証ができるようになったからです。元のコードのように、時間、分、秒が上限を超えていないかを確認するだけでなく、より厳密に確認するようにしたのです。

しかし翌朝、仕事を始める前に1つひらめいたのです。「どうして正規表現を使って文字列を検証するコードにしなかったのだろう」。わずか数分間の作業で、コードは次のようにたった1行になりました。

public static boolean validateTime(String time) {
    return time.matches("(0[1-9]1[0-2]):[0-5][0-9]:[0-5][0-9]([AP]M)");
}

ここで重要なのは、30行以上あったコードが最終的にたった1行になったということではありません。コンピュータに向かい合っているうちは「もうこれ以上のものはできない」と,思っていた、ということです。

ここまで書いてきたような問題解決方法もあるのです。ある問題について十分に考えたら、あとは音楽を聴くなり、散歩をするなりして、脳の創造を司る部分をはたらかせてみてください。じっとコンピュータの前に座って考え込んでいるより、その方が良いアイデアを思いつくものです。