「時期尚早な最適化がすべての悪の根源」についての誤解に対処する方法は?


26

私は、一般的な英語の意味で「最適化」とみなされるものに対して独断的に多くの人々に出会いました。そして、彼らは非常にしばしば「部分的な」引用「早すぎる最適化はすべての悪の根源」です彼らのスタンスの正当化として、私が話していることは何でも「時期尚早の最適化」であると解釈することを意味します。しかし、これらのビューは非常に馬鹿げているため、最も純粋な「単純な」実装からのあらゆる種類のアルゴリズムまたはデータ構造の逸脱、または少なくとも以前のやり方からの逸脱を排除します。「パフォーマンス」や「最適化」について聞いてからシャットダウンした後に再び「耳を開く」ように、このような人々にどのようにアプローチできますか?「この男は10行のコードに2週間を費やしたい」とすぐに思わせることなく、パフォーマンスに影響を与える設計/実装のトピックについて議論するにはどうすればよいですか。

さて、「すべての最適化は時期尚早ので、悪である」かどうかのスタンスがいるすでにここにカバーされてだけでなく、ウェブの他のコーナーで、すでに議論されている最適化は時期尚早ので、悪の場合に認識する方法が、残念ながら、現実の世界には、反最適化への信仰への挑戦に対してあまり開かれていない人々がまだいます。

以前の試み

数回、「時期尚早の最適化は悪い」↛「すべての最適化は悪い」と説明するために、ドナルドクヌースから完全な引用を提供しようとしまし

私たちは小さな効率を忘れてはなりません。約97%の時間です。早すぎる最適化はすべての悪の根源です。しかし、その重要な3%でチャンスを逃してはなりません。

しかし、見積もり全体を提供するとき、これらの人々は実際に、私がやっていることはPremature Optimization™であると確信し、耳を傾けて拒否します。それはまるで「最適化」という言葉が彼らを怖がらせるかのようです:数回、「optimiz(e | ation)」という言葉の使用を単に避けることで、拒否されずに実際のパフォーマンス改善コードの変更を提案することができました( 「パフォーマンス」も同様です-その言葉も怖いです)代わりに、「代替アーキテクチャ」や「改善された実装」のような表現を使用しています。このため、これは本当に独断的であり、実際に私が言うことを批判的に評価し、それを不要であるか、費用がかかりすぎると却下するのではないようです。


10
さて、前回あなたがそのような議論をしたとき、あなたは本当に純粋で素朴な実装ではパフォーマンスが悪いだろうと測定しましたか?または、少なくとも、予想される実行時間について大まかな見積もりをしましたか?そうでない場合、それらの他の人々は彼らの意見で完全に正しいかもしれません、あなたは知る方法がありません。
Doc Brown

12
@errantlinguist:プログラムが本当に「糖蜜のように遅い」場合、明らかに、Knuthの「その重要な3%」を簡単に検出できるはずであり、したがって、それを最適化することに反対する議論に勝るはずです。そして、それを検出できない場合は、宿題をまだ済ませておらず、まだ最適化する準備ができていません。したがって、問題がどこにあるのかは明確ではありません。
ニコルボーラス

6
@errantlinguist:コードのそのセクションがアプリケーションの重大なパフォーマンス問題であることの証拠を提示し、アプリケーション全体が必要以上に遅く、それでもコードを変更する必要性を拒否した場合、問題ない。あなたは、証拠に基づいた推論を受け入れず、したがって不合理な人々を扱っています。
ニコルボーラス

6
@errantlinguist:重要な質問:顧客はその分野のアプリケーションが遅いと不平を言っていましたか?
ロボット

5
OPは明らかに、実際の質問への回答ではなく、意見を検証するために誰かを探しているだけだからです。Workplace.SEでもこれが開いたままになるとは思わない(またはそうすべきではない)。
BlueRaja-ダニーPflughoeft

回答:


35

「純粋な素朴な実装」を最初に試さないで、「素朴な実装ではできないことを事前に知っているため、より洗練されたソリューション」を直接実装するショートカットを探しているようです。残念ながら、これはほとんど機能しません- 素朴な実装が遅すぎるか遅すぎることを証明する確固たる事実や技術的な議論がない場合、おそらく間違いであり、あなたがしているの時期尚早な最適化です。そして、Knuthと議論しようとすることは、難しい事実を持つことの反対です。

