若いDelphi開発者の戒め
かつて、私は若い開発者を監督する任務を負っていました。 簡単な推奨事項から始めることにしました。 結果はあなたの前にあります。
1短くて明確ではない
- コードを読んでください!
- 誰にとっても読みやすいコードを書く
- コメントではなく、コードが何をするのか書いてください
- 警告とヒントはコンパイルエラーよりも危険です-プロジェクトはそれらを排除せずに構築されます
2開発サイクル
- リーダーによるタスク設定
- 意思決定
- ソリューションを確認
- ソリューションの実装
- コードレビュー
- バージョン管理システムへの配置
3ソースコードの設計
- この点に関しては、プロプライエタリ契約を慎重に遵守する必要があります。プログラマーにとっていかに便利または論理的であるかに関係なく、最後の点に注意してください。 私たちは全員チームとして働いており、設計の混乱が主なもの、つまりコードの可読性を悪化させています。
- 書式が不十分なコードでは、作成者(欠陥を修正するため)とレビューア(欠陥のリストを編集し、修正後に再チェックするため)の両方に余分な時間を費やす必要があるため、登録時間を節約する最善の方法は、最初から正しく行うことです。
4コメント
- プロシージャ、クラスなどの宣言の前のコメントの最初の行 目的を明確にする必要があります。 次の行は、実装の特定の機能について説明しています。
- 仮想メソッドに関するコメントは、実装ではなく呼び出しの状況を記述する必要があります-継承者で重複する可能性があります。
- プロシージャおよびメソッドの本文のコメントは、演算子またはブロックが何をしているのかを説明するのではなく、それが使用されるGOALを示す必要があります。
- 目標の変更は、その実装手段よりもはるかに少ない
- 自分でコードを作成する理由を自分で理解でき、コードが非現実的である理由を理解できます。
5名前の選択
- クラス-必須のプレフィックスTを持ち、会社名(SMS)の形式でオプションの単数名詞。類似した名前のライブラリクラスとプロジェクト(ZVK、プラン)がある場合、クラスが複数のプロジェクトに関与できない場合。
- インターフェース-接頭辞Iを持つ名詞
- 手順-動詞。
- 関数-値を返すときの単数形と複数形-コレクション。 Getプレフィックスは、外部データの受信を目的としたプロパティと関数のメソッドの読み取りに使用され、Isプレフィックスは論理関数に、Createプレフィックスは関数作成に使用されます。 (結果を取得するためだけでなく)アクションを実行するために呼び出される関数は、事実上のものであるため、プロシージャとして呼び出されます。
- プロパティは、配列プロパティを除き、単数形の名詞です。 整数インデックスを持つ配列プロパティの場合、接尾辞がCountのサテライトプロパティが定義されます。 イベントプロパティには、On、Before、またはAfterのプレフィックスが必要です。 プロパティを読み書きするメソッドには、必須のGetおよびSetプレフィックスがあります。
- 仮想メソッド-保護用のDoプレフィックスを使用し、パブリックメソッド用のプレフィックスを使用しない動詞。
- 仮想メソッドの名前は、実装ではなく、呼び出しの目的を反映する必要があります。
6オペレーター
- 演算子の相互のネストの深さは可能な限り小さくする必要があります。深さが大きいと、コードの可読性が大幅に低下します。
- 分岐のネストの深さを減らすには、遷移演算子(gotoを除く)とraiseを使用すると便利です。
- try..finally構造のネストの深さを減らすには、tryの前にクリアされるnilオブジェクトへの割り当てを使用すると便利です。
7カプセル化
- 絶対に必要な場合を除き、使用可能なグローバル変数を使用しないでください。独自の変数を追加しないでください。
- すべてのクラスフィールドはプライベートのみです
- 1つのクラスで1つのタスクを実行し、ストレージ、表示、編集、データベースへの書き込みを組み合わせてはなりません
- 子孫およびクラス外のフィールドへのアクセスは、プロパティを介して行うことができます
- インターフェイスを実装するすべてのメソッドは、必ず保護され、非仮想です
- モジュールの外部で使用されていないものはすべて実装中です
- クラスの使用がプロジェクトの大部分を引っ張る場合、この使用のためのインターフェースを作成し、それをクラスに実装し、インターフェースのみを使用する必要があります
8エラー処理
- エラーの処理には、エラーのみを使用する必要があります。
- 例外はエラー処理にのみ使用する必要があります。
- exceptブロックでは、明示的に処理されないすべての例外を発生させます。
- 例外を例外的に「飲み込む」べきではありません(終了を除く)
- カテゴリ的には、基本クラスの例外の例外をスローしないでください。適切なライブラリがない場合は、定義する必要があります
- ログへの書き込みのみの例外を処理しないでください-これは自動的に行われます。
- 任意の場所で例外が発生する可能性があることを考慮して、コードを記述する必要があります。
- コンストラクタでエラーが発生した場合は常に例外をスローし、デストラクタで例外をスローまたはキャッチすることはありません。デストラクタは常に正しく終了する必要があります。
Delphiでのエラー処理の包括的なソース9デバッグ
- もちろん、コンパイラのすべての警告とヒントを完全に取り除く必要があります。もちろん、それらをオフにすることではありません。
トラブルシューティングに関するDelphiプロジェクトの設定ログファイルの読み方アクセス違反の詳細常にFreeではなくFreeAndNilを常に使用する必要がある理由10リソースリーク
- サブルーチン内で使用されるリソースのいずれかが漏洩する可能性はtry..finallyで排除されますが、リソースはtryの直前にキャプチャされ、リリースは最終的に行われます。
- 作成(キャプチャ)関数でのリソースリークの可能性は、try..exceptの助けを借りて排除されますが、リソースのキャプチャはtryの前に行われ、リリースは例外の後に発生します。
- キャプチャされたリソースへの参照をオブジェクトのフィールドに保存し、部分的に初期化されたオブジェクトを正しく削除するデストラクタを記述することにより、コンストラクタでのリソースリークの可能性が排除されます。 これは、Delphiでオブジェクトが作成された順序によるものです。
- オブジェクトにメモリが割り当てられ、ゼロで埋められます
- 進行中のコンストラクター
- 前の手順で例外がスローされると、デストラクタが呼び出され、占有メモリが解放され、例外が過剰に興奮します。
- リソースがオブジェクトへの参照である場合、デストラクタではそれらにFreeAndNilを使用するだけで十分です
- サブルーチン内では、try..finallyブロックを繰り返しネストする代わりに、同様の手法を使用して、tryの直後に「constructor」を配置し、finallyに「destructor」を配置できます。 ローカル変数は初期化されないため、手動で実行して、試行する前にnilを割り当てる必要があります。
- リソースがクラスとして実装されておらず、繰り返し使用される場合は、リソースがキャプチャされるコンストラクター、およびデストラクタであるリリースでクラスを作成する必要があります。 これにより、リソースの使用がより簡単で一貫性のあるものになり、リークのトラップはメモリリークのトラップに減ります。
リソースリークを検索する漏れの検索、続き11継承、構成、実装、拡張
- 別のクラスを実装するときに1つのクラスの機能が必要な場合、最も簡単な方法は構成を使用することです。たとえば、クラスのフィールドのリストにオブジェクトへの参照を追加します。 制限-新しいクラスは古いクラスのパブリックメンバーのみにアクセスできるため、委任コードを記述する必要があります。
- 既存のクラスがすでに新しい機能の一部を実装している場合、継承を使用できます。 制限は、継承クラスがあらゆる状況で親クラスを完全に置き換える必要があることです。たとえば、TPersistent継承の場合、Assignの正しい実装が必要です。
- 既存のクラスと同じ方法で新しいクラスを使用する必要があるが、動作が完全に異なる必要がある場合は、両方のクラスで実装されるインターフェイスを記述する必要があります。 その結果、クラスは完全に異なる祖先から継承できますが、外部から同じ方法で使用できます。 制限-インターフェイスを介した動作は継承されません。
- コードを妨害することなく、祖先クラスの動作を拡張する必要がある場合(したがって、すべての子孫に一度に新しい機会を与える必要がある場合)、ヘルパーを作成できます。 制限-仮想メソッドと新しいフィールドはありません。プロジェクト内のクラスごとに1つのヘルパー。
- 絶対に必要でない限り、ヘルパーを使用しないでください
12インターフェース
- インターフェイスを使用する場合、リークの心配はありません。
- インターフェイスを実装するメソッドは、非仮想であり、パブリックではなく、通常は保護されている必要があります。
- インターフェースには、少なくとも3つのメソッド(QueryInterface、AddRef、Release)が含まれています。
- これらのメソッドは暗黙的に呼び出されます。1つ目はas操作でインターフェイスへのリンクをキャストすること、2つ目と3つ目はインターフェイスへの新しいリンクを作成して削除する(または可視フィールドを残す)ことです。
- TObjectの子孫とのインターフェイスを実装する場合、上記の3つのメソッドをすべて実装する必要があります。
- 次のクラスの子孫には、QueryInterface、AddRef、およびReleaseのデフォルト実装があります。
- TInterfacedObjectは、クラスインターフェイスへのリンクがない場合に自動削除を実装するため、その子孫は作成後すぐにインターフェイスリンクにキャストする必要があります。
- TComponentは、実装されたインターフェイスへのリンクを無視し、手動でのみ削除されるため、その子孫を削除した後、インターフェイスへのダングリングリンクがないことを確認する必要があります。
13ビジュアルコンポーネント
- フレームとフォームには、ユーザーコマンドを表示および送信するロジック(実行しない!)以外のロジックを含めないでください。
- ユーザーコマンドのすべての可能なバリアントは、アクションの形式で実行され、このコマンドが使用可能な同じフレーム内の1つのActionListに配置される必要があります。
- 自動的に作成されたDelphiコンポーネント名は、メソッドコードで参照されておらず、ハンドラーがないものにのみ残すことができます。 このコンポーネントの最初のハンドラーを作成する前に、意味のある名前を設定する必要があります。設定しない場合、ハンドラー名を手動で編集する必要があります。
- 自動生成されたハンドラー名は、どうしても必要な場合にのみ変更してください。
- ビジュアルコンポーネントのイベントハンドラは、5行を超えてはなりません。 ハンドラーメソッドに関するコメントは、呼び出しの状況(ハンドラーの名前からわかる)だけでなく、まずその目的-このハンドラーが必要な理由を説明する必要があります。
14モジュール
- 複数のプロジェクトで使用されるモジュールは、ライブラリモジュールです。
- 定数、インターフェイス、タイプ(クラスではない)、例外、および補助プロシージャのみを含むモジュールは、インターフェイスモジュールです。
- ユーザー、データベースファイルシステムとデータを交換するためのコードを含むモジュール。 ネットワークなど -入出力モジュール。
- 他のすべてのモジュールは論理モジュールです。
- モジュール間の依存関係の理想的な構造:インターフェイスモジュールはインターフェイスのみに依存します。 論理モジュール-インターフェイスおよび他の論理モジュールからのみ。 入出力モジュール-インターフェイスおよびその他の入出力モジュールからのみ。 これにより、ロジックの単体テストを効果的に使用し、プロジェクトのさまざまな部分の実装を互いに独立して変更できます。
15不要な依存関係の削除
- パブリックグローバル変数からの依存関係は最悪です。少なくとも変数を関数に変換することは避けてください
- プライベートグローバル変数から-モジュール内の問題をローカライズするため、少し改善されています。 マルチスレッドの変更および初期化完了の可能性を監視する必要があります。 たとえば、グローバルインターフェイス変数の場合、モジュールをファイナライズすると、Releaseが暗黙的に呼び出されます。
- インターフェースモジュールから-絶対に必要でない限り、何も変更する必要はありません。
- 他のモジュールの入出力(GUI、データベース、アプリケーションサーバーとの通信など)のグローバルクラス、プロシージャ、および関数から。 プロジェクトモジュール自体がI / Oを対象としている場合は、何も変更する必要はありません。そうでない場合は、インターフェイスを介してこの通信を実装することでそれを削除することをお勧めします。
- リンクがあるモジュールからインターフェース部分を選択し、それだけを参照することにより、上記を含むモジュールを取り除く方が良いです。
- ライブラリまたは汎用モジュールのコンテンツから-緊急なしで、何も変更する必要はありません。
Source: https://habr.com/ru/post/J104377/
All Articles