That's the question.

分裂勘違い君劇場 - 「同じことを2度しないようにする」というプログラマの習性が、逆に生産性を大きく下げている
この記事で主張しているように「同じことを2度しない(Only and Only OnceあるいはDRY:Don't Repeat Yourself)」と無条件で考えてしまうと、逆に生産性が大きく低下するケースがたくさんある。

分裂勘違い君も指摘しているように、実は「繰り返さない」という選択には、「繰り返さないための仕組みを作る」というコストが伴う。

例えばフィボナッチ数のことを考えてみる。1, 1, 2, 3, 5, 8という数字を見せられて、「次に来るのは何?」と聞かれたら、わざわざ

perl -le 'sub f{my $n=shift; $n<2 ? $n : f($n-1)+f($n-2)}; print f(7)'

などとやるのは間抜けだ。そのまま5と8を足して13とやった方がいい。しかし「20番目は何?」と言われたら、

perl -le 'sub f{my $n=shift; $n<2 ? $n : f($n-1)+f($n-2)}; print f(19)'
とやった方がいいし、さらにこれが「100番目」とかになったら、さらにf()の定義の見直しが必要で、例えば

perl -MMemoize -le 'sub f{my $n=shift; $n<2 ? $n : f($n-1)+f($n-2)};' \
 -e 'memoize "f"; print f(100)'

という具合にMemoizeを使うとか、あるいは数学を駆使して

perl -le '$a=(1+sqrt(5))/2; $b=(1-sqrt(5))/2' \
 -e 'sub f{my $n=shift; int(($a**$n+$b**$n)/sqrt(5))}; print f(100);'

とかする必要が出てくるだろう。さらに何度も繰り返して使うのであれば、

perl -le '$a=(1+sqrt(5))/2; $b=(1-sqrt(5))/2;' \
 -e 'sub f{my $n=shift; int(($a**$n+$b**$n)/sqrt(5))}; print f(shift)' 100

という具合に引数で指定できるようにした方がいいし、一行野郎ですませるのではなくちゃんと実行可能なテキストファイルにした上で、fib.pl 100とかした方がいい。

しかし最初に戻って、「1, 1, 2, 3, 5, 8の次に来るのは?」と聞かれたら、プログラムを書くのすらもどかしいではないか。「とっとと考えないでやっちまった方が早くて安くて旨い」という例はプログラムに限らず人生の至る所で見られる。

一つ言えるのは、この編の「考えるべきかやっちまうべきか」の問題は、「やってみないと」わからないということだ。「やってみて、歯が立ちそうもなければ考える」。今のところこれが「枯れたアルゴリズム」のようである。

「20インチの望遠鏡を磨くには、まず10インチの望遠鏡を磨いてみてから取りかかった方が、20インチにいきなり挑戦するより早い」といったのは誰だっけ。確か"Programming Pearl"のどこかのページに載っていたことばだ。

最近悩ましいのは、「探した方がいいか考えた方がいいか」という設問である。分裂勘違い君も別entryで自分のキャッシュの深さを嘆いていたが、私も最近車輪を再発明してしまうことが昔に比べて増えて来たように思う。検索もまたコストなのだ。

Dan the Lazy, Impatient, and Hubristic