小さくても複雑なコードを書くのに役立つアルゴリズムについて勉強しています。150 行の if-else ステートメントを書く代わりに、20 行でそれを行うアルゴリズムを設計できます。問題は、これらのアルゴリズムの多くが複雑になる可能性があり、それらを理解するために多くの計算が必要になることです。彼らのことを理解しているのも、この辺では私だけです。
コードの保守性のために、他の人が行うようにコードを書く方が良いでしょうか、それともアルゴリズムを使用する方が良いでしょうか?
小さくても複雑なコードを書くのに役立つアルゴリズムについて勉強しています。150 行の if-else ステートメントを書く代わりに、20 行でそれを行うアルゴリズムを設計できます。問題は、これらのアルゴリズムの多くが複雑になる可能性があり、それらを理解するために多くの計算が必要になることです。彼らのことを理解しているのも、この辺では私だけです。
コードの保守性のために、他の人が行うようにコードを書く方が良いでしょうか、それともアルゴリズムを使用する方が良いでしょうか?
アインシュタインが言ったように:
すべてを可能な限りシンプルにしますが、シンプルにしないでください。
これはコードだけでなく、物理学にも当てはまります。
あなたの判断を下してください - 維持しやすくなりますか? 多くの場合、大きな if/else の混乱を小さなものに減らすことで、存在する必要のないコーナー ケースを取り除き、将来発生する可能性のあるバグを防ぎます。もちろん、明確な条件のセットを、たまたま機能するブール論理のあいまいなひねりに減らすことで、何かが変更されたときに物事を維持するのがはるかに難しくなる可能性があります。
編集:
あなたが引用した場合、数式が機能する場合は、おそらくより良いオプションです-ソースを引用してコメントを残すこともできます. ただし、以前は数式が存在していたが、特定のケースを回避できるようにするために削除された可能性は十分にあります。これは、バージョン管理リポジトリのコメントが役立つようなものです。
まだ誰もリンクを投稿していないので、彼が言及している PID アルゴリズムの説明を以下に示します。
コードは 1 回書き込まれ、10 回読み取られます。そのため、できるだけわかりやすくするように努める必要があります。
また、デバッグはコードを書くよりもはるかに困難です。では、複雑なコードを書くために頭脳をすべて注ぎ込んでいるのに、どうやってコードをデバッグできるのでしょうか?
ソフトウェア開発の 3 つの法則に従うようにしてください。
Robert C. Martin は、この漫画を彼の著書Clean Codeの紹介として使用しています。
(ソース: osnews.com )
コードは主に人間が理解する必要があることを忘れないでください...コンパイラーはコンピューターが理解できるようにします。
ここでの「複雑さ」のレベルは少し危ういかもしれませんが、アルゴリズムが解決するために数学の博士号を必要としない限り、
先に進んでアルゴリズムを使用してください。アルゴリズムの名前について適切なレベルのドキュメントを作成してください。また、アルゴリズムの仕組みの簡単な説明や、アルゴリズムに関するドキュメントへの参照も記載してください。
これにより、コードの量が抑えられ、アプリケーションのパフォーマンスが少し向上することが期待されます。また、周りの数人のプログラマーが新しいことを学び、レパートリーに追加するようになることが期待されます。さらに、これらのことを知っているプログラマーが後で出てこない可能性が常にあります。
古き良き引用...
愚か者なら誰でも、コンピューターが理解できるコードを書くことができます。優れたプログラマーは、人間が理解できるコードを記述します
150 行の何かが 20 行の何かよりも単純だと考える人がいるなんて信じられません。
20 行を使用して、次のように同僚を保護します。
すべてのデータ構造不変条件とすべての非自明なループ不変条件を文書化します。これらをコメントではなく、不変条件をチェックする実際のコードで文書化します。チェックは生産中にオフにすることができます。
コードで数式を使用する場合、またはコードで導出する場合は、コメント (または静的文字列)に参照を含めます。理想的には、2 つの参考文献を含めることをお勧めします。1 つは数秒で利用可能になる可能性が高い Web 参考文献であり、もう 1 つは、印刷物として長期間掲載され、大学の図書館で見つかる可能性が高い評判の高い教科書です。
コードを理解するために特別な専門知識 (偏微分方程式の理解、物理学の学位、ガロア理論など) が必要な場合は、身を守るために経営陣に「私にはこの特別な専門知識があり、私がより小さなコードを書くことは可能ですが (したがって、より速く、より信頼性が高く、保守が容易になります)、しかし、あなたが私の代わりになる場合は、同様の専門知識を持つ人を雇わなければなりません。 " そのような専門知識がいかに簡単に得られるかを経営陣に伝えていただけると助かります。たとえば、工学の学位を持っている人の多くは偏微分方程式を学ぶことができますが、ガロア理論家は地に足の着かない人です。
PS 後で自分のコードをデバッグできるように、趣味のプロジェクトからのコメントの例を次に示します。
/*
* Compute the position of a point partially along the geodesic from
* pt1.lat,pt1.lon to pt2.lat,pt2.lon
*
* Ref: http://mathworld.wolfram.com/RotationFormula.html
*/
必要なだけ複雑で、それ以上ではありません。
それは本当に複雑な意味に依存します。あなたの「単純な」アルゴリズムが 150 行のほぼ同じコードである場合、私の目は曇ってしまい、理解できなくなります。これらの条件をマトリックスなどに入れ、コードがマトリックスを読み取って決定を下すためのループである場合、ループが if/else ステートメントの束よりも「単純」ではない場合でも、それをよりよく理解できます。
基本的に、デフォルト変数 $_ を大量に使用して 1 行ですべてを行う Perl プログラムについて話している場合は、より長く、より冗長なバージョンを使用することをお勧めします。
何かを行うための承認された公式がある場合は、承認された公式を使用できます。3 行または 4 行の単純な代数式と 1 行の複雑な微分方程式がある場合は、単純な代数式を使用する必要があります。コメントで言及されているケースでは、PID アルゴリズムは 150 行の if/else コードよりも「単純」だと思います。アルゴリズムを使用して何かを覆い隠しているとは思いませんが、問題の領域で標準的な手法を使用しています。よくコメントして、式を説明する Web ページへのリンクを含めてください。
100 行の if/else ステートメントを通り抜ける方法を見つけることは、多くの場合 (私の意見では) より良いアルゴリズム (コメントで説明またはリンクする必要があります) を理解するのに同じ時間を費やし、最終的にそれを検証することよりも、メンテナーのスタミナにとってより困難です。実装の 20 行で実際にそれが実行されます。また、職場での教育の利点もあり、(良い意味で) はるかに興味深いものになり、多くの場合、実行プロファイルも向上します (リソースの使用が少なくなります)。
避けるべき巧妙さは、実際の利益なしに言語を悪用する「巧妙なハック」の形をとっています。採用すべき賢さは、常にその仕事に最適なアルゴリズムを使用することです。
編集: PID の例について: PID の機能を一連の if-else ステートメントで適切に置き換えることができるとは想像しがたいです。if-else ソリューションは常にうまく機能せず (遷移がスムーズにいかない)、保守が非常に難しく、調整が非常に困難です (望ましい動作を得るには、PID 部分の調整が非常に重要です)。簡単に調べることができる数学を知らなくても、PID を理解することはそれほど難しくないことを付け加えたいと思います。
興味深いことに、コードの複雑さの最も一般的な尺度の1つは、ネストの深さです。「If-then-else」ソリューションは、自動コードアナライザーによって、公式のソリューションよりも複雑に分類される可能性があります。
しかし、私は「WTF?」を十分に見てきました。あなたが説明するコーディングでは、私は通常、if-then-elseアプローチを採用します。しかし、これを考慮してください。より複雑で定型的なアプローチを使用することは可能ですが、特に難しいコンポーネントを適切な名前のメソッドに分割することは可能ですか?そうすることができれば(おそらく冗長性を排除するためにリファクタリングさえ)、マルチレベルのif-then-else構造を回避しながら、アルゴリズムの最悪の側面を回避できる可能性があります。
Zen of Pythonは、この問題に対処するのに非常に優れています。
..。
単純な方が複雑な方が優れています。
複雑なものは複雑なものよりも優れています。
..。
実装を説明するのが難しい場合、それは悪い考えです
..。
言い換えれば(そして他の人が言っているように)、課せられた制約(時間、メモリなど)の下で仕事を成し遂げる最も単純なアルゴリズムが最良のものです。明らかに、仕事を終わらせない単純なアルゴリズムでは十分ではありません。複雑なアイデアを使用しているためにコードが短い場合、それは複雑です。他の誰もあなたのコードを理解できない場合、それは複雑であり、あなたが彼らにそれを説明するのに苦労しているなら(たとえ彼らが数学の博士号でそれを理解するとしても)、それは悪い考えです。
..。
特別な場合は、規則を破るほど特別なものではありません。
実用性は純粋さを打ち負かしますが。
..。
多くの場合、その存続期間中に元々「純粋な」コードに忍び寄る特殊なケースのコードがたくさんあります。この建物の複雑さと戦う必要がありますが、必要なときにそれを受け入れてください。
通常は、よりシンプルな方が優れています。他の人がおそらくいつかそれを維持しなければならないことを忘れないでください。
コードを扱う平均的なプログラマーにとって最も保守しやすく、理解しやすい方法でコードを記述します。
不必要な複雑さは常に悪いことです。はい、200 行の機能を実行する素晴らしいワンライナーを書くのは楽しいかもしれません。ただし、コードは維持する必要があることを忘れないでください。そして、短い複雑なコードは維持するのが地獄です。
コードを単純化することのもう 1 つのリスクは、平均的なコーダーの山にまとめられることです。あなたが探している行は、読み取り可能/読み取り不能なコードです。1 週間後に戻ってきてコードを簡単に読めるなら、それは十分に単純だと思います。
非常に最適化されたコードは非常に遅く実行され、最適化されていないコードはすぐに実行されるのを見てきました。これは、コンパイラがコンピューターがどのように動作するかを知っており、コンパイラの作成者が最初に最適化が容易なコードに焦点を合わせているためです。
150 行のアルゴリズムが、20 行のバージョンより実行時にはるかに高速なものにコンパイルされる可能性があります。コンパイラがアルゴリズムを最適化する方法を知らないため、20 行のアルゴリズムは遅くなる可能性があります。
また、複雑なバージョンが何をしようとしているのかを保守担当者が理解できるように、if-else バージョンを 20 行のアルゴリズム バージョンの上のコメント ブロックに配置することもお勧めします (またはその逆)。両方をコードに含めると、2 つのパフォーマンス テストも簡単になります (両方を入力したら、もう一方を削除する必要はありません)。これにより、他の言語/プラットフォーム/コンパイラへの移行も容易になります。期待していないかもしれませんが、コードが機能する場合、コードは何十年も存続し、さまざまなコンパイラやプラットフォームが見られる可能性があります。
作成してから数週間後に、「より複雑な」バージョンを他の人にレビューしてもらいます。あなたがそれを読んで他の人に説明するのがどれほど難しいか、およびコードに対する彼らの反応で複雑さを判断してください。
複雑にすることのリスクは、他の誰もそれを理解できないということです。この場合、明確にコメントし、他の誰かがそれを学び、理解するのに役立ついくつかの情報源を引用してください.
シンプルにすることのリスクは、長いために誰かが理解しようとしないことです。
問題は、複雑なコードの方が優れているかどうかだと思います。より高速で信頼性が高いですか?目標は、最良のプログラムを書くことです。複雑なコードが最良の解決策である場合は、後継者が将来コードを管理できるように、より良いコメントを書く必要があります。原則として、コードはどのような状況でも可能な限り単純にする必要があります。
20行でそれを行うことができ、それらの行に適切にコメントを付けることができれば、私はそれを選ぶと思います. 保守するコードが少なくなるため、保守が容易になるだけでなく、仲間のプログラマーを賢くすることにも貢献できます。
事前の最適化と巧妙なハックは 1 つのことですが、スマートなアルゴリズムは常に公平なゲームでした。
ただし、これらのアルゴリズムは独自の関数で分離したままにし、入力変数と出力変数を説明することを忘れないでください!
必須の引用:
「複雑さを制御することは、コンピューター プログラミングの本質です。」(ブライアン・カーニガン)
ドメインの複雑さを基礎となる技術的な複雑さから分離することが重要だと思います。
コンピュータを使用したいドメイン固有の機能には、本質的に複雑なものもあれば、そうでないものもあります。たとえば、会計の問題は奇妙なルールでいっぱいですが、ほとんどの計算はかなり単純です。一方、金融証券の評価には、種類によっては、非常に複雑な数式と非常に多くのシミュレーションが含まれる場合があります。ほとんどのコンピュータ システムは、実際には大量のデータを収集しているだけですが、その多くには、いくつかの複雑なアルゴリズムが組み込まれています。
一方、テクノロジーはしばしば独自の複雑さを課します。PC 用に C++ で大規模なプログラムを作成するのは困難な場合があります。インターネット用の Web ベースのアプリケーションを作成することは、はるかに悪い場合があります。耐障害性、パフォーマンス、またはセキュリティを確保しようとすると、多くの場合、複雑さが大幅に増します。それぞれの異なるテクノロジーは、システムを助けたり妨げたりします。
私たちが本当にやりたいことは、固有のドメインまたは技術仕様に最も近い、可能な限り単純な形式でコードを表現することです。オペレーティング システムを作成している場合は、C の方が使いやすい言語です。保険の複雑なリスク確率を計算している場合は、APL のようなマトリックス指向の言語よりも適切な場合があります。大規模なレポートを作成するだけの場合は、レポート向けの単純な構文を持つものが最適です。
したがって、150 行の if/else が問題の表現方法と 20 行の巧妙な行よりもはるかに適切に「一致」している場合、それははるかに保守しやすく拡張しやすいコードです。長期的な観点から見ると、実行中のコードを書くのは簡単ですが、それを維持することは本当の挑戦です....
ポール。
ええと、コードが十分に大きくなると、ボリュームが非常に大きいために、コードを理解して維持するのがかなり難しくなる可能性があります(ほとんどのJavaコードを参照)。他のすべて(パフォーマンスなど)が等しく、単純なアルゴリズムと複雑なアルゴリズムの長さの違いが非常に大きい場合、単純で冗長なアルゴリズムよりも、複雑で簡潔でエレガントなアルゴリズムを常に使用します。両方のアルゴリズムが正しいことが証明されていると仮定すると、ifステートメントが少なく、コードが全体的に少ないアルゴリズムでは、実装の微妙なバグが発生する可能性が低く、したがってメンテナンスが必要になる可能性が低くなります。私がメンテナーだったとしたら、誰かが途方もなく長くて退屈なアルゴリズムをどのように実装したかを学ぶよりも、新しいアルゴリズムを学ぶことに時間を費やしたいと思います。
必要なだけ複雑にする必要があります。それができないのは、複雑で大きな違いです。
私は数学とアルゴリズムを知っていて好きであることは認めますが、私にとって 150 行の if/else 混乱は、20 行できれいに表現できるものよりもはるかに複雑で維持が困難です。コードを適切に文書化し、論文、本、またはウィキペディアへの参照を挿入します。
依存します。関数を構成する 150 行の if-then-else ステートメントを維持する必要はありません。特に、決定木が密集している場合はそうです。20 行の複雑な計算は、優れている場合とそうでない場合があります。理解するのに時間がかかるかもしれませんが、長いソリューションは検証にさらに時間がかかるかもしれません.
理想的には、より少ない、より単純な行でそれを行う方法を見つけるでしょうが、すべての関数がそのように機能するとは限りません。
20 行を使用する場合は、コメントに保存されている 130 行の一部を使用して、使用しているアルゴリズムを説明してください。うまく説明できない場合は、150 行のソリューションを使用してください。
複雑であることは、必ずしもコード行数の増減を意味するわけではありません。
完璧なシステムは、最初から構築されることはありません。 あなたにできることは、物事を一方通行に縛り付ける複雑な決定をしすぎないようにすることだけです。
そのため、私はプロジェクトの初期バージョンでは複雑さを低く抑えたいと思っています。何かを構築した理由 (新しい柔軟性) は、深刻な影響を受けます。できるだけ複雑にすると、最初に理解できる人は少なくなります。それは良いことかもしれませんし、悪いことかもしれません。
シンプルにしすぎると (そしてコードが 50 ~ 70% 増えると)、パフォーマンスの問題が発生する可能性があります。
システムが老朽化して成熟するにつれて、複雑さはリファクタリングによってもたらされるようです。それまでに、一部のコードが二度と触れられない可能性があるポイントに到達することができます。また、触れたとしても、触れる頻度が低くなるため、複雑さを理解するためのコストが低くなります。
簡単な手順で複雑な問題を解決するのが好きです。それが不可能な場合は、それに応じて複雑さが増します。いつ「十分」になるかを知ることについて、別の質問にポイントがありました。場合によっては、もう少しコードを増やす (5 ~ 20%) ことで複雑さが大幅に相殺されることがあります。
より良いアルゴリズムを必要とすることは、通常は良い問題です。なぜなら、それはあなたのものが使用され、対処すべき新しい要求があることを意味するからです.
これは、私にとってデータベースの抽象化に適用されるのと同じ種類の複雑さです。いつそれをより柔軟にするべきか、いつ単純に保つべきかを知る必要があります。何でも一行。
複雑なアルゴリズムは、速度またはスペースのブーストが実際に必要な場合にのみ有効です。25 程度の階乗は基本的に使用されないため、O(1) で実行される凝った階乗アルゴリズムをわざわざ書く必要はありません。ただし、コードが最も内側のループにあり、このコードで 25% のスピードアップを行うとアプリケーション全体が 20% 向上する場合は、それを実行してください。