あなたが見た中で最もばかげた悲観論は何ですか?[閉まっている]


145

早すぎる最適化はすべての悪の根源であることは誰もが知っています。さらに悪いのは悲観化です。誰かが「最適化」を実装すると、それはより高速になると考えられますが、遅くなり、バグが多く、メンテナンスが困難になります。 ?


21
「悲観化」は素晴らしい言葉です。
mqp 2009年

あなたが知らなかった場合に備えて、彼らはここで最新のポッドキャストであなたのスレッドについて話しました。
mmcdole 2009年

回答:


81

古いプロジェクトでは、Z-8000の経験が豊富な(そうでない場合は優れた)組み込みシステムプログラマーを何人か引き継ぎました。

新しい環境は32ビットのSparc Solarisでした。

RAMから16ビットを取得する方が32ビットを取得するよりも高速だったので、1人が行って、コードを高速化するためにすべてのintをshortに変更しました。

私は、32ビットシステムで32ビット値を取得する方が16ビット値を取得するよりも高速であることを示し、CPUが16ビット値を取得するには32ビット幅にする必要があることを説明するデモプログラムを作成する必要がありました。メモリアクセスし、16ビット値に不要なビットをマスクまたはシフトします。


16
ねえ、あなたはあなたの数学をどこで学びましたか?1つのキャッシュ/ RAMアクセスを持つ2つの命令は、1つのキャッシュ/ RAMアクセスを持つ1つの命令よりも明らかに高速です!
Razor Storm

2
@RazorStorm帯域幅とキャッシュがより貴重である最近のマシンでは、その逆になります。ビットマスク/シフトは安価ですが、キャッシュにできるだけ多く収め、帯域幅を最小限にしたいとします。
2013

206

私は、「時期尚早な最適化はすべての悪の根源である」という言い回しは、ずっと使われている方法だと思います。多くのプロジェクトでは、プロジェクトの後半までパフォーマンスを考慮しないことが言い訳になっています。

多くの場合、このフレーズは仕事を避けるための松葉杖です。この言葉は、「ああ、私たちは前もってそのことを本当に考えていなかったし、今はそれに対処する時間がない」と言うときに使われるのを見ています。

「悲観化」が原因で発生する問題の例よりも、ダムのパフォーマンス問題の「とんでもない」例の方がはるかに多い

  • プログラムの起動中に同じレジストリキーを数千回(または数千回)読み取る。
  • 同じDLLを数百または数千回ロードする
  • ファイルへのフルパスを不必要に保持することにより、メガバイトのメモリを浪費する
  • データ構造を整理しないため、必要以上に多くのメモリを消費する
  • MAX_PATHへのファイル名またはパスを格納するすべての文字列のサイズ
  • イベント、コールバック、またはその他の通知メカニズムがあるものに対する不必要なポーリング

私がより良い発言だと思うのは、「測定も理解もしない最適化は、最適化ではありません-ただのランダムな変化」です。

優れたパフォーマンス作業には時間がかかります。多くの場合、機能またはコンポーネント自体の開発に時間がかかります。


46
「時期尚早」がその引用のキーワードです。「測定して理解せずに最適化する」と言い換えても、意味が少し変わったようには見えません。それが正確にKnuthが意味したことです。
リザードを請求する

13
@Foredecker:その通り。あまりにも多くの人々がコンテキストを忘れており、そのため、その引用はミクロの最適化に固く反対しています。問題を分析して実装する前に適切なアルゴリズムを選択するのは時期尚早ではありませんが、そのような引用句がスローされて、最も怠惰で最も非効率的なソリューションを正当化することがよくあります。
Shog9 2008年

5
それは実際には個々のケースに依存します。不十分な最適化計画が問題になるよりも、時期尚早の最適化が問題になるケースの方が多いです
マークロジャース

12
-1:「最適化」と適切な設計には違いがあります。わからない人にとっては、「最適化」を行うとコードの読み取りは難しくなりますが、より速くまたはより効率的になります。優れた設計により、コードが読みやすくなり(少なくとも悪くなることはありません)効率が向上します。
TED

5
それが過度に使用されている場合、SOについて質問する人口は異常値に大きく重み付けされます。:D
dkretz 2009年

114

データベースは悲観化の遊び場です。

お気に入りは次のとおりです。

  • テーブルが「大きすぎる」ため、テーブルを複数に分割します(日付範囲、アルファベット順など)。
  • リタイアしたレコードのアーカイブテーブルを作成しますが、本番テーブルとのUNIONを続行します。
  • (部門/顧客/製品/など)によってデータベース全体を複製します
  • インデックスが大きすぎるため、インデックスに列を追加しないでください。
  • 生データからの再計算が遅すぎるため、多数のサマリーテーブルを作成します。
  • スペースを節約するために、サブフィールドを持つ列を作成します。
  • 配列としてのフィールドに非正規化します。

それは私の頭の上からです。


索引付けの必要性に抵抗することは、考えるのが大変です。
トカゲに請求する

2
はい、アメリカの大手石油会社で働いている人がいます。ほとんどすべてのテーブルに関連付けられたアーカイブテーブルがあり、ほとんどのクエリはテーブルのペアをUNIONするビューから選択します。パフォーマンスは期待通りです!
トニーアンドリュース

ああ、私はすべてのDBAがどこかの時点でアーカイブテーブルルートとの結合を解除したに違いないと思います。その時はいつもとても合理的に思えます。
クルアチャン

3
追加:データベースをいくつかの異なるデータベース(顧客ac、顧客dfなど)に分割します
Gabriele D'Antona

「配列としてのフィールドの非正規化」について詳しく教えてください。ここでどういう意味ですか?
Bart van Heukelom、2011

87