私の経験では、最初に弾丸を噛んで「単純な実装」を試す必要があります(そして、これがどれくらいの頻度でおそらく驚くでしょう)、または少なくとも次のように実行時間について大まかな見積もりをします:

「素朴な実装はO(n³)であり、nは100.000より大きくなります。数日実行されますが、それほど素朴な実装はO(n)で実行され、数分しかかかりません

そのような引数が手元にある場合にのみ、最適化が時期尚早でないことを確認できます。

これには、唯一の例外があります。より高速なソリューションがよりシンプルでクリーンなものである場合、最初からより高速なソリューションを使用する必要があります。標準的な例は、リストの代わりに辞書を使用してルックアップの不要なループコードを回避するか、必要な大きな結果セットの代わりに必要な1つの結果レコードを正確に提供する適切なSQLクエリの使用です。後でコードでフィルタリングされます。そのような場合は、パフォーマンスについて議論しないください-パフォーマンスは追加である可能性がありますが、ほとんどの場合は無関係なメリットであり、あなたがそれについて言及すると、人々はあなたに対してKnuthを使用したくなるかもしれません。読みやすさ、短いコード、きれいなコード、保守性について議論します-ここで何かを「隠す」必要はありませんが、それはそれら(そしてそれらだけ)が正しい引数だからです。

私の経験では、後者のケースはまれです-より一般的なケースは、より複雑で、おそらくより高速なものよりも理解しやすく、エラーが少ないシンプルで素朴なソリューションを最初に実装できる場合です。

そしてもちろん、要件とユースケースを十分に把握して、どのパフォーマンスが許容できるのか、ユーザーの目には「遅すぎる」状況を把握する必要があります。理想的な世界では、顧客から正式なパフォーマンス仕様が得られますが、実際のプロジェクトでは、必要なパフォーマンスは多くの場合灰色の領域です。多くの場合、それが何かが遅すぎるかどうかを調べる唯一の有効な方法です。ユーザーのフィードバックは、Knuthを引用してチームメイトに「ナイーブな実装」では不十分であると納得させる必要はありません。


15
@errantlinguist:多分私は自分自身をはっきりさせなかったのか、それとも単に聞きたいものではなかったのか?私からのアドバイスです:3% 『や『97%』「についてのクヌースの』 *哲学的引数を使ってみていない事実上のそれをしてください、そうでなければ、あなたの同僚はおそらく右のパフォーマンスの引数が不適切であるということである。。
ドク・ブラウン

4
@errantlinguist:Karl Bielefeldの答えへのコメントで説明した場合、「パフォーマンス」を使用する必要なく、すべての議論をあなたの側に持っているようです。さらに一歩進んで、そのような場合にパフォーマンスについて議論するなら、あなたの同僚は正しいので、あなたは大きな間違いを犯すだろうと言うでしょう。パフォーマンスは通常そこには関係ありません。シンプルさ、読みやすさ、保守性、コード行の削減については議論しますが、パフォーマンスについては(注)としてではなく、そうではありません。Knuthを使用する可能性を提供しないでください。
ドックブラウン

2
@errantlinguist:埋めない-それらの側面に焦点を合わせるべきであることが正しい場合、それらの側面に焦点を合わせ、エンドユーザーにとって重要な違いをもたらすことが証明できない場合は、引数としてパフォーマンスを使用しないでください。
Doc Brown

2
@errantlinguist:そ​​の結論にどのように到達するかわかりません。Doc Brownの答えは完全に明白です。許容できるパフォーマンスとそうでないパフォーマンスに関する事実の記述に固執することで、同僚との非生産的な議論を切り抜けます。
-jl6

1
これは小規模プログラミング向けの良いアドバイスですが、アーキテクチャ設計レベルでパフォーマンスの質問を無視すると、チームは長い行き止まりに陥る可能性があります。また、問題がアーキテクチャ上のものである場合、その作業の多くが再利用可能であるという保証はありません(製品を殺すのを見たことがあります)。 、そして質問をすることさえ、間違いなく誤り言語学者の同僚にとって嫌悪感です。
sdenham

