11

保守性を高めるために Delphi プログラムを構築する方法についてアドバイスを求めています。私は、Turbo Pascal でプログラミングすることを初めて学びましたが、ほとんどが C/C++ で数十年過ごした後、Delphi プログラミングを始めました。基本的な言語に違和感はありません。以前の C++ と C# の経験では、cxxtest と NUnit を使用して TDD に変換しました。

私はこのプログラムを継承し、現在は私が保守を担当しています。主にフォームといくつかのデータモジュールで構成されています。アプリケーションのビジネス ロジックとデータ アクセスは主にフォームに散らばっており、データ モジュールはほとんどグローバル ADO オブジェクトが存在する場所にすぎません。データベースへのアクセスは、通常、TADOQuery または TADOCommand のグローバル インスタンスを参照し、SQL テキストをオブジェクトの関連するプロパティにフォーマットし、その Open または Execute メソッドを呼び出すことによって行われます。

ビジネス ロジックをある程度カプセル化して、単体テストできるようにしようとしています。私はこの答えを見てきましたが、フォームからロジックを抽象化する限り、それは完全に理にかなっています。データ アクセスのベスト プラクティスとは何か疑問に思っています。私の考えでは、データ モジュールは一種のアプリ固有のミニ API (おそらくすべての仮想メソッド) を公開して、テスト用のモック オブジェクトに置き換えることができるようにする必要があります。この他の回答のリンクは、私が正しい方向に進んでいると確信させるいくつかの例を示していますが、それでも、データ モジュールに関する何らかのベスト プラクティス ドキュメントを見ることに興味があります。私が Google で見つけたページのほとんどは、データ バインドされたコントロールをクエリに接続することで設計時に実行できるすべてのクールなことについて、同じ種類の例を示していますが、あまり興味はありません。この時点で。

4

4 に答える 4

8

個人的に私はTDataModuleのファンではありません。優れたオブジェクト指向設計の原則を奨励することはほとんどありません。それが使用されたのがDBコンポーネントの便利なコンテナだけだったとしたら、それは1つのことですが、あまりにも頻繁に、ドメイン層でより適切なビジネスロジックのダンプグラウンドになります。これが起こると、それは最終的に神クラスと依存関係の磁石になります。

これに、フォームの前に開かれていないユニットにデータソースが配置されている場合に、フォームのデータ対応コントロールがデータソースを失う原因となる少なくともDelphi 2以降も存在し続けるバグ(またはその機能)を追加します。 。

私のおすすめ

  • UIとデータベースの間にドメインレイヤーを追加します
  • 可能な限り多くのビジネスロジックをドメインオブジェクトにプッシュします。
  • デザインアーキテクチャパターンを使用して意思決定をドメインレイヤーに委任することにより、UIとデータ永続性レイヤーを可能な限り浅くします。

あなたがそれに精通していない場合、この技術はドメイン駆動設計と呼ばれます。それは確かに唯一の解決策ではありませんが、それは良い解決策です。基本的な前提は、UI、ビジネスロジック、およびデータベースがさまざまな速度でさまざまな理由で変更されることです。したがって、ビジネスロジックを問題のあるドメインのモデルにし、UIやデータベースから分離してください。

これにより、コードがよりテストしやすくなりますか?

ビジネスロジックを独自のレイヤーに移動することで、UIまたはデータベースからの干渉なしにビジネスロジックをテストできます。これは、コードを独自のレイヤーに配置したからといって、コードが本質的にテスト可能になるという意味ではありません。レガシーコードをテスト可能にするのは難しい作業です。ほとんどのレガシーコードは緊密に結合されているため、明確に定義された責任を持つクラスにコードを分解するのにかなりの時間を費やします。

これはDelphiスタイルですか?

それはあなたの視点に依存します。従来、ほとんどのDelphiアプリケーションは、UIとデータベースを連携して開発することによって作成されていました。フォームデザイナにいくつかのdb対応コントロールをドロップします。コントロールのデータを格納するフィールドを持つテーブルを追加/更新します。イベントハンドラーを使用して、大量のビジネスロジックを振りかけます。ビオラ!アプリケーションをベイクしました。非常に小さなアプリケーションの場合、これは大幅な時間の節約になります。しかし、自分自身をからかうことはできません。小さなアプリケーションは大きなアプリケーションに変わる傾向があり、この設計は持続不可能なメンテナンスの悪夢になります。

これは本当に言語のせいではありません。何百ものVB、C#、およびJavaショップから、同じクイック/ダーティ/近視眼的なデザインを見つけることができます。これらの種類のアプリケーションは、よく知らない初心者の開発者(および、よく知っているはずの経験豊富な開発者)の結果であり、IDEを使用すると、作業が非常に簡単になり、仕事をすばやく終わらせることができます。