絶対的なルールはないと思います。最初に最適化されるものとそうでないものがあります。

たとえば、衛星からデータパケットを受信する会社で働いていました。各パケットは多額の費用がかかるため、すべてのデータは高度に最適化されました(つまり、パックされました)。たとえば、緯度/経度は絶対値(浮動小数点数)ではなく、「現在の」ゾーンの「北西」のコーナーに対するオフセットとして送信されました。使用する前にすべてのデータを解凍する必要がありました。しかし、これは悲観化ではなく、通信コストを削減するためのインテリジェントな最適化だと思います。

一方、ソフトウェアアーキテクトは、展開されたデータを非常に読みやすいXMLドキュメントにフォーマットし、データベースに保存することを決定しました(対応する列に各フィールドを保存するのではなく)。彼らの考えは、「XMLが未来」、「ディスク容量が安い」、「プロセッサが安い」ので、何も最適化する必要はありませんでした。その結果、16バイトのパケットが1つの列に格納された2kBのドキュメントに変換され、単純なクエリでさえ、メガバイトのXMLドキュメントをメモリにロードする必要がありました。毎秒50パケット以上を受信したので、パフォーマンスがどれほどひどいか想像できます(ところで、会社は倒産しました)。

繰り返しになりますが、絶対的なルールはありません。はい、最適化が早すぎることは間違いです。しかし、「cpu /ディスクスペース/メモリは安い」というモットーがすべての悪の本当のルーツである場合もあります。


37
「cpu /ディスクスペース/メモリは安い」がすべての悪の本当の根であることに同意します。+1
ksuralta 2009年

5
XMLドライブルも聞いたことがあります。別の戦車中の会社。
n8wrl 2009年

19
@ksuralta:「Cpu /ディスクスペース/メモリは安い」は考えを避けるのに便利な言い訳です。思考を避けることは、すべての悪の架空の根です。
Piskvorが建物を去る

このXML化は私の職場でも起こり、JSON化が続きました。「面倒な」リレーショナルデータベースの設計を回避するためにすべて。
Tanz87 2017年

75

良い主よ、私はそれらすべてを見てきました。多くの場合、怠惰すぎてパフォーマンスの問題の原因を突き止めたり、実際にパフォーマンスの問題があるかどうかを調査したりできない、だれかがパフォーマンスの問題を修正するための努力です。これらの多くのケースでは、特定のテクノロジーを試してみて、必死に彼らの光沢のある新しいハンマーに合う釘を探しているその人のケースではないのではないかと思います。

ここに最近の例があります:

データアーキテクトが、かなり大規模で複雑なアプリケーションのキーテーブルを垂直に分割するという手の込んだ提案を思い付きました。彼は、変化に対応するためにどのような開発努力が必要かを知りたいと思っています。会話は次のようになりました:

私:なぜこれを検討しているのですか?解決しようとしている問題は何ですか?

彼:テーブルXは幅が広すぎます。パフォーマンス上の理由から分割しています。

私:それが広すぎると思うのはなぜですか?

彼:コンサルタントは、1つのテーブルに含めるには列が多すぎると言いました。

私:これはパフォーマンスに影響を与えていますか?

彼:はい、ユーザーはアプリケーションのXYZモジュールで断続的な速度低下を報告しています。

私:テーブルの幅が問題の原因であることをどうやって知っていますか?

彼:これはXYZモジュールで使用されるキーテーブルで、200列のようなものです。それは問題だろう。

私(説明):ただし、特にモジュールXYZはそのテーブルのほとんどの列を使用し、ユーザーがそのテーブルから表示するデータを表示するようにアプリを構成しているため、モジュールが使用する列は予測できません。いずれにしても、95%の時間ですべてのテーブルを結合し直すことになりパフォーマンスが低下する可能性があります。

彼:コンサルタントは幅が広すぎるため、変更する必要があると述べました。

私:このコンサルタントは誰ですか?私たちがコンサルタントを雇ったことも知らなかったし、彼らが開発チームに話しかけたこともまったくなかった。

彼:ええ、まだ採用していません。これは彼らが提案した提案の一部ですが、このデータベースを再構築する必要があると彼らは主張しました。

私:ええと。したがって、データベースの再設計サービスを販売するコンサルタントは、データベースの再設計が必要だと考えています。

会話はこのように続いた。その後、問題のテーブルをもう一度調べて、エキゾチックなパーティショニング戦略を必要とせずに、単純な正規化で狭めることができると判断しました。もちろん、これは(以前は報告されていなかった)パフォーマンスの問題を調査し、それらを2つの要因にまで追跡すると、問題になる可能性があることが判明しました。

  1. いくつかのキー列のインデックスがありません。
  2. MSAccessを使用して直接運用データベースにクエリを実行することにより、キーテーブル(「広すぎる」ものを含む)を定期的にロックしていた少数の不正データアナリスト。

もちろん、アーキテクトは依然として、「幅が広すぎる」メタ問題にぶら下がっているテーブルの垂直分割を要求しています。アプリを見たりパフォーマンス分析を実行したりせずにデータベースの大幅な設計変更が必要であると判断できる別のデータベースコンサルタントから提案を得て、彼のケースをさらに強化しました。


製品へのAaag MSAccess。数分ごとにすべてのアクセス接続をドロップする手順を記述しました。tpは最終的に、それが不良であるというメッセージを受け取りました。
Nat

1
私たちにも同じような仕事がありましたが、それは廃れてしまいました。公平に言うと、Accessは問題ではなく、新参者が非永続的なクエリを簡単に作成/実行できるようにするだけです。
JohnFx 2009年

当社では、本番データベースへのレガシーアドホックアクセス接続に依存しています。カジュアルなSQLの何人かがWHERE句を忘れてメインテーブルをデッドロックするようなものはありません。
HardCode 2009年

