コードレビューで「早すぎる最適化は諸悪の根源」という言葉を、一度は聞いたことがあるでしょう。
しかし原文を読んでみると、話は少し違います。ドナルド・クヌースが本当に言いたかったのは、決して「最適化するな」ではありません。
結論から言うと、クヌースは「97%の些細な最適化は忘れ、本当に重要な3%を決して逃すな」と述べました。よく引用される半端な一文では、その後半が丸ごと切り落とされています。
今回は、この言葉の本当の文脈と、コードをいつ最適化すべきかを整理します。
原文はこうでした
出典は、ドナルド・クヌースが1974年に執筆した論文です。タイトルは「Structured Programming with go to Statements」で、ACM Computing Surveysに掲載されました。
原文をそのまま示すと、次のとおりです。
「些細な効率化、いわば97%については忘れるべきだ。早すぎる最適化は諸悪の根源である。しかし、その決定的な3%で機会を逃してはならない。」
お分かりでしょうか。私たちが知っている言葉は、ちょうど中央だけを切り取ったものです。
前には「97%は忘れろ」、後ろには「3%を逃すな」が続きます。この3文で一つのセットです。
クヌースは最適化するなと言ったのではありません。どこに力を注ぐか選べ、と言ったのです。
「97%は忘れて3%に集中する」これが核心です
クヌースは同じ論文で、もう一つ重要な指摘をしています。
プログラマーは、プログラムの重要でない部分の速度を気にして、膨大な時間を浪費しているという指摘です。
そのように先回りして施した最適化が、かえってデバッグや保守を難しくすることもあります。
つまり問題は最適化そのものではなく、タイミングと場所です。ボトルネックがどこかも分からない状態で、手当たり次第に変更することが問題なのです。
最適化するなではなく、根拠なくどこでも最適化するな、という意味です。
では、いつ最適化すべきでしょうか?
最もよく聞かれる質問です。答えは単純で、測定してからです。
クヌースの言う決定的な3%を見つける方法は、勘ではなく測定です。プロファイラを実行して実際に時間を消費している箇所を見つけ、そこを改善します。
Swiftなら、次のようにまずボトルネックを確認できます。
// 実際にどのコードが時間を消費しているか測定
let clock = ContinuousClock()
let elapsed = clock.measure {
slowFunction()
}
print(elapsed) // 所要時間が大きい区間がその '3%'
測定してみると、予想が外れていることがほとんどです。「ここが遅いはず」と思った場所は問題なく、考えもしなかった一つのループが全体を圧迫していることもよくあります。
早すぎる最適化と正当な最適化は、次のように区別すると分かりやすいでしょう。
| 区分 | 早すぎる最適化 | 正当な最適化 |
|---|---|---|
| 時点 | 測定前、勘で | 測定後、データで |
| 対象 | 目につく任意の場所 | ボトルネックと確認された3% |
| 結果 | コードが複雑になるだけ | 実際のパフォーマンス改善 |
もう一つ、この言葉は実はクヌースのものではないかもしれません
興味深い後日談があります。
この文はトニー・ホーア(C. A. R. Hoare)の言葉としてもよく引用されます。広く使われている引用サイトにも、ホーアの名言として掲載されています。
ところがクヌース自身は、1989年の論文「The Errors of TeX」でこれを「ホーアの格言(Hoare’s Dictum)」と呼びました。
ホーアもまた、自分の言葉ではなくクヌースの言葉だと述べています。
二人の巨匠が互いに「あなたの言葉だ」と譲り合った形ですが、文献上は1974年の論文に初めて登場したクヌースの表現とするのが定説です。
誰が最初に言ったかにかかわらず、重要なのは本来の意味が半分に切り取られ、誤解されていることです。
よくある質問
Q. では、最初からパフォーマンスを気にしなくてもよいのですか?
いいえ。アルゴリズムの選択のように構造を決める判断は、最初から考慮すべきです。クヌースが忘れろと言ったのは「些細な」効率であり、設計レベルの判断ではありません。
Q. 測定はいつ行いますか?
動作するコードをまず作った後です。まず動く状態にし、遅ければプロファイラでボトルネックを探し、その箇所だけを直します。
この言葉に再び出会ったら、今度は後半まで思い出してください。97%は忘れても、3%は逃さないことです。
測定なしの最適化には注意しつつ、本当のボトルネックにはひるまないこと。クヌースが本当に伝えたかったのはそれです。
今日のコードで「何となく遅そうだから」と変更しようとしている箇所があるなら、まず一度プロファイラを実行してみてください。