18

これを自問してください:

  • ソフトウェアはパフォーマンス仕様を満たしていませんか?
  • ソフトウェアにパフォーマンスの問題はありますか?

これらが最適化の理由です。そのため、人々が反対する場合は、仕様を示して戻って、仕様を満たしていないため最適化する必要があることを説明してください。それ以外は、最適化が必要であることを他の人に納得させるのに苦労するでしょう。

引用の要点は、問題がなければ、他の場所で時間とエネルギーを費やす可能性があるため、不必要な最適化を実行しないことだと思います。将来のビジネスから、これは完全に理にかなっています。

第二に、最適化を恐れる人のために、パフォーマンスの結果をメトリックで常にバックアップします。コードはどれくらい高速ですか?パフォーマンスは以前よりどれくらい改善されましたか?以前のバージョンよりもコードを2%改善するためだけに2週間を費やした場合、私があなたの上司だったら、私は満足しません。これらの2週間は、より多くの顧客を引き付け、より多くの収益を上げることができる新しい機能の実装に費やされた可能性があります。

最後に、ほとんどのソフトウェアは高度に最適化する必要はありません。スピードが本当に重要なのは、いくつかの専門産業だけです。そのため、ほとんどの場合、既存のライブラリとフレームワークを使用して効果を上げることができます。


4
良い情報ではありますが、これは実際にパフォーマンスに関係する瞬間にディスカッションを妨害する人々とどのように働くかという私の質問には答えません。
誤り言語学者

7
「速度が本当に重要なのは、いくつかの専門産業でのみです」を除き、これらすべてに同意します。顧客の観点から、パフォーマンスの問題があるソフトウェアの量を過小評価していると思います。
ロボット

@StevenBurnap:ええ- 実際には遅くない野生のWebアプリケーションはありますか?-同じ科学分野のWebアプリケーションを見たいです。
誤り言語学者

1
google.comは非常に高速です。:-P
ロボットを