35
藤色が

もっとひどかったかもしれない。Excelクエリエディターを使用すると、データベース全体がロックされます。それについて知らなかったときは、別の作業をしている間、そのインスタンスを1日開いたままにしておきました。最悪の部分は、MS SQL Serverがロックを行っていた正しいユーザー名/マシンを報告しなかったことです。数時間後、ロックされているテーブルがクエリを実行しているビューの一部であり、他のすべてを最初にチェックしたため、ロックの理由であることがわかりました。
EstebanKüber10年

58

私は、alphadrive-7を使用してCHX-LTを完全に培養する人々を見てきました。これは一般的ではありません。より一般的な方法は、ZTトランスフォーマーを初期化してバッファリングを減らし(正味の過負荷抵抗が大きくなるため)、Javaスタイルのバイトグラフィックを作成することです。

全く悲観的!


10
多分彼らはフラックスコンデンサーをembiggenしようとしていた
Mikeage 2009年

6
つまり、基本的に含まれる唯一の新しい原理は、導体と磁束の相対運動によって電力が生成される代わりに、磁気リラクタンスと容量性デュラクタンスのモード相互作用によって生成されるということですか?
マットRogish 2009年

17
+1とにかく私のモニターはとにかく掃除が必要だったので;-)
RBerteig 2009年

1
くそー!!しかし、eclectromagentic-cross-genetic effectについてはどうでしょう。それも考慮に入れるべきだと思います。または、被験者はゾンビに変身する場合があります。
スラジュチャンドラン

1
3つの言葉:「クロムマフラーベアリング」
Allbite 2010年

53

驚異的なことは何もないと私は認めますが、StringBufferを使用してJavaのループの外で文字列を連結する人々を見つけました。回転のようなシンプルなものでした

String msg = "Count = " + count + " of " + total + ".";

StringBuffer sb = new StringBuffer("Count = ");
sb.append(count);
sb.append(" of ");
sb.append(total);
sb.append(".");
String msg = sb.toString();

かなり高速だったため、この手法をループで使用することは非常に一般的でした。実は、StringBufferは同期されているため、いくつかの文字列を連結するだけの場合、実際には余分なオーバーヘッドが生じます。(言うまでもなく、違いはこのスケールでは取るに足らないものです。)このプラクティスに関する他の2つのポイント:

  1. StringBuilderは非同期であるため、コードを複数のスレッドから呼び出すことができない場合は、StringBufferよりも優先する必要があります。
  2. 現代のJavaコンパイラーは、とにかく適切な場合に、読み取り可能な文字列連結を最適化されたバイトコードに変換します。

3
まず、なぜJava 5以上を使用しないのですか?第二:はい、できます。最初の例では5まで数えることができるが、2番目の例では数えられないのはどうしてですか?最初と同じ文字列リテラルを使用します。読み取り可能なコードを記述し、コンパイラーにStringBufferをいつ使用するかを決定させます。
トカゲに請求する

4
@ MetroidFan2002:2番目の例の文字列リテラルもオブジェクトです。答えで述べたように、このスケールでは違いは取るに足らないものです。
リザードを請求する

1
これは、各文字列を独自のStringBufferで置き換えることを意味するものではありません。コンパイラーが実行する最適化により、作成されるオブジェクトの数が減少します。
リザードを請求する

3
@Eric:文字列msg = "Count =" + count + "of" + total + "。"; 多くの場合、JavaでStringにコンパイルされますmsg = new StringBuffer()。append( "Count")。append(count).append( "of").append(total).append( "。")。toString(); ...これは正確に2番目の例が行うことです。
Grant Wagner

3
ワグナー氏は、コンパイラではなく、これらすべてのメソッド呼び出しを確認する必要があるということです。それらを書いて、後で理解する必要があります。コンパイラはとにかく同じことを行います。したがって、この場合は読みやすさがより重要になります。
ypnos 2009年

47

「ルート」テーブルを使用するMSSQLデータベースを見たことがあります。ルートテーブルには、GUID(uniqueidentifier)、ID(int)、LastModDate(datetime)、およびCreateDate(datetime)の4つの列がありました。データベース内のすべてのテーブルは、ルートテーブルに対して外部キーが設定されていました。データベース内の任意のテーブルに新しい行が作成されたときは常に、(データベースがジョブを実行するのではなく)関心のある実際のテーブルに到達する前に、ルートテーブルにエントリを挿入するためにいくつかのストアドプロシージャを使用する必要がありましたいくつかのトリガーを持つ単純なトリガー)。

