この、ドナルド・クヌース先生の有名な格言について考えてみます。
プログラムのコードをきれいな状態に保つことと、実行速度の向上や必要なリソースの削減といった最適化を図ることとは両立しない場合が多々あります。こうした場合にどちらを優先すべきか?という問いに対し、クヌース先生は「まずコードをきれいにしろ」と答えています。
ソフトウェアのユーザにとって、コードがきれいかどうかは何の価値もありません。対して実行速度などは使いやすさに直結する重要な要素です。それなのになぜ、きれいなコードのほうが優先されるべきなのでしょうか?
きれいなコードとは? なぜ最適化と両立しない?
まず考える必要があるのは「きれいなコード」とは何か?ということです。
それは、開発者がコードを眺めて「なんて美しいんだ!」と悦に入るためのものではありません。
きれいなコードの条件として、大きく以下の2つが挙げられると思います。
・理解しやすい
・修正しやすい
「理解しやすい」ためには、コードの一部だけを見ることで、それが何をするためのものなのかが判断できるということが必要です。
逆に「コードを全て読んで初めて、とある関数が何をしているのかが分かった」などというのでは、理解しやすいとは言えません。
「修正しやすい」ためには、コードの一部を修正した場合、その影響が他の部分へ及ばないことが必要です。
逆に「ここを書き換えたら、何が起こるかわからない」というのでは、修正は困難になります。
どちらの条件も、コードの各部分が独立性を保っていることがカギとなります。どこから参照されてるかわからないグローバル変数が使われているとか、何故だか処理Aは処理Bの前に必ず呼ばなくてはならないといった制約がある、といった場合には独立性が損なわれていることになります。
実のところ、「オブジェクト指向」や「抽象化」といった概念は、この、各部分の独立性を保つということを実現するためにあります。
さらに言うと、コードの各部分とはクラスや関数の形で表れることになりますが、それぞれが適切な大きさであり、ふさわしい名前が付けられているといったことも重要です。
これに対し、最適化を行う場合には、たとえば処理Aの過程でできたリソースを、せっかくだから処理Bで使いまわせば効率が良いじゃないか、といったことが行われます。もったいない精神と考えてもいいかもしれません。
こうした場合、処理Bは処理Aの内容に依存することになります。Bへの影響が及ぶことからAをおいそれとは修正できなくなり、恐らくはそれぞれの処理を呼び出す順序にも制約が生じることになります。つまり、AとBそれぞれの独立性が失われるわけです。きれいなコードと最適化されたコードが両立しない理由はここにあります。
きれいなコードを最適化するのは容易。逆は困難。
きれいな(修正が容易な)コードであれば、最適化も容易です。
逆に最適化によって修正が難しくなったコードは、きれいにするのも困難です。
また、ある一定以上の規模のソフトウェアであれば、機能追加や修正がまったく発生しないということはほぼありません。そのソフトウェアが使われなくなるまで、コードをきれいにしておくことで、メンテナンス性を保つということが重要になります。
したがって、状況にもよりますが、まずはきれいなコードを書き、必要に応じて最適化を施す、というのが開発における理想的な戦略になります。
コードのどこが遅いのかは、予測するのが難しい
でもやっぱり、速く動作するソフトウェアには価値がある。最適化を優先したい。と考える開発者もいると思います。が、ちょっと待ってください。
コードを書いていると、つい「この関数が呼ばれるたびにこのインスタンスを生成することになっちゃうのか。なんだか効率が悪そうだな。。。」なんてことを考えます。
しかしこうした「このせいで動作が重くなるのでは?」という推測は、しばしば外れます。実際動かしてみれば、心配してたほどの影響はない、という場合が非常に多いのです。逆に、思いもよらない場所がボトルネックになることもよくあります。
さらには、動作が重いというとき、その実行時間の大部分がプログラムのほんの一部分において費やされるといった状況もよく発生します。この場合、それ以外の部分に最適化を施しても、その効果は微々たるものになります。
最適化は推測ではなく、実測に基づいて行うべし
最適化を行う上で重要なのは、どこを最適化すれば効果的なのかを判断することです。これは、時間計測のコードを挿入したり、プロファイラを利用するなどして、実測を行った上で決めるべきです。
実測をせずに推測だけで行う「早すぎる最適化」は、何の効果も上げられないまま、いたずらにコードを汚してしまう可能性があります。開発者がソフトウェアの性能に対して行う推測は、あてにならない場合が多いのです。
最適化の作業は、しばしば開発者を没頭させる甘い罠です。それは本当に行う価値があるのか?裏付けをもって行いましょう。
まとめ
きれいなコードとは、各部分の独立性が保たれることによって、理解しやすく修正しやすいコード。
最適化を行うと、きれいなコードを汚してしまう場合がある。
まずはきれいなコードを書き、その後必要に応じて最適化を行うべし。
最適化を行う場合は、どの部分を最適化すべきかを判断することが重要。
どの部分を最適化すべきかの判断を、推測に基づいて行うのは良くない。実測してから行うべし。