ソフトウェア設計

早すぎる最適化は諸悪の根源――クヌースが本当に伝えたかったこと

「早すぎる最適化は諸悪の根源」というクヌースの言葉は、後半が省略された引用です。97%は忘れて3%に集中するという原文の文脈と、プロファイラでボトルネックを確認してから最適化する実務上の基準を整理します。

読了 5 分
早すぎる最適化は諸悪の根源――クヌースが本当に伝えたかったことのカバー画像

コードレビューで「早すぎる最適化は諸悪の根源」という言葉を、一度は聞いたことがあるでしょう。

しかし原文を読んでみると、話は少し違います。ドナルド・クヌースが本当に言いたかったのは、決して「最適化するな」ではありません。

結論から言うと、クヌースは「97%の些細な最適化は忘れ、本当に重要な3%を決して逃すな」と述べました。よく引用される半端な一文では、その後半が丸ごと切り落とされています。

今回は、この言葉の本当の文脈と、コードをいつ最適化すべきかを整理します。

原文はこうでした

出典は、ドナルド・クヌースが1974年に執筆した論文です。タイトルは「Structured Programming with go to Statements」で、ACM Computing Surveysに掲載されました。

原文をそのまま示すと、次のとおりです。

「些細な効率化、いわば97%については忘れるべきだ。早すぎる最適化は諸悪の根源である。しかし、その決定的な3%で機会を逃してはならない。」

お分かりでしょうか。私たちが知っている言葉は、ちょうど中央だけを切り取ったものです。

前には「97%は忘れろ」、後ろには「3%を逃すな」が続きます。この3文で一つのセットです。

クヌースは最適化するなと言ったのではありません。どこに力を注ぐか選べ、と言ったのです。

Structured Programmingの論文の印刷物に蛍光ペンで文が示された机
原文を読むと、省略された後半の文こそ本当の核心だと分かります。

「97%は忘れて3%に集中する」これが核心です

クヌースは同じ論文で、もう一つ重要な指摘をしています。

プログラマーは、プログラムの重要でない部分の速度を気にして、膨大な時間を浪費しているという指摘です。

そのように先回りして施した最適化が、かえってデバッグや保守を難しくすることもあります。

つまり問題は最適化そのものではなく、タイミングと場所です。ボトルネックがどこかも分からない状態で、手当たり次第に変更することが問題なのです。

最適化するなではなく、根拠なくどこでも最適化するな、という意味です。


では、いつ最適化すべきでしょうか?

最もよく聞かれる質問です。答えは単純で、測定してからです。

クヌースの言う決定的な3%を見つける方法は、勘ではなく測定です。プロファイラを実行して実際に時間を消費している箇所を見つけ、そこを改善します。

Swiftなら、次のようにまずボトルネックを確認できます。

// 実際にどのコードが時間を消費しているか測定
let clock = ContinuousClock()
let elapsed = clock.measure {
    slowFunction()
}
print(elapsed)  // 所要時間が大きい区間がその '3%'
遅い関数が強調表示されたプロファイラの出力が映る開発者のノートPC画面
勘で決めず、まずプロファイラを実行すればボトルネックがはっきり見えます。

測定してみると、予想が外れていることがほとんどです。「ここが遅いはず」と思った場所は問題なく、考えもしなかった一つのループが全体を圧迫していることもよくあります。

早すぎる最適化と正当な最適化は、次のように区別すると分かりやすいでしょう。

区分 早すぎる最適化 正当な最適化
時点 測定前、勘で 測定後、データで
対象 目につく任意の場所 ボトルネックと確認された3%
結果 コードが複雑になるだけ 実際のパフォーマンス改善

もう一つ、この言葉は実はクヌースのものではないかもしれません

興味深い後日談があります。

この文はトニー・ホーア(C. A. R. Hoare)の言葉としてもよく引用されます。広く使われている引用サイトにも、ホーアの名言として掲載されています。

ところがクヌース自身は、1989年の論文「The Errors of TeX」でこれを「ホーアの格言(Hoare’s Dictum)」と呼びました。

ホーアもまた、自分の言葉ではなくクヌースの言葉だと述べています。

二人の巨匠が互いに「あなたの言葉だ」と譲り合った形ですが、文献上は1974年の論文に初めて登場したクヌースの表現とするのが定説です。

誰が最初に言ったかにかかわらず、重要なのは本来の意味が半分に切り取られ、誤解されていることです。


よくある質問

Q. では、最初からパフォーマンスを気にしなくてもよいのですか?

いいえ。アルゴリズムの選択のように構造を決める判断は、最初から考慮すべきです。クヌースが忘れろと言ったのは「些細な」効率であり、設計レベルの判断ではありません。

Q. 測定はいつ行いますか?

動作するコードをまず作った後です。まず動く状態にし、遅ければプロファイラでボトルネックを探し、その箇所だけを直します。


この言葉に再び出会ったら、今度は後半まで思い出してください。97%は忘れても、3%は逃さないことです。

測定なしの最適化には注意しつつ、本当のボトルネックにはひるまないこと。クヌースが本当に伝えたかったのはそれです。

今日のコードで「何となく遅そうだから」と変更しようとしている箇所があるなら、まず一度プロファイラを実行してみてください。

参考資料