これは役に立たない傍聴と頭痛の混乱を引き起こし、sprocsを使用するためにその上に何かを書く必要がありました(そして会社にLINQを導入するという私の希望を排除しました。それがすることになっていたことを達成する。

このパスを選択した開発者は、テーブル自体にGUIDを使用しなかったため、これにより大量のスペースが節約されるという前提でそれを守りました(ただし、作成するすべての行のGUIDがルートテーブルで生成されていないのですか?) 、何らかの形でパフォーマンスが向上し、データベースへの変更を「簡単に」監査できるようになりました。

ああ、データベースダイアグラムは地獄からの変異スパイダーのように見えました。


42

POBIはどうですか-意図的に明らかに悲観化しますか?

90年代の私の同僚は、CEOがすべてのERPソフトウェア(カスタムリリース)のリリースの最初の日を新しい機能のパフォーマンスの問題の特定に費やしたという理由だけで、CEOに尻を蹴られることにうんざりしていました。新しい機能がギガバイトを使い果たし、不可能を可能にしたとしても、彼は常にいくつかの詳細、または一見大きな問題でさえも、不平を言うことに気づきました。彼はプログラミングについて多くのことを知っていると信じていて、プログラマーのお尻を蹴ることによって彼のキックを得ました。

批判の無能な性質(彼はITの人ではなくCEOであった)のために、私の同僚はそれを正しく理解することができませんでした。パフォーマンスの問題がない場合、それを排除することはできません...

1つのリリースまで、彼は多くの遅延(200)関数呼び出し(それはDelphiでした)を新しいコードに入れました。稼働開始からわずか20分後、彼はCEOのオフィスに出て、期限切れの侮辱を直接受け取るように命じられました。

これまでの唯一の珍しいことは、彼が戻って、笑顔で、冗談を言って、BigMacや2人でBigMacに出かけたとき、彼が通常テーブルを蹴り、CEOと会社について怒鳴り、その日の残りの時間を費やして死んだときの私の同僚のミュートでした。

当然のことながら、私の同僚は今や彼の机で1〜2日間休憩し、Quakeでの照準スキルを向上させました。2日目または3日目に、Delayコールを削除し、再構築して「緊急パッチ」をリリースしました。彼がパフォーマンスの穴を修正するために2日と1泊を費やしたこと。

これは、邪悪なCEOが「素晴らしい仕事だ!」と言ったのは初めて(かつ唯一)でした。彼に。それだけが重要ですよね?

これは本物のPOBIでした。

しかし、これは一種のソーシャルプロセスの最適化でもあるので、100%OKです。

おもう。


10
「Lite」が毎秒数データセット、「スーパーデュッパー」バージョンを数千しか処理できないさまざまなレベルで販売されたデータ処理アプリについて書いた人を覚えています。ソースコードの唯一の違いは、Sleep(N)です。
peterchen 2010

1
鮮やかさ!そのような状況では、その標準をお勧めします。開発の最初に、メモリの大きなチャンクを割り当て、いくつかのスリープコールを追加します。パフォーマンスを確認する必要があるときはいつでも、それらを削減します。それは奇跡の労働者であると呼ばれています;)
RCIX 10/07/28

残念ながら、スリープをNOPにパッチするのは簡単なので、ライトバージョンは非常に簡単にクラックできます。この「最適化」予約では、デバッグとパッチの適用を困難にするために実行可能なパッカーが必要になる場合があります。
TheBlastOne

32

「データベースの独立性」。これは、ストアドプロシージャ、トリガーなどがなく、外部キーも含まれないことを意味します。


8
この「独立性」は、データベースをはるかに上回っており、データが何であるかを忘れているという意味ですか?「移行の苦痛を回避するために」データベースを不必要に抽象化することは非常に不愉快です。あなたはそれを必要としないでしょう。
Rob

8
かなり。職場での建築宇宙飛行士。私はWebが登場して以来、Webアプリを構築してきましたが、その間、実際にdbプラットフォームから別のプラットフォームに移動したことはありません。
クリス

5
私はそれが起こると確信していますが、その可能性に基づいてアーキテクチャを設計する場合、ばか者であることは十分にまれです。
クリス

6
ハーポ、それは別の状況です-それはその場合の要件です。私はそれが要件ではないときについて話しているが、AAはある時点で「あるかもしれない」と判断する。
クリス

3
@すべて:DBの独立にはコストがかかる可能性がありますが、私たちの製品は、DBベンダーが入札によって選択されている環境で実行されており、基本的に一緒にプレイする必要があります。一部の開発者は、垂直統合されたソフトウェアスタックの贅沢を手に入れず、それにもかかわらずそれを行わなければなりません。
Chris R

31
var stringBuilder = new StringBuilder();
stringBuilder.Append(myObj.a + myObj.b + myObj.c + myObj.d);
string cat = stringBuilder.ToString();

私が今まで見たStringBuilderの最良の使用法。


9
「コンセプトが不明」について話してください。うわー!
エディ

3
涼しい。「私のリードは、文字列を連結したい場合はStringBuilderクラスを使用する必要があると言っています。それが私が行うことです。それで何が問題なのですか?」Lol ...
TheBlastOne 2010

26

単純なstring.splitで十分なときに正規表現を使用して文字列を分割する


25
しかし、Java String.Splitでは、正規表現を使用します!
フランククルーガー

Regexが内部の文字列分割ほど高速であるとは思えません。
AndreiRînea2009

2
しかし、文字列分割に使用される正規表現を意図的に探し出し、それを「単純な」分割関数に置き換えることは、悲観化の完璧な例のように聞こえます。正規表現ライブラリは十分に高速です。
David Crawshaw、

5
@David Crawshaw:マイクロ最適化の機会を見つけるのは人間の時間を浪費します。コードを書くときは、最も複雑でない十分なソリューションを使用してください。
Piskvorが

6
-1:正規表現に慣れている場合は、1001言語内部の文字列マニピュレータに慣れるのではなく、これを書くのが自然です。
KillianDS、2011

26

私が知っているこのスレッドには非常に遅れていますが、最近これを見ました:

bool isFinished = GetIsFinished();

switch (isFinished)
{
    case true:
        DoFinish();
        break;

    case false:
        DoNextStep();
        break;

    default:
        DoNextStep();
}

ええ、ブール値に追加の値がある場合に備えて...


22
True、FalseのFileNotFound
コース

ねえ、あなたはいつもデフォルト/ケースelse / etcを持っているべきです。明るい人がそのブール値を列挙型に変更して他のステータスを反映し、次の人が列挙型に追加して手順を変更するのを忘れた場合はどうなりますか?実行時間と開発時間をほとんど費やす必要がない場合にデフォルトを設定します。実行時に発生する誤って導入された論理エラーを追跡する...これには、時間、お金、評判がかかります。時間のステッチは9を節約します。
Oorang

