プログラマは悲観的な生き物である。少なくとも、プログラマとして考えるときには、悲観的になる。
この「悲観的」とはどういうことか。
人間の思考には「制御幻想」というバイアスがある。「実際には偶然によって生じているのに、自分の意図と能力によって統制できると錯覚する現象。自尊心の自己防衛論的観点で説明される」。
たとえば、ただのサイコロを被験者に渡して、何百回か振らせる。ただしそのとき、「これはイカサマ用の仕掛けのついたサイコロで、投げ方を会得すれば高い確率で狙った目が出せる」と吹き込んでおく。すると被験者は、何百回か振るうちに、「イカサマの投げ方を会得した」と思い込むわけだ。
この罠にひっかからない人もいる。たとえば、抑うつ状態の人だ。また、この罠にひっかかっていては仕事にならない人もいる。たとえば、プログラマだ。
昔なにかの本で、こんな話を読んだ。プログラムをコーディングシートに記入して計算機センターに持っていった時代の話だ。計算機センターが「このプログラムはエラーで止まった」と報告してきたのに対して、「そんなわけはない、そっちが間違ってる」と言い張ってきかないプログラマがいたという。生まれて初めて書いたプログラムでそこまで言い張るのは、困った人を通り越してヤバい人なので、多少の「自信」を得るだけの経験はあったのだろう。その「自信」は、「イカサマの投げ方を会得した」という思い込みと同種のものだったわけだ。
もちろんプログラマも経験則に頼る。たとえば私は、「開発環境を疑うのは疲労の兆候」という経験則を固く信じている。コンパイラ等のバグに出くわすことは非常に稀なのに対し、疲労のせいで他人を疑い出す現象は非常によくある。
だから、経験則がすべて悪いのではない。「自尊心の自己防衛」に奉仕するもの、「イカサマの投げ方を会得した」という思い込みに類するものを退けなければならない。
こういう態度は、少なくとも「イカサマの投げ方を会得した」と軽々しく思い込む種類の人間からは、「悲観的」と呼ばれるだろう。
さて本書、『リーダブルコード』について。
著者は35ページで、「C++のSTLのlist::size()の計算量がO(n)だとは予期しなかったので、実行性能上のバグを作った。size()の計算量がO(n)なのはユーザの期待に反する。関数は名前から期待される挙動をしなければならない」と述べている。
「関数は名前から期待される挙動をしなければならない」。一般論としては当たり前の話ではある。もしコレクションのsize()がコレクションを初期化したら、誰がどう見てもバグだ。
だが、著者の述べるケースは、それほど自明ではない。
プログラミングの一般論には、こんなものもある――「実行性能を当て推量するな」。キャッシュもなければ命令パイプラインもないCPUのアセンブリ言語を書いていた時代はとっくに終わった。データが小さければ、O(n^2)のコードがO(1)より速い場合はままある。
そして、標準ライブラリの計算量について予期を抱くことも、実行性能の当て推量にほかならない。
というわけで、著者の述べるケースは、「関数は名前から期待される挙動をしなければならない」という一般論が単純に通じるケースではない。このことだけでも著者の能力を疑うが、問題はもうひとつある。
著者は、自分の出くわしたバグを、「関数は名前から期待される挙動をしなければならない」という一般論に帰した。だが、こんな議論に帰してもいいはずだ――「関数のユーザがどんな予期を抱くかを予想するのは難しい」。
関数のユーザがどんな予期を抱くかを予想するのは難しい。
プログラマならだれでも、この食い違いが多くのバグを生むことを知っている。この問題の一例に対して著者は、「関数の名前と挙動を一致させればよい」と処方箋を示したわけだ。だがこの処方箋は、一般性のない、「イカサマの投げ方」ではないか。
「関数のユーザがどんな予期を抱くかを予想するのは難しい」ということへの認識の甘さを感じさせる例が、ほかにもある。たとえば135ページ、「汎用コードをたくさん作る」だ。
はたして著者は、2分探索の歴史を知っているのだろうか。2分探索の概念が公表されてから(1946年)、バグのないコードが公表されるまでのあいだに、12年以上もかかった。
汎用コード、言い換えれば、入力に対する暗黙の前提を持たないコードを書くことは、腰を抜かすほど難しい。特定の状況で、入力に対する暗黙の前提にべったり依存したコードを書くこととは、トライアスロンと100m走ほどにも違う(種目が違うだけで、どちらかが偉いわけではない。100m走で10秒を切れば英雄だ)。だが著者の陽気な書きぶりは、この桁外れの難しさを認識しているようには到底見えない。著者は、ドキュメントに明示されているlist::size()の計算量さえ、「ユーザの期待に反する」と言ってのける。
関数のユーザがどんな予期を抱くかを予想するのは難しい。バグは避けられない。当て推量は当たらない。
私は本書から、こうした「悲観的」な認識を感じることはできなかった。
私は著者のプログラマとしての資質と能力を強く疑う。また、本書はほとんどのプログラマにとって、よくても無益であり、悪くすれば益よりも害が大きい、と考える。