残念ながら、多くの場合、作成者は、詳細な説明に進むことなく、プロジェクトの1%にせいぜい必要な多層アーキテクチャの到達不可能な高さに登るか、「コードを明確にする」または「OOPとパターンを使用する」などの一般的なフレーズに制限されています。たとえば、コードの「わかりやすさ」が測定されます。
この記事では、コードの品質を評価するための基準、およびサイズと特異性、使用するプログラミング言語、およびその他の要因にほとんど関係なく、実際のプロジェクトに適用することができる記述方法を体系化することを試みます。
1.シンプルさ
私たちの前ですべてがすでに発明されています-素晴らしいKISSの原則と、アルバートアインシュタインの格言「すべてはできるだけシンプルに、しかし簡単ではない」と言われています。
単純なコードはあらゆる点で複雑なものよりも優れています-理解しやすく、修正とテストが簡単で、コメントとドキュメントが少なくて済み、エラーが少なくなります(統計的にのみ、言語の数とコードの論理構造の数に関してエラーの平均数をとると、特定のプログラマーごとに一定の値)。
また、理想的なシステムでのTRIZの立場を言い換えると、理想的なコードは存在しないものであり、解決しなければならないタスクは正常に解決されたと言えます。 明らかに、この理想は(他のような)実際には達成不可能ですが、開発者の心を正しい方向に向けることができます。
実際には、これらの美しいフレーズはすべて1つのことを意味します。コードを複雑化し難読化することによる損害を超えない実際の (仮説ではない)ツールを使用しないでください。 解決に役立つ1つの狭いタスクのために、フレームワーク全体にアプリケーションを構築しないでください。 単純なクラスでできる複雑なパターンは使用しないでください。 コード内のネイティブオブジェクトのプロパティでも機能しないペアの関数にクラスを使用しないでください(使用しない場合)。 アプリケーションの他の場所で再利用されていない関数で3行のコードをラップしないでください(150年後ではなく、近い将来使用されません)。
もちろん、これはすべて、5000行の命令型スタイルでスパゲッティコードを記述する必要があるという意味ではありません。 そのような欲求が生じたらすぐに、コードを「 できるだけ単純だが単純ではない」という、上記の引用の2番目の部分を読み直して理解する必要があります。
問題を解決できるのであれば、単純な設計を恐れる必要はありません。 また、プロジェクトを開発したり、顧客の要望を1、2年で変えたりするときに、コードが理論的にどのように使用されるかについての考えを隠さないでください。 シンプルかつ迅速な開発の支持者の多くが主張するように、コードが「とにかく破棄され、ゼロから書き直される」ことすらありません。 おそらくそうではないでしょう。 しかし、問題は、高い確率では、単純に正しい方向を推測できないことです。 (ファイルを少し修正した後)ねじをねじることができるようにハンマーを設計しますが、スイング時に釘とレーザーガイダンスの自動送りを締める必要があることがわかります。 そして、特定の方向の開発のために設計されたアーキテクチャは、「単なるハンマー」と比較して失われるだけです。 私を信じて、私は私が話していることを知っています、なぜなら 5年間、私はRunetでプロジェクトをサポートしてきました。このプロジェクトは、最大の労力が費やされた場所や作成されたものではなく、「サイド」機能の小さなブランチが原因で大きく成長しました。
2.概念
この基準は、コードの「単純さ」と大部分が交差していますが、それでも別のセクションに入れることにしました。 このアプローチの本質は、概念の使用であり、理想的には、他のソリューションですでに広く使用されている一般に受け入れられている概念です。
私が意味することを簡単なアナロジーで説明させてください。
あなたがタスクを持っていると想像してください-2から9までのすべての数を互いに乗算した結果を記憶すること。 2x2 = 4、2x3 = 6、...、3x7 = 21、...などの行を入力して、このテキストを暗記し始めることができます。
正式には、これは使用でき、学習することもできます。 しかし、はるかに実用的なオプションがあります-「テーブル」の概念を使用する-つまり XとYの値のリストを定義するデータ構造。あらかじめ定義された式(この場合はZ = X * Y)を使用して、交差点とこれらの点の値をすばやく決定できます。 その結果、子供の頃から全員に知られている乗算表が得られます。これは、テキストの文字数の平凡な経済に加えて、他のいくつかの利点があります。
- 構造認識 -乗算自体の結果に加えて、脳は他の多くの有用な情報を受け取ります-数字ごとに、それ自体による乗算を含む同じ量の結果があり、列を下に移動するときに積を増やすステップはこの列の見出しの数に等しいという文字列についても同様)など
- スケーリングの容易さ -手元にテーブルを持ち、その概念を理解すると、たとえば1から20までの数値に対してスケーリングするよりも簡単なことはありません。
- 変更の容易さ -乗算表を加算、除算、または他の表に変換することも非常に簡単です。 使用されている基本概念により、アーキテクチャを変更せずに特定の制限内で製品プロパティを簡単に変更できます。
この方法でテーブルを「機能させる」ために追加の努力をする必要はなく、また「テーブルを使用するための指示」をドキュメントに添付する必要もないことに注意してください。これはプログラミングで概念を使用する主な強みです。 概念を適切に使用するソリューションは、しばしばエレガントと呼ばれます。
すばらしい概念の例は、 UNIXシステムの「リダイレクト」です 。これにより、ファイルや他のストリームの読み取り/書き込み、またはテキストフィルターなどの他のプログラムとのやり取りに1行のコードを費やすことなく、さまざまなプログラムを作成できますgrep。 必要なのは、標準のテキスト入力/出力インターフェイスを提供することだけです。
したがって、最も人気のある数十のチームでさえ、その使用のために数千のオプションを生成します。 何かを思い出させますか? そうです-これは、「存在しないコード」を使用した問題の解決策です。
より簡単な実用的な例-ある広告サイトサイトの2つの異なるアカウントからサードパーティの広告ネットワークの広告をローテーションする必要がありましたが、それらの間の利益分配はほぼ等しい(許容偏差1〜2%)という条件で。 「額」に適用できる面倒な解決策は、データベースの各アカウントの広告インプレッションを、これらのインプレッションのコスト(異なる場合もあります)を考慮して記録し、ページを開くたびにこれらのデータに基づいて不均衡を最小限に抑えるために表示する広告の決定。
少し後に、多数の法則によると、アカウントを選択する際の「ヘッドテール」の原則に関する通常の確率チェックが、与えられた条件内で問題を完全に解決することが判明しました。 また、この方法では、3つ以上のアカウント間でインプレッションを分配するのに問題はありません。 もちろん、これは人によって発明された概念ではなく、基本的な数学的原理ですが、コードの観点から、重要なことはただ1つです。それは機能します。
3.機能の一意性(繰り返さないでください)
「自分自身を繰り返さない」という原則(DRYと略記)は、システムの各機能単位が、コードの論理ブロック、関数、またはクラス全体であるかどうかに関係なく、コードで1回だけ表現する必要があることを示しています。
重複したコードブロックは通常、関数でレンダリングされます。 関数は、プラグ可能なライブラリと名前空間を使用します。 クラスに関しては、些細な継承から、多くの場合より多くのコードと精神的な努力を必要とする「工場を製造する工場」から「工場を生産する工場」までの洗練されたシステムまでプログラマー、保存より。
繰り返しを避けるような方法でコードを設計するという当初からの欲求は、明らかに破壊的です。 80%の状況では、コードを記述するまでコードの重複について知ることができません。
すべてのプロジェクトで実際に使用するための本当のアドバイスは、コードの重複の問題を検出した直後に解決することです(ただし、それ以前ではありません!)。
5〜10行の非常によく似たコードブロックがいくつかあり、いくつかの条件と変数のみが異なりますが、それらを関数でラップする最善の方法はまだわかりません。 ループを使用します。
新しいメソッドのコードを配置するクラス/オブジェクトがわからない? 開発中のシステムに関するより完全な情報が得られるまで、関数を作成してプラグインライブラリに配置するだけです。
クラス継承を使用しますが、1つの論理構造を変更するために、継承者で50行のメソッドを完全に再定義する必要がありますか? まず、大規模なメソッドをいくつかの分離されたメソッドに分割すること、または他のクラスのインスタンスをすべてのメソッドとともに元のオブジェクトのプロパティ値として使用することを検討してください。
シンプルで実績のあるソリューションは、コードの重複に関するすべての問題の95%を解決します。残りの5%については、コードの「悪い」セクションの意味のある再設計と比較して、教科書の複雑な構造を機械的に適用する可能性について10回考える必要があります読みやすさの向上)。
単純なソリューションをいつでも上位レベルのソリューションに置き換えることができます。また、システム全体に重複が既に散在している場合、後の段階で複雑なリファクタリングを生コードに適用するよりもはるかに簡単です。
4.読みやすさ
- 変数の名前の本質を最もよく表す変数、関数、クラス、およびメソッドの名前を使用します。 単一文字の変数(おそらく、i、n、k型のループカウンターを除く)、およびvar1、function2などの名前を避けます。 CreateTextDocumentWithAttachedFilesViaHTTPのような名前など、極端に急がないでください。読みやすさもそれほど向上しません。 最適なタイトルの長さ:1-3ワード。
- 関数とメソッドの名前、およびそれらの引数と戻り値の構造に一貫性を持たせるようにしてください。 PHP開発者の間違いを繰り返さないでください(例として、配列を操作する関数の名前はarray_filter、preg_grep、array_unique、in_array、sort、currentなどです)
- マジックナンバーを使用しないでください。 例外は1つだけです。このコードが表示されるのはあなた以外の誰もいないことは150%確信しており、数年後には自分でそのサポートを受け入れることはありません。
- 言語構造を互いに分離するときに、スペースと改行を節約しないでください。 文学英語(ロシア語など)では、コンマの後にテキストをスペースで区切り、段落を空行で区切るのが慣習であることに注意してください。 同じ規則がプログラムコードに適用されます。
- 利用可能な最も簡潔な標準言語構成を使用します。 たとえば、1行に収まるコードブロックのif-elseの代わりに三項演算子。 コードが競争に備えていない限り、大部分の開発者に知られていない非標準的な方法で演算子を使用しないでください。
- コードの明白でないセクションにコメントしてください。 明白なことにコメントしないでください。 内部の「エビデンスの決定要因」を訓練するために、月に一度、同僚や少なくとも馴染みのあるプログラマーにコードを見せることができます。
もちろん、コード自体の優れた設計は、プログラムの品質とその認識の容易さを保証しません。 しかし、まさにそのような細部へのこだわりが、真のプロと「多分それが合う」スタイルで働くシンプルな職人を区別しています。
結論として何を言えますか
この記事は計画よりもややボリュームがありましたが、 接続性や接続性 、 デザインパターン 、本全体がすでに書かれている他の概念など、多くの側面については慎重に議論することを避けましたが、多くの新しいものを書くことができます。
私の目標は、「正しい」(私の観点から)プログラミングの非常に基本的なことを詳細に述べることでした。その多くは、Captain Evidenceのペンにふさわしく、それにもかかわらず、特にWebセグメントでは、ほとんどの開発者によって定期的に無視されています。 完璧主義のジャングルに深く入り込むことなく、これらの簡単な基本のみに準拠することで、あらゆる方法でコードを改善することができます。
私が何かを見逃したか、どこかで間違えられた場合-コメントの建設的な批判が強く推奨されます。