1
@Oorang ...なぜとにかくそれをスイッチとして持っているのですか?これはブール値です-if / elseだけで十分です。
Damovisa

@Damovisa facepalm右...非常によくそれから:)それを逃した:)
Oorang

2
それはNullable <Boolean>でした... :)
George Chakhidze

25

私が考えることができる最悪の例は、すべての従業員に関する情報を含む私の会社の内部データベースです。それは人事から毎晩更新を取得し、ASP.NET Webサービスを上に持っています。他の多くのアプリは、Webサービスを使用して、検索/ドロップダウンフィールドなどを入力します。

悲観論は、開発者がWebサービスへの繰り返しの呼び出しは繰り返しSQLクエリを作成するには遅すぎると考えていたことです。それで、彼は何をしましたか?アプリケーション開始イベントはデータベース全体を読み取り、それをすべてメモリ内のオブジェクトに変換します。アプリケーションプールがリサイクルされるまで無期限に保存されます。このコードは非常に遅いため、2000人未満の従業員でロードするのに15分かかります。日中に誤ってアプリプールをリサイクルした場合、各Webサービス要求が複数の同時リロードを開始するため、30分以上かかることがあります。このため、新規採用者はアカウントが作成された最初の日にはデータベースに表示されないため、最初の2日間はほとんどの社内アプリにアクセスできず、親指をいじる必要がなくなります。

悲観論の2番目のレベルは、依存するアプリケーションの破壊を恐れて開発マネージャーがそれに触れたくないということですが、そのような単純なコンポーネントの設計が不十分なため、重要なアプリケーションが散発的に全社的に停止し続けています。


28
最高の管理-「いいえ、このアプリを修正するために1回限りの80プログラマ時間を費やさないでください。それは高すぎます。そのままにしておくと、そのバグにより、1か月あたり200ユーザー時間以上、1か月あたり10プログラマ時間を浪費できます。 'メンテナンス'。" AAAAAAAAAUGH !!!
Piskvorが建物を去る

25

誰もソートについて言及していないようですので、私は述べます。

何度か、私は誰かがバブルソートを手動で作成したことを発見しました。これは、状況が、すでに存在する「ファンシーすぎる」クイックソートアルゴリズムの呼び出しを「必要としなかった」ためです。テストのために使用している10行のデータに対して、手作りのバブルソートが十分に機能したとき、開発者は満足しました。顧客が数千行を追加した後、それはあまりうまく行きませんでした。


2
通常はn = 2であると判断したとき、私は一度自分でそれを行いました。その後の製品拡張により私の前提は無効になり、コードはPDQに置き換えられました。
Mark Ransom

2
ええ、でも、その時々に基づいて何かアルゴリズムを書くのはいいことです;)
UpTheCreek

20

私はかつて、次のようなコードでいっぱいのアプリに取り組みました:

 1 tuple *FindTuple( DataSet *set, int target ) {
 2     tuple *found = null;
 3     tuple *curr = GetFirstTupleOfSet(set);
 4     while (curr) {
 5         if (curr->id == target)
 6             found = curr;
 7         curr = GetNextTuple(curr);
 8     }
 9     return found;
10 }

を削除し、最後foundに戻っnullて、6行目を次のように変更します。

            return curr;

アプリのパフォーマンスが2倍になりました。


1
私はかつて、コーディングガイドラインで「維持のために最後に1つだけ戻る」ことを要求する会社で働いていました。そして、確かに、あなたのようないくつかの唾吐きのコードは、彼らが考えていないためです(明白な解決策は、ほとんどの場合、proc出口へのgotoを使用するか、ループの終了条件を変更することでした)
flolo

12
ここでリターンカーを使用すると、特に異なる動作が発生します。currを返すと、最初に一致した結果が得られ、貼り付けたコードが最後の一致を返します。
SoapBox 2008年

2
@SoapBox:あなたは正しいです。@Dour High Arch:ループ条件を(curr &&!found)に追いかけると同じ効果があるとフロロが言ったように、パフォーマンスの向上は単一のリターンルールとは何の関係もありませんでした。proc出口へのGOTOは恐ろしいものであり、シングルリターンガイドラインの目的に反しています。
Akusete 2008年

2
みんな良いコメント。この場合、各IDを持つタプルは1つだけであると想定されていました。
Dour High Arch、

7
それは「悲観化」ではないですよね?それは単に起こるのを待っている最適化です。
Tim Long、

20

私はかつてこれらの宝石を定数クラスに含むコードを変更する必要がありました

public static String COMMA_DELIMINATOR=",";
public static String COMMA_SPACE_DELIMINATOR=", ";
public static String COLIN_DELIMINATOR=":";

これらのそれぞれは、アプリケーションの残りの部分でさまざまな目的で複数回使用されました。COMMA_DELIMINATORは、8つの異なるパッケージで200以上の使用でコードを散らかしました。


少なくともそのようなものは、ソースから簡単に検索/置換できます-それでも、私の同情。
エリックフォーブス

12
また-Deliminator?私はそれが「デリミタ」と綴られていると思った。Deliminatorは、90年代半ばの悪い映画のように聞こえますが、どういうわけか3つの等号を取得しました..........
Erik Forbes

53
Deliminator III:Rise of the Commas
Rob

33
別のメモでは、コリンズの適切な区切りを確認できてうれしいです。彼の才能に値するすべてのプログラマーは、あなたが絶対に適切に分離しなければならないことがあるなら、それはいまいましいコリンズであることを知っています。
ロブ

2
適切な検索と置換を行うのはそれほど簡単ではありません。それぞれが異なる目的で使用されるため。優れたプログラマは、少なくとも次のようなことをしているはずです:COUNTRY_LIST_DELIM = ... CLASSIFICATION_DELIM = ... etc
KitsuneYMG

