web-dev-qa-db-ja.com

「時期尚早の最適化がすべての悪の根源である」という誤解にどう対処するか?

私は、単語の一般的な英語の意味で「最適化」と見なすことができるものに対して独断的に反対する多くの人々に遭遇しました。彼らのスタンスの正当化として、彼らが私が話していることは何でも「時期尚早の最適化」であると解釈することを意味します。ただし、これらのビューは、とんでもないほど定着している場合がありますany純粋な「素朴な」実装からのアルゴリズムまたはデータ構造の一種の逸脱...または少なくともそれらの方法からの逸脱以前にやったことがあります。 「パフォーマンス」または「最適化」について聞いてシャットダウンした後、このような人々に再び「耳を開く」ようにさせるにはどうすればよいでしょうか。人々に即座に考えさせることなくパフォーマンスに影響を与える設計/実装のトピックについて話し合うにはどうすればよいですか:「この人は2行を10行のコードに費やしたいのですか?」

ここで、「すべての最適化は時期尚早であり、したがって悪」であるかどうかのスタンスは すでにここでカバーされています および Webの他のコーナー であり、すでに議論されました 最適化が時期尚早で悪であることを認識する方法 しかし、残念ながら、現実世界には反最適化への信仰への挑戦に対してそれほどオープンではない人々がまだいます。

以前の試み

数回、「早期の最適化が悪い」K「すべての最適化が悪い」ことを説明するために、 Donald Knuthからの完全な引用 を指定してみました。

小さな効率については忘れてください。たとえば、97%の時間です。時期尚早な最適化は、すべての悪の根源です。しかし、その重要な3%で機会を逃してはなりません。

ただし、引用全体を提供する場合、これらの人々は実際に、私がしていることがPremature Optimization™であり、調査を拒否して聞くことを拒否していると確信することがあります。それはまるでWordの「最適化」がそれらを怖がらせるようなものです:場合によっては、「optimiz(e | ation)」というWordの使用を単に回避するだけで、拒否されることなく、実際のパフォーマンス向上コードの変更を提案できました(そして「パフォーマンス」-Wordも怖いです)代わりに、「代替アーキテクチャ」や「改良された実装」などの表現を使用します。このため、これは本当に教義主義のようであり、実際に私が言っていることを批判的に評価し、不要または高額であるとして却下するのではありません。

26
errantlinguist

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

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

"単純な実装はO(n³)であり、nは100.000を超えます。これは数日実行されますが、それほど単純ではない実装はO(n)で実行されます。数分しかかかりません」

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

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

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

そしてもちろん、どのパフォーマンスが許容可能か、そしてユーザーの目には「遅すぎる」状態になる時期を十分に理解できるように、要件とユースケースを十分に理解する必要があります。理想的な世界では、顧客から正式なパフォーマンス仕様が得られますが、実際のプロジェクトでは、要求されるパフォーマンスは多くの場合灰色の領域であり、プログラムが本番環境で動作するのが遅いとユーザーが言うだけです。そして、多くの場合、それが何かが遅すぎるときを見つける唯一の有効な方法です。ユーザーのフィードバックであり、Knuthを引用してチームメイトに「単純な実装」では不十分であることを説得する必要はありません。

35
Doc Brown

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

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

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

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

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

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

18
Jon Raynor

パフォーマンスと関係がある分にディスカッションを妨害している人々とどのように連携するのですか?

まず、グループの戦略的方向性に基づいて構築された原則を共有します。

私の原則:

コードの記述に関する私の個人的な原則は、まずプログラムの正確さを目指し、次にそれをプロファイリングして、最適化が必要かどうかを判断することです。他のプログラマーが私のコードの潜在的なコンシューマーであり、遅い場合はそれを使用しないため、私のコードを自分でプロファイリングします。したがって、私のコードでは、速度が特徴です。

消費者が顧客である場合、より高速なコードが必要かどうかは顧客からわかります。

ただし、コードには既知の明らかに優れた選択肢がいくつかあります。いくつかの理由により、私は最初のドラフトでそれを正しくしたいと思います。

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

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

これが最適化を必要とするコードの本当に重要な部分であると仮定すると、 Schlemiel the Painter のたとえを伝えるか、引用符の残りの部分を強調できます。

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

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

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

リーダーシップ

時々問題は自我です-他の人が自分より正しい人よりも、次善またはバグのあるコードを使用したい人もいます。あなたはおそらくこれらの人々と一緒に働くことを避けたいでしょう。

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

7
Aaron Hall

今後の方法は、実際の引用とさまざまな解釈を忘れることです。それは、どちらか一方の方法で、グルによる特定の引用にそれほど焦点を当てることです。とにかく、Knuthは常に正しいと誰が言うのでしょうか。

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

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

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

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

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

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

6
JacquesB

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

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

それでも、その重要な3%で機会を逃してはなりません。優れたプログラマーは、そのような推論によって自己満足に陥ることはなく、彼は賢明です重要なコードを注意深く見てください。しかし、そのコードが識別された後にのみ。

-Donald Knuth、 go to Statements ACM Computing Surveys、Vol 6、No. 4、Dec. 1974年、268ページ

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

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

4
greyfade

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

他の人のコードに関してこの種の反対を受けている場合、それは通常、かなりの量のやり直しを提案しているためです。このような場合は、実際に測定して、それが価値があることを示す必要があるか、コードを書く前の設計段階の早い段階で関与するようにしてください。つまり、3%であることを証明する必要があります。自分の好みに合っていないすべてのコードを書き直した場合、達成できることはありません。

3
Karl Bielefeldt

確かに、この引用については多くの誤解があるので、一歩下がって実際の問題が何であるかを確認するのが最善です。問題はそれほど多くはないので、「最適化」してはいけません。 「最適化」は、実行すべき作業ではないということです。朝起きてはならず、「今日はコードを最適化するべきだ!」.

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

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

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

2
Gort the Robot

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

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

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

1
sara

物事を間違った方法で行うことも、正しい方法で行うこともできます。

多くの場合、物事は間違った方法で行われ、コードは正しい方法で行われるようにリファクタリングされます。新しいコードを書くつもりで、大きなペナルティなしに正しい方法で物事を実行できることがわかっている場合、私はそれを正しい方法で行うことを誤っています。 (パフォーマンステストなどの後、変更が必要になる場合がありますが、それでも問題ありません。あるいは、完全にナイーブな実装が行われることはめったにありません)。

A)それが将来的に役立つことを知っている場合、またはb)次善のパスが将来問題につながることを知っている場合、それは必ずしも時期尚早な最適化ではありません。本当にチェスゲームのようなものです。

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

1
lunchmeat317