シンプルvs複雑な(ただしパフォーマンスは効率的)ソリューション-どちらを選択するか?


28

私は数年前からプログラミングをしていて、ジレンマに陥っていることがよくあります。

2つの解決策があります-

  • 一つはシンプルなもの、すなわちシンプルなアプローチであり、理解と保守が容易です。冗長性、余分な作業(余分なIO、余分な処理)が含まれるため、最適なソリューションではありません。
  • しかし、他は複雑なアプローチを使用し、実装が難しく、多くのモジュール間の相互作用を伴うことが多く、パフォーマンス効率の高いソリューションです。

達成するのに難しいパフォーマンスSLAがなく、シンプルなソリューションでさえパフォーマンスSLAを満たすことができる場合、どのソリューションに取り組むべきですか?簡単な解決策については、仲間の開発者の間で軽disを感じています。

シンプルなソリューションでパフォーマンスSLAを満たすことができる場合、最も最適な複雑なソリューションを考え出すのは良い習慣ですか?


10
参照:「開発者の不適切な最適化の直感」を回避するにはどうすればよいですか?「残念ながら、開発者は一般的に持っている恐ろしい直感 ....アプリケーションにおけるパフォーマンスの問題が実際にされる場所については、」
ブヨ

1
「最適ではない」ことはまだ「十分」です。それからそれととどまりなさい。

8
うん。「ル・ミエ・エスト・レンヌミ・デュ・ビエン。」ヴォルテール。(「完璧は善の敵です。」)十分なことは十分です-パフォーマンステストでそうでないと言われるまで。
デビッドハンメン

(一般に)単純なことは効率的であることを意味します。したがって、多くの場合、妥協する必要はありません。
ダン

2
「これ以上追加するものがないときではなく、削除するものがないときに完全性が達成されるようです。」-アントワーヌドサンテグジュペリ
-keuleJ

回答:


58

達成するのに難しいパフォーマンスSLAがなく、シンプルなソリューションでさえパフォーマンスSLAを満たすことができる場合、どのソリューションに取り組むべきですか?

シンプルなもの。仕様を満たし、理解しやすく、保守しやすく、おそらくバグが大幅に少なくなります。

パフォーマンス効率の良いソリューションを提唱するためにあなたがしていることは、投機的な一般性と時期尚早な最適化をコードに導入することです。しないでください!パフォーマンスは、他のほぼすべてのソフトウェアエンジニアリング '信頼性'(信頼性、保守性、可読性、テスト容易性、理解可能性など)の粒度に反します。テスト時のパフォーマンスの追跡は、パフォーマンスを追跡する必要があることを示しています。

パフォーマンスが重要でない場合は、パフォーマンスを追跡しないでください。重要であっても、パフォーマンスのボトルネックが存在することがテストで示されている領域でのみパフォーマンスを追跡する必要があります。simple_but_slow_method_to_do_X()その単純なバージョンがボトルネックとして表示されない場合、パフォーマンスの問題を高速バージョンに置き換える言い訳にしないでください。

強化されたパフォーマンスは、多くのコードのにおいの問題でほぼ必然的に妨げられます。あなたは質問でいくつかに言及しました:複雑なアプローチ、実装が難しく、より高い結合。これらは本当に引き込む価値がありますか?


あなたの答えは非常に役立ちます
-MoveFast

1
できるだけ単純ですが、単純ではありません。可能な限り高速ですが、高速ではありません。など
-user606723

2
「疑わしいときは、ブルートフォースを使用してください」;)
tdammers

コード内のコメントは、ここではカタルシス的で役立つ場合があります。複雑で高速なソリューションとそれを使用しなかった理由を指摘する小さなコメントは、最適なアルゴリズムを無視したように感じさせないようにします。また、後で最適化が実際に必要になった場合、メンテナーが選択を理解し、正しい方向に向けるのに役立ちます。
TheAtomicOption

12

短い答え:複雑なものよりも単純な解決策を優先しKISSとYAGNIの原則を覚えておいてください

プロジェクトの初期要件とソフトウェアは完璧ではないため、アプリケーションの開発/使用に合わせて変更する必要があります。開発フェーズでの反復アプローチは、物事をシンプルに開始し、必要に応じて拡張するのに非常に適しています。最も単純なソリューションには、柔軟性の余地があり、メンテナンスがより簡単です。

さらに、スマートになり、アプリケーションを構築しながらアドホックな最適化を行うことは良い習慣ではなく、ソリューションが過度に複雑になる可能性があります。知られているように"premature optimization is the root of all evil"-クヌースの本から


1
@ManojGumber、問題はありません。プログラマーとして私たちが第一に気をつけなければならないことの本質です。
ELユスボフ

8

ここでKnuthから教訓を得てください:「私たちは小さな効率を忘れて、時間の約97%を言うべきです:早すぎる最適化はすべての悪の根源です」

ソリューションを次の順序で考えてください。まず、常に正しいこと。第二に、明快さとシンプルさを改善します。第三に、必要性、効率性を実証できる場合のみ。

