2

私は最近、既存のデータベース (Oracle) と MVC 4 を使用したプロジェクトを開始しました。すでに多くのコーディングが行われています..しかし、コードには「戦略」はありません..DB -> ORM -> Controller だけです。だから私は、いくつかの DDD 開発テクニックを練習するだけでなく、開発にフレアを追加しようとしています。

いくつかの集約ルートを定義しました。それぞれに、それらの保存と削除 (およびその子) などを処理するリポジトリがあります。これらの集約ルートの 1 つは別の集約ルートへの参照を持ち、「子オブジェクト」を介して処理します。それ。

例:

A Client has one or more purchase orders which has Line Items, 
if a client wants to add a line item to the purchase order, 
it has to go through the purchase order.

それは結構です..クライアント集約ルート、注文書集約ルート。

現在、発注書のステータスを変更するサービスのように、いくつかのサービスも登場しており、発注書ARから負担を取り除きます。注文書のステータス)、(おそらく、それは注文書 AR の一部であるべきでしょうか? 些細なことです..)

リポジトリは現在、データベースからのデータを永続化する仕事を行っており、ARをデータで「埋め尽くし」ています。ARがそれを「保存」すると、リポジトリは、保存が必要なものをすべて保存します。Purchase Order Repository はクライアントARによって使用されるため、クライアントはそこに含まれる可能性のあるすべての発注書をロードできます。うまくいけば、正しい軌道に乗っています。

ここで、MVC に入ります。そのため、いくつかの ViewModel も用意しました。これは基本的に、ユーザーに何を送り出す必要があるかについての表示定義です。Automapper は驚くべきものであることが証明されているので、ビュー モデルに「自動マップ」するだけです。頭脳は必要ありません、完璧です..

今、本当に私を悩ませている実装の詳細..

コントローラーは現在、 Client Factory を介して動作しており、これは Client ARを返します。これは、購入注文リストコントローラーが行う必要があるすべてのことを行うことができます。これは、関連する注文書を管理します (注文書の詳細やこの場合のデータ)。

だから今、私はこれが正しいことを確認したい..私が見る多くの例では、工場ではなくリポジトリで動作するコントローラーがあるため、ARの作成に工場が推奨されているのも見た..例では、コントローラーは集約ルートを処理していますが、「消費者」がARを取得するためにARを照会する必要があるような方法:

お気に入り:

Get the Client Aggregate where the ClientID is 15

またはさらに良い:

get the Client Aggregate, where the ClientID is 15 
and where active purchase orders > 0 ...or something..

次のようになります。

ClientAR = ClientRepository.GetClientByIDAndHasActivePurchaseOrders(15);
resultsImLookingFor = ClientAR.PurchaseOrders(); //or something

この場合、リポジトリは私のニーズに合わせて ClientAR を「満たす」ように感じたので、使用状況に応じて変化するこの ClientAR を手に入れました。匂いがします..

工場から ClientAR を作成してから使用しているだけなので、工場を使用すると「気分が良くなります」。状況に応じて変化するわけではありません。

ClientAR  = ClientFactory.CreateClient(15) // returns a ClientAR 
resultsImLookingFor = ClientAR.GetPurchaseOrdersByStatus(statusID);

または、私はそれを完全に見逃しているので、これを行う必要があります::

ClientAR = ClientRepository.GetClientByID(15, PurchaseOrderSpec)

物事の仕様面が欠けていますか?(この時点では、仕様を実際に進めるには十分ではありません(まだ)、これを機能させる必要があるためです)

私は実装の詳細に行き詰まらないようにしています。もちろん、私のボスマンは私がそれを行う方法についてがらくたを与えないためです..これまでのところ、少なくともDDDについて考えて物事を実装しています(うまくいけば、私は得ていますそれは)、この「パターン」または「考え方」から生じる責任の論理的な「境界」と、テスト可能性で非常に優れていることが証明されています..