19

私が社内ソフトウェアで何度も何度も遭遇する、史上最大のナンバーワン:

「移植性」の理由から「後で別のベンダーに切り替えたい」という理由でDBMSの機能を使用しない。

私の唇を読んで。社内作業の場合:ITは発生しません!


9
それは起こります。MySQL-> postgresqlなので、何も失われませんでした。
トーマス

またはpostgres / postgis-> sqlite / spatialite ...それはお尻の痛みでした...
Philip

JUnitテストで発生します
kachanov

17

私のCコンパイラのオプティマイザとルーチンの裏をかくようとしている同僚がいて、彼だけが読むことができるコードを書き直しました。彼のお気に入りのトリックの1つは、(いくつかのコードを作成する)のような読み取り可能なメソッドを変更することでした:

int some_method(int input1, int input2) {
    int x;
    if (input1 == -1) {
        return 0;
    }
    if (input1 == input2) {
        return input1;
    }
    ... a long expression here ...
    return x;
}

これに:

int some_method() {
    return (input == -1) ? 0 : (input1 == input2) ? input 1 :
           ... a long expression ...
           ... a long expression ...
           ... a long expression ...
}

つまり、一度読み取り可能なメソッドの最初の行は " return"になり、他のすべてのロジックは深くネストされた3項式に置き換えられます。これがどのように維持不可能であるかについて議論しようとしたとき、彼は彼のメソッドのアセンブリ出力が3または4つのアセンブリ命令よりも短いという事実を指摘しました。必ずしも速くはありませんでしたが、常に小さなものでした少し短いです。これは、時々メモリ使用量が問題になる組み込みシステムでしたが、コードを読み取り可能にしておくよりもはるかに簡単な最適化を行うことができました。

そして、この後、なんらかの理由でptr->structElement判読不能と判断したため、これらすべてを(*ptr).structElementより読みやすく、より高速であるという理論に変え始めました。

読み取り可能なコードを読み取り不能なコードに変換して、最大で1%の改善を実現します。


上記のモジュールがループごとに何百万回も何百万回も呼び出されている場合、その最適化について彼がコメントしている限り、私はその最適化を承認します。
マイケルドーガン、2010

2
@マイケル:短いだけでなく、速いという測定値がない限り、そうはしません。
dsimcha 2010

ほとんどの状況では、3項演算子の方がより読みやすくなっていifます。Cでの表現に関する主張の主張は、文化的/宗教的な教義であり、いかなる客観的な慣習でもありません。(より良いガイドライン:入れ子になった3項が長すぎて読みにくい場合は、ifどちらも使用しないでください。)
Leushenko

2
ここでの問題は、関数全体を取り、それを単一のステートメントであるreturnに置き換えることです。したがって、関数全体のすべてのロジックをネストされた3値に置き換えます。見ればわかると思います。これは、「3項演算子が嫌い」という宗教的なことではありません。if関数でシングルを取り、それを三項で置き換えることについて話しているのではありません。それは問題なく、多くの場合より読みやすくなっています。30行以上のメソッド全体を単一のreturnステートメントとネストされた3値に置き換えることについて話している。新しいコードの方が読みやすいとは誰も思っていませんでしたが、1人の開発者はそれがより速いと思っていました。
エディ

15

私は本格的な開発者としての最初の仕事の1つで、スケーリングの問題に悩まされていたプログラムのプロジェクトを引き継ぎました。小さなデータセットでは十分に機能しますが、大量のデータが与えられると完全にクラッシュします。

調べてみると、元のプログラマーは分析を並列化することでスピードアップを図り、追加のデータソースごとに新しいスレッドを起動しようとしていることがわかりました。ただし、すべてのスレッドが共有リソースを必要とし、その上でデッドロックが発生していたため、彼は間違いを犯していました。もちろん、同時実行のすべての利点は消えました。さらに、100以上のスレッドを起動するためにほとんどのシステムをクラッシュさせ、そのうちの1つを除くすべてをロックしました。私の頑丈な開発マシンは例外で、約6時間で150のソースデータセットを処理しました。

そこで、それを修正するために、マルチスレッドコンポーネントを削除し、I / Oをクリーンアップしました。他の変更はありませんでしたが、150ソースのデータセットの実行時間は私のマシンでは10分未満になり、平均的な会社のマシンでは無限から30分未満になりました。


今日のプロジェクトでこれが発生するのを防ぐだけです。今、私は良い選択をしたことを知っています。
deadalnix、2011

14

私はこの宝石を提供できると思います:

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1, root = 0;
    #define ISQRT_INNER(shift) \
    { \
        if (value >= (tmp = ((root << 1) + (1 << (shift))) << (shift))) \
        { \
            root += 1 << shift; \
            value -= tmp; \
        } \
    }

    // Find out how many bytes our value uses
    // so we don't do any uneeded work.
    if (value & 0xffff0000)
    {
        if ((value & 0xff000000) == 0)
            tmp = 3;
        else
            tmp = 4;
    }
    else if (value & 0x0000ff00)
        tmp = 2;

    switch (tmp)
    {
        case 4:
            ISQRT_INNER(15);
            ISQRT_INNER(14);
            ISQRT_INNER(13);
            ISQRT_INNER(12);
        case 3:
            ISQRT_INNER(11);
            ISQRT_INNER(10);
            ISQRT_INNER( 9);
            ISQRT_INNER( 8);
        case 2:
            ISQRT_INNER( 7);
            ISQRT_INNER( 6);
            ISQRT_INNER( 5);
            ISQRT_INNER( 4);
        case 1:
            ISQRT_INNER( 3);
            ISQRT_INNER( 2);
            ISQRT_INNER( 1);
            ISQRT_INNER( 0);
    }