Delphiコミュニティには(他のコミュニティと同様に)、より優れた設計手法を長い間提唱してきた人々がいます。

于 2011-02-15T19:40:44.297 に答える
7

現在の ADO データセット オブジェクトの代わりに使用できるモック データセット (クエリ、テーブルなど) コンポーネントが必要だと思います (実際、ほとんどの Delphi データベース開発者は必要になるでしょう)。テスト目的で、このモック データセットに。置換機能を提供する 1 つの方法であるインターフェイスを設計に強制する代わりに、Liskov 置換原理により、(テスト フィクスチャのセットアップ時に) データ モジュールにモックのセットを注入できるはずであるという事実を考慮してください。 -使用したいデータセット。テストの実行時に、使用している ADO データセットを、機能的に同等の他のエンティティ (モック データセット、またはファイルに基づくテーブル データセット) に置き換えるだけです。

データ モジュールからデータセットを完全に削除し、実行時に (メイン アプリケーションで) 正しい ADO データセット オブジェクトに接続し、単体テストでモック データセットをアタッチすることもできます。

ADO データセットを作成していないため、ユニット テストを行う必要はありません。ただし、そのようなデータセットのモックアップは難しい場合があります。

JvCsvDataSet または ClientDataSet をフィクスチャ (モック) データセットのベースとして使用することを検討することをお勧めします。これらを使用して、すべてのデータベース プラットフォームの依存関係 (リモート プロシージャまたはデータベース SQL を記述するもの) が他のクラスに抽象化されていることを確認できます。これもモックアップする必要があります。このような取り組みは、ビジネス ロジック ユニットをテスト可能にするために必要なだけでなく、ビジネス ロジックで複数のデータベース プラットフォームに対応するためのステップとなる可能性もあります。

CustomerQuery という ADOQuery があるとします。データ モジュールにドロップしたオブジェクトの名前を CustomerQueryImpl に変更し、これをデータ モジュール クラス宣言に追加します。

  private
        FCustomerQuery:TADOQuery;

  published
        property CustomerQuery:TADOQuery read FCustomerQuery write FCustomerQuery;

次に、create イベントのデータ モジュールで、プロパティをオブジェクトに接続します。

   FCustomerQuery := CustomerQueryImpl

これで、実行時に CustomerQuery を「フック」して独自のテスト フィクスチャ (モック オブジェクト) に置き換える単体テストを作成できるようになりました。

于 2011-02-11T18:34:57.570 に答える
4

まず、何かを変更する前に、いくつかの単体テストが必要です。これにより、何も壊れていないことを確認できます。何も変更せずに、現在の GUI に対して単体テストを作成しようとします。DUnitは (従来の単体テストに加えて) GUI テストをサポートしており、少しぎこちなく、モーダル ダイアログを処理できませんが、機能します。

次に、あなたのフォームはデータ認識コントロールを使用していないので、フォームと既存のグローバル データ モジュールの間に、データ モジュールの別のレイヤー、場合によってはサービス レイヤーを導入することでこれに取り組みます。

アプリケーションのすべてのフォームに対して、対応する新しいサービス層データ モジュールを作成します。これは多くのデータ モジュールのように聞こえるかもしれませんが、非常に軽量であり、必要に応じて後で統合することができます。

必要に応じて、サービス層に TDataModule ではなく通常の TObject を使用することもできますが、データ モジュールを使用すると、非ビジュアル コンポーネントを後で配置できる柔軟性が得られます。後日、ルートを制御します。

最初は、各サービス層のデータ モジュールは、グローバル データ モジュールにアクセスするためのプロキシとして機能するだけでした。この時点での目標は、グローバル データ モジュールに対するフォームの直接的な依存関係を取り除くことです。

フォームがサービス層のデータ モジュールを介してグローバル データ モジュールに間接的にのみアクセスしたら、機能をフォームからサービス層に移動し始めます。サービス レイヤー データ モジュールのこの機能を使用すると、新規および既存のコードの単体テストを簡単に作成できることがわかります。

この時点で、フォームごとのサービス レイヤー データ モジュールの統合を開始することもできます。フォームからのロジックの抽出が完了した後でそれらを統合する方が、そのプロセス中に行うよりもはるかに簡単です。

于 2011-02-11T23:00:25.790 に答える
0

モック オブジェクトの理論、UT のローカライズ、インターフェイスの発見など、単体テストとモック オブジェクトに関する記事をお読みください。

楽しんでくれると良いです。

于 2011-02-11T20:54:22.790 に答える