EDGEモバイル接続でgoogle.comを使用してみてください。はい、それはばかげたエッジケースですが、それは間違いなくかなり高速ではありません。;)(パンは実際には意図されていません
-errantlinguist

7

パフォーマンスに関係する瞬間にディスカッションを妨害する人々とどのように協力するか?

グループの戦略的方向性に基づいた共通の原則から始めます。

私の原則:

コードを書く上での私の個人的な原則は、最初にプログラムの正確性を目指し、次にプロファイルを作成し、最適化が必要かどうかを判断することです。他のプログラマーは私のコードの潜在的な消費者であるため、自分でコードをプロファイリングします-そして、それが遅い場合、彼らはそれを使用しません-したがって、私のコードにとって、速度は機能です。

消費者が顧客である場合、より速いコードが必要かどうかを顧客が教えてくれます。

ただし、コードには、明らかに実証できるほど優れた選択肢があります。いくつかの理由から、最初のドラフトでそれを正しく理解したいと思います。

  1. 最初に正しく理解できれば、実装を忘れることができ(情報の隠蔽を利用して)、TODOでコードを乱雑にすることはありません。
  2. 他の人(特に仕事でしか学ばない人)は、それが正しい方法で行われていることを理解し、今後同じスタイルのコードから学び、使用します。逆に、彼らが私に間違ったやり方をするのを見たら、彼らも間違ったやり方でやるでしょう。

最適化の必要性が正しいと仮定する

これが最適化が必要なコードの本当に重要な部分であると仮定すると、シュレミエルのたとえをペインターに伝えるか、引用の残りを強調することができます:

「プログラマーは、プログラムの重要でない部分の速度を考える、または心配するのに膨大な時間を浪費します。これらの効率化の試みは、デバッグとメンテナンスを考慮すると、実際に強いマイナスの影響を及ぼします。 97%の時間:早すぎる最適化はすべての悪の根源です。しかし、その重要な3%で機会を逃すべきではありません。」-ドナルド・クヌース

追加の複雑さのコストを比較検討する

追加される複雑さの保守性に関して、実際のコストがかかる場合があります。この場合、2次実装を別の関数またはサブクラスに保持し、同じユニットテストを適用して、それが正しいことを疑わないようにすることができます。後で、コードのプロファイルを作成し、ナイーブな実装がボトルネックになっている場合は、最適化されたコードに切り替えて、プログラムを明らかに改善できます。

リーダーシップ

時々、問題は自我です-一部の人々は、他の誰かが彼らよりもより適切であるよりも、準最適またはバグのあるコードを使用することを好むでしょう。あなたはおそらくこれらの人々との仕事を避けたいと思うでしょう。

リーダーシップは、特にあなたが人に対して位置的な権限を持っていない場合、合理的な提案を行い、他者をコンセンサスに導くことです。あなたのチームを心の会議に導くことができないなら、おそらく問題は急ぐ価値がありません。揚げる魚はおそらくもっと大きいでしょう。


6

前進する方法は、実際の引用とさまざまな解釈を忘れることです。それは、教祖による特定の引用にそれほど焦点を当てるのは、どちらの方法でも独断的です。とにかく、Knuthは常に正しいと言うのは誰ですか?

代わりに、手元のプロジェクト、あなたが同意しない同僚と一緒に開発しているソフトウェアに焦点を合わせます。このソフトウェアの許容可能なパフォーマンスの要件は何ですか?これより遅いですか?次に最適化します。

「最適化」と呼ぶ必要はありません。実装が要件に適合しない場合は定義上バグであるため、「バグを修正する」と呼ぶことができます。

より一般的には、最適化に関して2つの可能性があります。

  1. また、最適化されたコードは短く、理解しやすく、保守が容易です。

  2. 最適化されたコードは理解するのがより複雑で、作成とテストに時間がかかります。または、要件が予期しない方法で変更された場合、将来変更するのがより複雑になります。

(1)の場合、最適化について議論する必要すらありません。ただし、(2)が当てはまる場合は、トレードオフの決定を下しています。これは実際にはビジネスレベルの決定であり、純粋に技術的な決定ではありません。最適化のコストと利益を比較検討する必要があります。メリットがあるためには、まず最初に、ユーザーエクスペリエンスの悪さ、またはハードウェアやその他のリソースの大幅なコスト増加のいずれかとして、非効率性が問題になる必要があります。


まあ、私はあなたの最初の文に完全に同意します。ただし、パフォーマンス要件を正式な方法で明示的に指定しなくても、一部のソフトウェアは「意図したユースケースでは非常に遅くなる」ことがあると確信しています。
Doc Brown

@DocBrown:もちろんですが、遅すぎるかどうかを決めるのは開発者ではなく顧客です。
ジャックB

パフォーマンス要件を明示的に述べているビジネス要件に遭遇したことはありません。
誤り言語学者

@errantlinguist:私の経験では、オンラインショップのような顧客中心のビジネスではかなり一般的です。ただし、企業内で使用するツールとアプリケーションの場合、ユーザーエクスペリエンスは通常、プロジェクトオーナーの懸念事項ではありません。
ジャックB

4

文脈の完全な引用有益であると思います。このトピックについてRedditで作成した投稿からコピーします。

効率の限界が悪用につながることは間違いありません。プログラマーは、プログラムの重要でない部分の速度を考える、または心配するのに膨大な時間を浪費します。これらの効率化の試みは、デバッグと保守を考慮すると、実際に大きな悪影響を及ぼします。私たちは小さな効率を忘れてはいけません。時間の約97%を言ってください:早すぎる最適化はすべての悪の根源です。

しかし、その重要な3%でチャンスを逃してはなりません。優れたプログラマーは、そのような推論によって自己満足に落ち着かないでしょう。重要なコードを注意深く見るのが賢明でしょう。しかし、そのコードが特定された後にのみ。

-Donald Knuth、Go to Statements ACM Computing Surveys、Vol 6、No。4、1974年12月、268ページ

重要なことは、最適化にあまりにも早く注意を向けるよりも、重要なことを心配する必要があるということです。確かに、データ構造とアルゴリズムを慎重に検討する必要があります(これは3%です)が、低レベルの最適化が明らかになるまで、減算がモジュロよりも速いかどうか(これは97%です)を心配する必要はありません。必要。

前者は、同僚が考えているという意味で必ずしも最適化されているわけではありませんが、適切に選択されていないアルゴリズムとデータ構造は最適ではないという意味での最適化です。


2
Knuthは、アルゴリズムの時間的な複雑さを分析し、それに基づいて設計を選択することは時期尚早の最適化であるとは考えていないと明確に付け加えます。
-sdenham

3

私の経験では、この種の最適化への反対を定期的に受けている場合、人々は本当に最適化について文句を言っていません。彼らはあなたが最適化の名において犠牲にしていることについて不平を言っています。これは通常、読みやすさ、保守性、または適時性です。コードが同じ時間で配信され、理解しやすい場合、より効率的なデータ構造とアルゴリズムを使用している場合、人々はそれほど気にすることはできません。この場合の私の提案は、コードをよりエレガントで保守しやすくすることです。

他の人のコードに関してこのような反対を受けているのは、通常、かなりの量の手直しを提案しているためです。そのような場合、努力する価値があることを示すために実際の測定値が本当に必要です。あるいは、コードが書かれる前に、設計段階の早い段階で関与することを試みてください。つまり、3%以内であることを証明する必要があります。正確に私たちが好きな方法ではなかったすべてのコードを書き直した場合、何も達成できませんでした。


残念ながら、実際には反対のケースを実行しました。たとえばDeque、Java標準ライブラリのArrayListaを使用して、コードの作業中にスタックとして使用される大量のロジックを置き換えます。レビューの変更。言い換えると、レビュアーはに詳しくないため、より低速でバグが発生しやすいコードを増やしたいと考えていましたDeque
誤り言語学者

3
あなたの言語で10年もの間何かを学ぼうとしないことは、プログラマーにとって有毒な態度であり、あなたが最初に説明したよりもはるかに深い問題です。個人的には、そのような状況ではアドバイスを拒否し、必要に応じて経営陣にエスカレーションします。
カールビーレフェルト

5
@errantlinguist:レビュアーが明確で単純なソリューションの代わりとして明らかに悪い(より複雑な)ソリューションを提案した場合、それについて議論する必要があります。パフォーマンスについて議論しないでください!真剣に、その議論で「パフォーマンス」という言葉を使わないでください。読みやすさと保守性についてのみ議論します。また、レビュアーが自分の悪いコードを主張している場合は、エスカレーションしてください。
Doc Brown

+1この回答に、賛成票の代わりに下票があり、受け入れられた回答である理由がわかりません。問題を処理する方法と、実際の根本的な問題の分析(つまり、コードを根本的に書き換える必要があることを誰にも伝えたくない)の両方を示唆しています。
アンドレスF.

2

実際、この引用については多くの誤解があります。そのため、実際の問題とは何かを振り返って検討するのが最善です。問題はそれほど多くないため、決して「最適化」しないでください。それは「最適化」があなたがするために着手すべきタスクではないということです。朝目を覚まして、「今日はコードを最適化するべきだ!」と自分に言ってはいけません。

これは無駄な努力につながります。コードを見て、「もっと速くできる!」と言うだけです。そもそも十分な速さで何かを高速化するために多大な努力を必要とします。コードを4倍高速化したと自負するかもしれませんが、そのコードがボタンを押したときに発生する計算であり、人間のユーザーに表示するまでに最初に10ミリ秒かかった場合、いまいましい。

それが「時期尚早な最適化」の「時期尚早」です。「時期尚早」ではないのはいつですか?お客様から「これは非常に遅いので、修正してください!」それは、コードを掘り下げて、それをより速くしようとするときです。

これは、脳をオフにする必要があるという意味ではありません。1つのリンクリストに10,000件の顧客レコードを保持する必要があるという意味ではありません。念頭に置いて行うことのパフォーマンスへの影響を常に理解し、それに応じて行動する必要があります。しかし、アイデアは、あなたがそれをより速くしようと意図的に余分な時間を費やしていないということです。あなたは、他の同等の選択肢からよりパフォーマンスの高い選択肢を選択しているだけです。


これは、脳をオフにする必要があるという意味ではありません。1つのリンクリストに10,000件の顧客レコードを保持する必要があるという意味ではありません。>それについては100%同意しますが、実際にリンクリストがそのように使用されているのを見て、「触れないでください」と言われました。
誤り言語学者

良い情報ではありますが、これは実際にパフォーマンスに関係する瞬間にディスカッションを妨害する人々とどのように働くかという私の質問には答えません。
誤り言語学者

3
悲しいことに、「単一リンクリスト」はランダムな例ではなく、私が個人的に出会ったものです。
ロボットを取得

1

あなたは物事を間違った方法で行うか、物事を正しい方法で行うことができます。

多くの場合、物事は間違った方法で行われ、コードは正しい方法で行われるようにリファクタリングされます。あなたが新しいコードを書くつもりで、大きなペナルティなしで正しい方法で物事ができることを知っているなら、私はちょうどそれを正しい方法でやる側に間違いを犯すでしょう。(パフォーマンステストなどの後、いくつかの変更が必要になる可能性があることに注意してください-しかし、それは大丈夫です。あるいは、完全に素朴な実装はめったに、めったに正しくありません。)

a)将来的に役立つことがわかっている場合、またはb)最適ではないパスが今後の問題につながることを知っている場合、必ずしも時期尚早な最適化とは限りません。まるでチェスゲームのようなものです。