#undef ISQRT_INNER
    return root;
}

平方根は非常に敏感な場所で計算されたので、それをより速くする方法を検討するという仕事を得ました。この小さなリファクタリングにより、実行時間が3分の1に短縮されました(使用するハードウェアとコンパイラーの組み合わせ、YMMVの場合):

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1, root = 0;
    #define ISQRT_INNER(shift) \
    { \
        if (value >= (tmp = ((root << 1) + (1 << (shift))) << (shift))) \
        { \
            root += 1 << shift; \
            value -= tmp; \
        } \
    }

    ISQRT_INNER (15);
    ISQRT_INNER (14);
    ISQRT_INNER (13);
    ISQRT_INNER (12);
    ISQRT_INNER (11);
    ISQRT_INNER (10);
    ISQRT_INNER ( 9);
    ISQRT_INNER ( 8);
    ISQRT_INNER ( 7);
    ISQRT_INNER ( 6);
    ISQRT_INNER ( 5);
    ISQRT_INNER ( 4);
    ISQRT_INNER ( 3);
    ISQRT_INNER ( 2);
    ISQRT_INNER ( 1);
    ISQRT_INNER ( 0);

#undef ISQRT_INNER
    return root;
}

もちろん、これを行うにはより速くより良い方法がありますが、私はそれが悲観化のかなりきちんとした例だと思います。

編集:考えてみてください。展開されたループは、実際にはきちんとした悲観化でもありました。バージョンコントロールを掘り下げて、リファクタリングの第2ステージも紹介できます。

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1 << 30, root = 0;

    while (tmp != 0)
    {
        if (value >= root + tmp) {
            value -= root + tmp;
            root += tmp << 1;
        }
        root >>= 1;
        tmp >>= 2;
    }

    return root;
}

これは、実装が少し異なりますが、まったく同じアルゴリズムなので、適格であると思います。


私は考えisqrt()を計算しfloor(sqrt())、しかし、なぜこのコードの動作はしますか?
Pablo H

11

これはあなたが求めていたものよりも高いレベルにあるかもしれませんが、それを修正する(許可されている場合)には、より高いレベルの痛みも伴います。

確立され、テストされ、成熟したライブラリの1つを使用する代わりに、オブジェクトリレーションシップマネージャー/データアクセスレイヤーを手作業でローリングすることを主張する(たとえそれらがあなたに指摘された後でも)。


独自のコードをロールすることは常に悪い考えではありません。かつて言った賢い人のように、依存関係を見つけ、それらを排除します。それがコアビジネス機能である場合は、自分で実行してください。
Kibbee 2008年

私はそれが常に悪い考えだとは決して推測しませんでした。Frans Boumaなどと言わない限り、ORM / DALがコアビジネス機能であるとは思えません。通常、NIHシンドロームが原因で、(四角)ホイールを再発明する場合など、独自の同等物を作成するのは非常にコスト効率がよくありません。
Gordon Hartley、

@Kibbee-同意する。サードパーティの依存関係を使用するよりも、独自にロールして理解する方が良いです。それが壊れたとき(そしてそれはそうなるでしょう)、少なくともあなたはそれを修正します。私は過去にHibernateとApache Commonsにアプリのパフォーマンスを完全に損なうバグを発見しました。
CodingWithSpike 2009

4
確立されたものがどれもあなたが必要とする重要な機能を持っていない場合、手巻きは本当にあなたの唯一の選択肢です。
staticsan 2009

3
実際、上記のコメントのいくつかを考慮して、もう少し見方を変えます。別の悲観化は、ORMにすべてを実行させることです。多くの場合、95%以上のケースで役立ちます。最後の5%では、パフォーマンス、単純さ、またはその両方のために、手作りの永続化コード/直接ストアドプロシージャの呼び出しなどにドロップする方がはるかに簡単です。
Gordon Hartley

10

すべての外部キー制約はデータベースから削除されました。そうしないと、非常に多くのエラーが発生するためです。


8

これは問題に完全には適合しませんが、とにかく警告的な話をします。私は、実行速度が遅い分散アプリで作業していて、問題を解決することを主な目的とする会議に参加するためにDCに飛んで行きました。プロジェクトリーダーは、遅延の解決を目的とした再アーキテクチャの概要を説明し始めました。週末にいくつかの測定を行って、ボトルネックを単一の方法に限定したことを申し出ました。ローカルルックアップでレコードが欠落しており、アプリケーションがトランザクションごとにリモートサーバーにアクセスする必要があることが判明しました。レコードをローカルストアに追加することで、遅延が解消され、問題は解決しました。再構築によって問題が修正されなかったことに注意してください。


8

すべてのJavaScript操作の前に、操作対象のオブジェクトが存在するかどうかを確認します。

if (myObj) { //or its evil cousin, if (myObj != null) {
    label.text = myObj.value; 
    // we know label exists because it has already been 
    // checked in a big if block somewhere at the top
}

このタイプのコードに関する私の問題は、それが存在しない場合、誰も何も気にしないようです?何もしない?ユーザーにフィードバックを提供しませんか?

Object expectedエラーが煩わしいことに同意しますが、これはそのための最良の解決策ではありません。


では、最善の解決策は何ですか?直接的な結果がなくても、たまにエラーが発生するようなコードを書くのはずさんだと思います。もちろん、どのような状況でもオブジェクトがnullであると予期しない場合は、これを行うべきではありません。おそらくこれが意図したことです。
サイモン

7

YAGNI過激主義はどうでしょう。それは時期尚早の悲観化の一形態です。YAGNIを適用するといつでもそれが必要になり、最初に追加した場合よりも10倍の労力が必要になります。成功したプログラムを作成した場合、オッズはそれを必要としています。人生がすぐに尽きるプログラムを作成することに慣れているなら、YAGNIを練習することを続けます。