効率を上げると、ほとんどの場合重要な何かがかかるので、必要があるとわかっている場合にのみ追求する必要があります。


4
これは、そもそも良い実装を書くべきではないという意味ではないことに注意してください。

@ThorbjørnRavnAndersen:もちろん、それが最初の2つのポイントについてです。
サイモン

1
@simon引用は、

2番目のポイントについて:正しいスパゲッティの前に、正しく構造化されていないクリーンなコードを好むと頻繁に言っていた同僚がいました。
-Buhb

@ThorbjørnRavnAndersen無能な人は言い訳に何でも使うでしょう。元の思考の価値に影響を与えません。
サイモン

7

シンプルさが信頼性の前提条件です。動作するシンプルなソリューションがあれば、ぜひ行ってください!最適化されたプログラムを機能させるよりも、動作中のプログラムを最適化する方がはるかに簡単です。また、ムーアの法則についても忘れないでください。単純なソリューションが今日のパフォーマンス目標を達成する場合、おそらく1年か2年でそれらを破壊するでしょう。


1 ジミー・ホファが以下のコメントで指摘したように、ムーアの法則には限界があるため、そこには保証がありません。


あなたは、ムーアの他の法律、「おっと、私の最初の法律について」を忘れていました。ごめんなさい、ムーアの法律はもうありません(しゃれ)。あなたの主張の残りの部分には同意しません。少なくとも最後の部分はそこに注意してください。
ジミー・ホッファ

2
申し訳ありませんが、この業界での私のすべての経験において。「ワークセット」は、一貫してアップグレードされるハードウェアの速度よりも速くFARを増やしています。本当に、ムーアの法則のポイントを削除するだけです。
user606723

@ user606723「作業セット」ポイントの増加は、「最適化されたまたは単純な」質問に直交します。実装するソリューションに関係なく、ワークロードはそれらに追いつきます。ムーアの法則をミックスに取り入れるポイントは、執筆時点で単純なソリューションが何らかのパフォーマンスのプレッシャーにさらされていても、より高速なハードウェアが利用可能になるとプレッシャーが減少することを指摘することでした。
-dasblinkenlight

@dasblinkenlight、ワークセットの成長は、ムーアの法則ほど問題に直交していません。ワークセットを問題に持ち込むポイントは、単純なソリューションがリリース時にパフォーマンスのプレッシャーにさらされている場合、ワークセットの増加によりハードウェアの改善によって達成されたパフォーマンスの改善が失われるため、パフォーマンスは非常に近い将来不十分になります。私はシンプルで、信頼性が高く、保守可能なソフトウェアを求めていますが、リリース時にすでにパフォーマンスのプレッシャーにさらされているソフトウェアをリリースし、ムーアの法則もそれを期待するのは恐ろしい哲学です。
user606723

3

シンプルなソリューションでパフォーマンスSLAを満たすことができる場合、最も最適な複雑なソリューションを考え出すのは良い習慣ですか?

最適とは曖昧な言葉です!

最終的に、複雑なものを維持しなければならない場合に多くのリスクがあり、単純なものが「十分」である場合、私は常に単純なものの側で間違いを犯します。

複雑なものが十分ではないというリスクを加えると、おそらくKISSが正解です。


2

シンプルな方がいいです。私の意見では、時期尚早な最適化は解決するのと同じくらい多くの問題を引き起こします。多くの場合、優れた設計により、特定の実装がボトルネックになった場合、将来的に実装を変更できます。

結論としては、できるだけ柔軟に設計しますが、柔軟性のために単純さを犠牲にすることはしません。


2

どっちが安い?

ほとんどの場合、わずかに遅いシンプルなソリューションはパフォーマンスの点で完全に受け入れられ、シンプルさは開発、保守、そして最終的に交換するのに安価になります。

一方、速度が非常に重要な場合もあり、わずかな速度の改善で得られる経済的利益は、より複雑なソリューションのコスト増加よりもはるかに大きくなる可能性があります。たとえば、トランザクションを完了するまでの時間を0.01秒短縮すると、証券取引システムの収益性が大幅に向上します。数百万のユーザーをサポートするシステムの効率が10%向上すると、サーバーコストが大幅に削減される可能性があります。

ですから、あなたが自問しなければならない質問は次のとおりです。複雑なソリューションを使用することは、最終的なラインに追加コストを支払うのに十分な影響を与えるか 実際には、請求書を支払い、潜在的な利益を享受しているので、クライアントに決定を依頼する必要があります。1つの良い選択肢は、最初に単純なソリューションを使用し、改善策としてより複雑なソリューションを提供することです。それにより、システムを稼働させ、クライアントにテストを開始するための何かを与えることができます。その経験は、より複雑なソリューションを実装する(または実装しない)決定に役立つ場合があります。


2

2つのアプローチを評価する場合、1つはよりシンプルだが効率が低く、もう1つはより複雑でより効率的である場合、問題とプロジェクトドメインを考慮する必要があります。