人々は間違ったことをするのではなく、正しいことをしたいと思う傾向があると思います。これは、代替戦略を同僚と議論するときに使用します。


5
「間違った方法」や「正しい方法」はありません。一般に、「私の神、これはどのように実行されますか?」から連続して実行される無限の方法があります。「ジョン・カーマックとドナルド・クヌースはペア・プログラミング中にこれを改善できませんでした」へ。
ロボット

@StevenBurnapこれは本当です。しかし、個人には一般にいくつかの正しい方法と多くの間違った方法があると思います。(私たちがより良いプログラマになると、そのスペクトルは変化し始めます-私たちの新しい正しい方法は古いものよりも良い一方で、古い「正しい方法」は時々私たちの新しい「間違った方法」になるかもしれません。)あなたのために可能な限り最高の、最も正しい方法。これにより、より良いプログラマーになり、より良いチームメイトになり(問題を指導します!)、より良いコードを書くことにつながります。
lunchmeat317

人々は間違ったことをするのではなく、正しいことをしたいと思うだろう」-問題は、何が正しいか間違っているかについて非常に異なる意見があるということです。いくつかは、それについての神聖な戦争さえ開始します(文字通りの意味で)。
JensG

1

これはプログラミングの問題ではなく、通信の問題のようです。人々が自分のやり方を感じる理由を理解し、あなたのやり方がより良いと思う理由を明確にしてみてください。あなたがそれをしたとき、あなたの目標が他の人がなぜ間違っているのか、そしてあなたが正しいのかを他の人に伝えることである対立的な議論を始めないでください。あなたの考えや感情を説明し、人々がそれに反応するようにします。何らかのコンセンサスに達することができず、これが本当に重大な問題であると感じる場合、おそらくチーム全体に重大な問題がいくつかあります。