それで、私はこれに正しく近づいていますか?それが議論の余地がある場合は、私はそれで大丈夫です..それが単に間違っている場合は、ガイダンスは間違いなく高く評価されます.

前もって感謝します。

4

1 に答える 1

8

だから私は、いくつかの DDD 開発テクニックを練習するだけでなく、開発にフレアを追加しようとしています。

フレアは通常、プロジェクトにとって望ましい品質ではなく、頭字語主導の開発や履歴書主導の開発などにつながる逆効果になる可能性があります。DDD についても同じことが言えます。欠点を理解せずに DDD 戦術パターンを適用しようとしないでください。

これらの集約ルートの 1 つが別の集約ルートを参照しています

AR 間の参照は、可能な限りオブジェクト参照ではなく、ID 参照に制限する必要があります。AR は、最も自然な方法で現実を反映するモデルに必ずしもつながるとは限らない一貫性の境界を定義する必要があります。クライアントと PO の間の関係を表現するには、ID 参照を使用します。PO にはクライアント ID があります。詳細については、Vaughn Vernon による「Effective Aggregate Design 」をご覧ください。

多分それは発注書ARの一部であるべきですか?

エンティティ状態の変更は、エンティティによってカプセル化される必要があります。ドメイン サービスは、その機能が既存のエンティティに自然に適合しないエンティティに機能を提供できます。

リポジトリは現在、データベースからのデータを保持し、AR をデータで「満たす」作業を行っています。AR がそれを「保存」すると、リポジトリは、保存が必要なものをすべて保存します。Purchase Order Repository はクライアント AR によって使用されるため、クライアントはそこに含まれる可能性のあるすべての発注書をロードできます。うまくいけば、正しい軌道に乗っています。

AR、エンティティ、値オブジェクトのいずれも、リポジトリを参照したり、リポジトリのメソッドを呼び出したりしてはなりません。リポジトリは、アプリケーション サービスによって呼び出される必要があります。クライアント AR に PO のコレクションが含まれる可能性は低いです。代わりに、クライアントの PO のリストが PO リポジトリによって提供される必要があります。関係はまだそこにあり、オブジェクト トラバーサルの代わりにリポジトリで実装されているだけです。この理由は、一貫性の境界である AR にまでさかのぼります。

コントローラは現在クライアント ファクトリを介して動作しています

ファクトリは、永続化されたインスタンスにアクセスするためではなく、新しいインスタンスを作成するためにのみ使用する必要があります。これがリポジトリの目的です。プレゼンテーション層 (MVC) は、いくつかの方法で設計できます。典型的な DDD アーキテクチャでは、コントローラーがアプリケーション サービスを参照します。次に、アプリケーション サービスは、リポジトリ、ファクトリ、インフラストラクチャ サービスを調整し、AR で動作を呼び出すことによって、特定のユース ケースを実装します。クライアントが新しい PO を作成するユース ケースがあるとします。コードは次のようになります。

public ActionResult CreatePurchaseOrder(CreatePurchaseOrderViewModel viewModel)
{
   var poData = viewModel.CreatePurchaseOrderData();

   this.purchaseOrderAppService.CreatePurchaseOrder(viewModel.ClientId, poData);

   return RedirectToAction("Index");
}

...

public class PurchaseOrderAppService
{
  readonly IClientRepository clientDb;
  readonly IPurchaseOrderRepository poDb;

  public void CreatePurchaseOrder(int clientId, PurchaseOrderData poData)
  {
     var client = this.clientDb.Get(clientId);

     var purchaseOrder = PurchaseOrderFactor.Create(client, poData);

     this.poDb.Add(purchaseOrder);
     this.poDt.Commit(); // committing of Unit of Work should be moved up to infrastructure level
  }
}

DDD プロジェクトの MVC UI 実装を含むこのDDDSample.Net プロジェクトを見てください。

于 2013-02-06T04:40:20.850 に答える