ヘルスケア業界向けの数十億のソフトウェアプロジェクトについて考えてみましょう。このプロジェクトでは、15年以上のメンテナンスと20年以上の使用期間を計画しています。このようなプロジェクトでは、パフォーマンスが問題になることはありませんが、プロジェクトの複雑さと構造は、プロジェクトのメンテナンスに大きな問題を引き起こす可能性があり、それは少なくとも15年間続きます。保守性とシンプルさが何よりも優先されます。

次に、別の例を考えます。今後5年以上にわたり、同社の今後のゲームを強化することになっているコンソールゲームエンジン。ゲームは非常にリソースに制約のあるプログラムであるため、多くの場合、保守性よりも効率性が優先されます。特定のタスクのために独自の非常に具体的なデータ構造とアルゴリズムを記述することは、ソフトウェア開発の「ベストプラクティス」に反する場合でも非常に重要です。これの良い例は、実際のオブジェクトではなく、同様のデータ配列にデータを保存するデータ指向設計です。これは、局所性の参照を増やし、CPUキャッシュの効率を高めるためです。実用的ではありませんが、特定のドメインでは非常に重要です。


1

これは常に難しい質問であり、答えが一方向に揺れるのを見るので、反対側のゲームをプレイしますが、どちらの答えも正しいとは言いませんが、非常にソフトでケースバイケースのトピックです。

複雑でありながら高性能なソリューションについての1つのことは、いつでもそれを記録することができるということです。私は一般的に自己文書化コードのファンですが、私はそれが私を遅くしないように感じさせる時間内に応答するソフトウェアのファンでもあります。複雑だが高性能なソリューションを使用する場合は、それほど悪くないようにするためにできることを検討してください。

それをインターフェースでラップし、それ自身でアセンブリに入れ、場合によってはすべてのプロセスに入れてください。漏れを防ぐために、できるだけ厚い抽象壁でできるだけ疎結合にしてください。将来のリグレッションを防ぐために、多数の単体テストを作成してください。

それをコードで文書化し、実際の文書を書くことを検討してください。複雑なデータ構造とそれらがどのように文書化されているかを考え、それを説明するデータ構造の本/ウィキペディアの記事なしで、コードからそれらの実装を理解しようとすることを想像してください。しかし、これらの複雑なデータ構造は実際には良いものであり、誰かが私たちの言語でそれらを実装することは有益です。

誰もがTCP / IPスタックでメッセージを送信していることを忘れないでください。コードを見ると、コードが取得する可能性があります。おそらくあなたの問題はこのレベルの最適化を必要としないかもしれませんが、おそらく必要としますが、私たち全員が時々しなければならないので、この質問に取り組むときは注意してください。


0

私は、パフォーマンスSLAがない分野でこの作業に参加しています。コンピューターグラフィックスのオフラインレンダラーに関しては、ユーザーに「満足のいくパフォーマンス」はありません。なぜなら、最先端のレンダラーでもクラウドにコンピューティングを分散し、ファームをレンダリングするために莫大な金額を既に投入しているからです。フィルムの生産品質の画像とフレームを出力します。例えば

しかし、このドメインで長年働いている人として、効率を優先して保守性を大幅に低下させるソリューションは、常に変化するパフォーマンス要件に実際に取り組んでいると言わなければなりません。周囲のコードと競合他社がお互いに優れていることを期待するユーザーの両方の観点で、物事が足元で変化しているため、今後何年もソリューションを効果的に維持できない場合、ソリューションはすでに廃止され、卸売りの交換が必要です。

VTuneのようなプロファイラーの究極の目的は、コードをより高速に実行する方法とは思いません。彼らの究極の価値は、増大するパフォーマンス要求に対応するために生産性を低下させないことです。私は絶対にし、いくつかグロス探してマイクロ最適化、プロファイラを適用する必要がある場合は、(私が想像するいくつかのテストケースではなく、現実世界のユーザ事例に対してそれを実行していると組み合わせる可能性が重要である)を、私は適用を確実にするように、必然的に総-探し最適化は、非常に慎重に表示される上位のホットスポットのみに加えて、非常に慎重に文書化するだけでなく、ソリューションが実行可能であれば、今後数年間はそれらを再検討し、維持し、微調整して変更する必要があるためです

特に、最適化されたソリューションがより多くのカップリングを伴う場合、私はそれを使用することを本当に嫌がります。コードベースの最もパフォーマンスが重要な分野で私が評価する最も価値のあるメトリックの中には、デカップリングがあります(動作する必要がある情報量を最小限に抑えるなど、変更を直接必要としない限り、変更を必要とする可能性を最小限に抑えるなど) )、これらの重要な領域は、物事が変化する理由を大幅に増やすからです。つまり、作業に必要な情報が少ないほど、変更の理由が少なくなり、変更の理由を最小限に抑えることは、とにかく絶えず変化する必要があるため、特定の焦点領域で生産性を向上させるための大きな部分ですそれ以外の場合は1年で廃止されます)、

私にとって最大かつ最も効果的なソリューションは、効率と保守性、生産性が互いに正反対にならないソリューションです。私の探求は、これらの概念をできる限り調和のとれたものにすることです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.