実際のプログラミングにもっと焦点を合わせ、直感だけが「速い」ということについて長い議論に時間を無駄にしないでください。Webアプリでリクエストごとに1回呼び出されるメソッドを誰かが書いているのを見て、実際にO(log(n))時間の問題であることがわかっているときにO(n ^ 2)時間の複雑さがある場合、簡単なことではありません。

しかし、人間として、私たちのプログラマーは、アプリケーションのどの部分がボトルネックになるのかを推測するのが本当に悪いです(そして、私はAWFULを意味します)。Eric Lippertがこのブログ投稿でこの興味深いテーマについて書いています。常に保守性を優先します。最終的に発見されたパフォーマンスの問題は、詳細情報があれば簡単に(まあ、比較的)修正できます。


答えを編集して、もう少し肉付けしましたが、ダウンボッターはフィードバックを追加できますか?:)
サラ

私はダウンボッターではありませんが、あなたの最初の段落は目前の質問に対処する際にスポットオンですが、残りは実際にパフォーマンスに関係する議論を妨害する人々と働く方法に関する私の質問に答えていません(それでもなお良いアドバイスです)。
誤り言語学者

基本的に、最後の2つの段落で説明したいのは、「これらの最適化は重要ではないかもしれません」です。その場合、あなたの戦いを選ぶ方が良いです。
サラ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.