コードを書くときは、コードをできる限りクリーンで読みやすいものにするように常に心がけています。
ときどき、ラインを越えて、すっきりしたきれいなコードから少しugいコードに移行して、より速くする必要があるときがあります。
その線を横切るのはいつですか?
コードを書くときは、コードをできる限りクリーンで読みやすいものにするように常に心がけています。
ときどき、ラインを越えて、すっきりしたきれいなコードから少しugいコードに移行して、より速くする必要があるときがあります。
その線を横切るのはいつですか?
回答:
あなたがラインを横切るとき
実例は次のとおりです。私が実行している実験システムは、データの生成が非常に遅く、実行ごとに9時間以上かかり、CPUの40%しか使用していませんでした。コードをめちゃくちゃにするのではなく、すべての一時ファイルをメモリ内ファイルシステムに移動しました。8行の見苦しいコードを追加し、CPU使用率は98%を超えました。問題が解決しました; さは必要ありません。
foo
て名前を変更します。foo_ref
通常foo
は、ソースファイルのすぐ上にあります。私のテストハーネスではfoo
、foo_ref
検証と相対的なパフォーマンス測定のために呼び出します。
それは間違った二分法です。あなたはコードを高速に行うことができますし、維持しやすいです。
あなたがそれをする方法は、特にできるだけ単純なデータ構造で、きれいに書くことです。
次に、時間の流れがどこにあるかを見つけて(それを実行することによって、前にではなく、書いた後で)、それらを1つずつ修正します。 (例を示します。)
追加:時間とメモリのトレードオフ、速度と保守性のトレードオフなど、トレードオフについて常に耳にしますか?そのような曲線が存在する可能性は十分にありますが、特定のプログラムが曲線上にある、またはその近くにあるとさえ仮定すべきではありません。
曲線上にあるプログラムは(特定の種類のプログラマーに提供することで)簡単に、非常に遅く、保守性を低くすることができます。そうすると、曲線に近づきません。そのようなプログラムには、より速く、より保守しやすいようにする十分な余地があります。
私の経験では、そこから多くのプログラムが始まります。
私のOSSの存在では、パフォーマンスを目的とした多くのライブラリ作業を行います。これは、呼び出し側のデータ構造(つまり、ライブラリの外部)に深く結び付けられており、着信タイプに対する(設計上の)義務はありません。ここで、このパフォーマンスを実現する最良の方法はメタプログラミングです。これは(私は.NETの国にいるので)IL-emitを意味します。これはsomeい、いコードですが、非常に高速です。
このように、ライブラリコードはアプリケーションコードよりも「ugい」かもしれませんが、入力の制御が少ない(またはまったくない)ため、異なるメカニズムでいくつかのタスクを達成する必要があります。または先日私がそれを表明したように:
「狂気の崖をコーディングするので、あなたはする必要はありません」
現在、アプリケーションコードはわずかに異なります。これは、「通常の」(健全な)開発者が通常、共同作業/専門家の時間の多くを投資する場所であるためです。それぞれの目標と期待は(IMO)わずかに異なります。
IMOは、高速で保守が容易であることを示唆する上記の回答は、開発者がデータ構造をより細かく制御し、メタプログラミングなどのツールを使用していないアプリケーションコードを参照しています。とはいえ、メタプログラミングにはさまざまな方法があり、さまざまなレベルの狂気とさまざまなレベルのオーバーヘッドがあります。その分野でも、適切な抽象化レベルを選択する必要があります。しかし、積極的に、積極的に、本当に最速の方法で予期しないデータを処理することを本当に望んでいるとき。いかもしれません。それに対処する; p
コードのプロファイルを作成し、実際に大幅な速度低下を引き起こしていることを確認したとき。
クリーンコードは、高速実行コードと必ずしも排他的ではありません。通常、読みにくいコードは、実行速度が速いためではなく、記述が速いために作成されました。
あなたの変更が実際に何かを改善することを確実に知らないので、それをより速くしようとする試みで「汚い」コードを書くことは間違いなく賢明ではありません。Knuthが最高の結果を出しました:
「小さな効率を忘れて、時間の約97%を言うべきです。時期尚早な最適化はすべての悪の根源です。しかし、その重要な3%で機会を逃してはなりません。優れたプログラマーは、論理的に、彼は重要なコードを注意深く見るのが賢明でしょう。しかし、そのコードが特定された後にだけです。」
つまり、最初にコードをきれいに記述します。次に、結果のプログラムのプロファイルを作成し、そのセグメントが実際にパフォーマンスのボトルネックになっているかどうかを確認します。その場合、必要に応じてセクションを最適化し、最適化について説明するために、ドキュメントのコメント(おそらく元のコードを含む)を十分に含めるようにしてください。次に、結果をプロファイルして、実際に改善を行ったことを確認します。
質問は「コードを読むのが難しい」と言っているので、単純な答えは決してありません。読みにくいコードを書く言い訳はありません。どうして?2つの理由。
使い捨てコードの場合。私はその文字通り意味:あなたは一回限りの計算やタスクを実行する、そして、そのような確信を持って知っているスクリプトを書くとき、あなたは「RMソース・ファイル」躊躇せずに、できることを再度、そのアクションを行う必要がありませんそして、あなたが選ぶことができますいルート。
さもなければ、それは間違った二分法です-より速くそれをugくする必要があると思うなら、あなたはそれを間違っています。(または、優れたコードについての原則を改訂する必要があります。gotoを使用することは、問題の適切な解決策である場合、実際には非常にエレガントです。ただし、めったにありません。)
私にはそれは安定性の割合です(コンクリートにセメントで固めた、粘土をオーブンで焼き、石に固め、永久インクで書いたような)。将来的にコードを変更する必要がある確率が高いほど、コードが不安定になるほど、生産性を維持するために、湿った粘土のように柔軟性が必要になります。また、読みやすさではなく柔軟性を強調しています。私にとって、コードの変更のしやすさは、コードの読みやすさよりも重要です。コードは読みやすく、悪夢は変更することができます。また、変更が悪夢である場合、実装の詳細を読み取って簡単に理解できるのはどのような用途ですか?単なるアカデミックな演習でない限り、通常、実動コードベースのコードを簡単に理解できるのは、必要に応じてより簡単にコードを変更できるようにすることです。変更が難しい場合は、その後、読みやすさの多くの利点が見えなくなります。可読性は一般に柔軟性のコンテキストでのみ有用であり、柔軟性は不安定性のコンテキストでのみ有用です。
読むのがどれだけ簡単か難しいかに関係なく、想像できるコードを維持するのが最も難しい場合でも、それを変更する理由がなく、それを使用するだけであれば、問題は生じません。そして、特にパフォーマンスが最も重要になる傾向がある低レベルのシステムコードでは、このような品質を実現することが可能です。私は今でも定期的に使用しているCコードを持っていますが、80年代後半から変わっていません。それ以来、変更する必要はありません。コードは、いじくり回す頃に書かれたfuいもので、私にはほとんど理解できません。しかし、それは今日でも適用可能であり、十分に活用するためにその実装を理解する必要はありません。
テストを徹底的に記述することは、安定性を向上させる1つの方法です。もう1つはデカップリングです。コードが他のものに依存していない場合、コードを変更する唯一の理由は、コード自体を変更する必要がある場合です。場合によっては、少量のコードの複製がデカップリングメカニズムとして機能して、安定性を劇的に向上させることができます。これにより、他のコードから完全に独立したコードが得られた場合、価値のあるトレードオフになります。これで、コードは外の世界への変更に対して無敵です。一方、10の異なる外部ライブラリに依存するコードには、将来変更される理由が10倍あります。
実際には、ライブラリをコードベースの不安定な部分から分離することもできます。サードパーティのライブラリの場合と同様に、ライブラリを個別にビルドすることもできます(同様に、少なくとも、チーム)。そのような組織は、人々が改ざんするのを防ぐことができます。
もう1つはミニマリズムです。コードが実行しようとする回数が少ないほど、コードが適切に実行できる可能性が高くなります。モノリシックデザインはほとんど永久に不安定です。機能が追加されると、完成度が低下するためです。
死に至るまで微調整された並列化されたSIMDコードのように、必然的に変更が困難になるコードを作成しようとする場合は常に、安定性が主な目標になります。コードを変更する必要がなく、将来それを維持する必要がない可能性を最大化することにより、コードを維持する難しさを打ち消します。これにより、コードの保守がどれほど困難であっても、保守コストがゼロになります。