3
ありがとう、私はこれらの不完全な「極端なプログラミング」の頭字語と、人々がそれらを使って怠惰な非生産的な慣行をサポートする方法にうんざりしています。
JAL

実際のプロジェクトの調査によると、1回限りのコードと再利用コードの間の実際の係数は平均で約3です。したがって、10は単なる「フェルト」値ですが、意図は正しいです。
peterchen 2010

@peterchen-研究は、再利用可能なコードを1回限りのコードとして書くのに3倍の時間がかかることを示していますか、それとも、1 回限りのコードを再利用可能なコードに変換するのに3倍の時間がかかることを書いていますそもそも再利用可能なコード?
ジェフスターナル、

@jeff:IIRC彼らは、別々のメソッドに移されたインラインスニペットのいくつかの複雑さの尺度(あなたが何を考えていても)を比較しました。サポートされる追加のケース、パラメーターのチェックなどにより、複雑さが増します(これにより、メソッドがかなり小さいと想定されます)。リファレンスを掘り下げてみます。
peterchen 2010

6

これは時期尚早な最適化ではありませんが、間違いですが、これはBBCのWebサイトでWindows 7についての記事から読まれました。

カラン氏は、Microsoft Windowsチームは、オペレーティングシステムのあらゆる面を徹底的に改善してきたと語った。「WAVファイルのシャットダウン音楽をわずかにトリミングすることで、シャットダウン時間を400ミリ秒短縮することができました。

現在、私はまだWindows 7を試していないので、間違っているかもしれませんが、シャットダウンにかかる時間よりも重要な他の問題があることに間違いはありません。結局のところ、「Windowsをシャットダウンしています」というメッセージが表示されると、モニターの電源がオフになり、離れていきます。この400ミリ秒のメリットは何ですか?


他の問題は、BBC Webサイトでプログラマー以外の人に説明するのは簡単ではないことに気付くでしょう。
トム・Leys

これは私が考慮しなかった角度です-多分私は私の皮肉を失い始めているかもしれません:-)
belugabob 2009年

その400ミリ秒は、400ミリ秒の消費電力です。おそらく取るに足らないことですが、時間の経過とともに増える可能性があります。それでも、心配することはありません。
ZachS

1
XP VMがシャットダウンして次の作業に移るのを待つのに、合計で何時間も無駄になりました。シャットダウンの高速化に非常に感謝しています。
James

1
興味深いことに、WAVファイルは非同期で再生されるため、シャットダウンのファンファーレがシャットダウンに必要な時間よりも短い限り、WAVファイルをトリミングしても何も起こりません。さらに興味深いことに、シャットダウンが非常に最適化されている場合、シャットダウンするすべてのWindowsボックスが実際にダウンするまで、どうして必要になるのでしょうか。(もちろん、大きな赤いボタンの使用を除きます。)
TheBlastOne 2010

6

私の部門の誰かがかつて文字列クラスを書いたことがあります。のようなインターフェースCStringが、Windowsに依存していません。

彼らが行った「最適化」の1つは、必要以上のメモリを割り当てないことでした。どうやらクラスがstd::string過剰なメモリを割り当てる理由に気付かないのは、+=操作をO(n)時間で実行できる。

代わりに、1回の+=呼び出しごとに再割り当てが強制され、追加が繰り返されてO(n²)ペインターのアルゴリズムになりました


5

私の元同僚(実際にはsoab)が割り当てられ、顧客のデータ(小売業界)を収集および分析する必要があるJava ERPの新しいモジュールを構築しました。彼は、EVERY Calendar / Datetimeフィールドをそのコンポーネント(秒、分、時間、日、月、年、曜日、妊娠中期、妊娠中期(!))に分割することを決定しました。


3
それは時期尚早の最適化ではなく、正確さのためにそれを行う必要があると彼は思った
Pyrolistical 2008年

確かに、彼は思った、彼はそれを必要としますが、ほとんどのDBMSは、DAYOFWEEK(タイムスタンプ)機能のいくつかの種類、その混乱をやってを持っているので、アップフロント:)私の意見では時期尚早で十分です
Joril

1
私はOLTPには使用しませんが、「顧客のデータを分析する」場合、それは実際にデータウェアハウスを設計する非常に柔軟な方法です(日付と時刻が異なるディメンションに分割されている限り)。本当に何百万行ものデータに対してDAYOFWEEK()を呼び出しますか、それとも単に整数フィールドに対してインデックス検索を行いますか?
Tim Medora

行がそれほど多くあったかどうかはわかりませんが、確かにそれは与えられた説明ではありません:)
Joril

3

誰にも害はありませんが、私はこれを持っている課題(java)を採点しただけです

import java.lang.*;

1
これが上級レベルのクラスでない限り、なぜこれが良い考えではないのかを十分に教えられない限り、この学生を少し緩める必要があると思います。
ブライアンオークリー

24
正しくプログラミングすることを教える責任があるという生徒のコードについて、教師がWTFを呼び出す皮肉に注意するのは私だけでしょうか?
JohnFx 2009年

3
ええ、私はこれが傷つくことを見ることができません。最悪の場合、それは過剰です。学習中、生徒は厳密な一貫性に訴える傾向があり、java.langのインポートは、生徒がインポートについて学んだことと厳密に一貫しています。
cygil 2009年

1
分かりやすく教えてくれてありがとう。それは計算生物学の課題であり、私はそれを数えませんでしたし、言及さえしませんでした。
オーバーフロー

2
@JohnFX:採点者と教師が同じ人物であるとは限りません。
エディ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.