複雑なドメイン中心のアプリケーションでの基本的なCRUD操作へのDDDアプローチ


9

私の会社はWebアプリケーションをゼロから書き直しています。これは、金融業界で複雑なドメインを持つ大規模なエンタープライズレベルのアプリケーションです。

永続化のためにORM(エンティティフレームワーク)を使用しています。

本質的に、アプリケーションの半分はユーザーから生データを収集して保存することに集中しており、実際のドメインロジックのほとんどを含むアプリケーションの残りの半分はその生データを使用して、元のデータとは大きく異なるドメイン画像を作成します生の入力、およびそれを計算エンジンに渡し、計算を実行し、結果を吐き出し、ユーザーに表示します。

レイヤーを使用したDDDアプローチでは、CRUD操作がドメインレイヤーを通過するように見えます。しかし、少なくとも私たちの場合、これは意味をなさないようです。

たとえば、ユーザーが編集画面に移動して投資口座を変更した場合、画面のフィールドはデータベースに保存されているフィールドそのものであり、後で計算に使用されるドメイン表現ではありません。では、編集画面でデータベース表現(生の入力)が必要なときに、なぜ投資口座のドメイン表現を読み込むのでしょうか。

ユーザーが投資口座画面で[完了]をクリックし、コントローラーに対してPOSTが実行されると、コントローラーには、保存する必要のある投資口座のほぼ正確なデータベース表現が表示されます。しかし、何らかの理由で、コントローラーのモデルをデータベースモデル(エンティティフレームワークモデル)に直接マッピングするのではなく、ドメイン表現をロードして変更を加えることになっていますか?

つまり、本質的には、データモデルをドメインモデルにマッピングします。これにより、永続化するためにデータモデルにマッピングし直すことができます。それはどういう意味ですか?

回答:


9

フォームの投稿をEFオブジェクトに直接マッピングするアカウント作成ページを実装し、それをデータベースに保存するとします。

さらに、データベースにさまざまな制限があり、完全に間違ったデータが入力されるのを防ぐと仮定しましょう。アカウントには常に顧客などがあります

すべてがうまくいくようです。しかし、ビジネスは新しいルールを作ります。

  • 木曜日に作成されたアカウントは、2%のボーナス金利を受け取ります。(金利が口座フィールドの1つであると想定)

ここで、このロジックをどこかに配置する必要があり、それを配置するドメインオブジェクトがありません。

DDDは、常にこの種のルールがあることを前提としています。アカウントの作成には、さまざまなチェック、監査ログなどが必要です。「データベースに行を書き込む」だけではありません。

追加のロジックを含む永続性またはMVCコントローラーがないと想定して、ドメインを計画します。すべての要件をキャプチャ、それらがすべてドメインモデルにあることを確認してください。


3
それはそれを置くのに良い方法です。DBの詳細が混在するビジネスルールを見つけるのは嫌いです。+1
candied_orange 2017

良い点ですが、これらの検証ルールがユーザーの入力の作成および更新中にのみ適用される場合はどうでしょうか?次に、ユーザー入力があると、計算の実行時に作成されるモデルは完全に異なるモデルになります。投資アカウントには2つのドメインモデルが必要ですか?1つはユーザーの生の入力のCRUD操作用で、もう1つは計算で使用されるドメインモデルを作成するためにそれらの入力が使用される場合です。
wired_in

私の質問を混乱させます。完全な例を示す必要があります。ドメインロジックがある場合は、ドメインオブジェクトに配置する必要があります。それdoesntのは、後で最初のものから別のドメインオブジェクトを作成カント意味
ユアン・

複雑な計算エンジンを想像してみてください。計算を実行するために必要な入力の1つは投資勘定ですが、計算エンジンへのすべての投資勘定は、一定期間の収入ストリームです。この投資口座のドメインモデルは、ユーザーがこの投資口座に対して入力した生の入力とは完全に異なります。ただし、ユーザーが名前、現在値などの基本的な入力を入力している場合でも、検証ロジックは必要ですが、計算エンジンが使用するモデルとは関係ありません。それでは、ここに投資アカウントの2つのドメインモデルがありますか?
wired_in

.....またはおそらくドメインに投資口座モデルを持つことはCRUD操作にとって過剰であり、使用されるいくつかのバリデーター属性または何かがあるはずです
Wired_in

7

それはどういう意味ですか?

短い答え:それはしません

より長い答え:ドメインモデルを開発するための重要なパターンは、単なるデータベースであるソリューションの部分には適用されません。

ウディダーハンはこれを明確にするのに役立つかもしれない興味深い観察をしました

Dahanは、サービスにはある種の機能とデータの両方が必要であると考えています。データがない場合、それは単なる関数です。データに対してCRUD操作を実行するだけの場合は、データベースです。

結局のところ、ドメインモデルのポイントは、データへのすべての更新が現在のビジネスの不変を維持することを保証することです。または、言い換えると、ドメインモデルは、記録システムとして機能するデータベースが正しいことを確認する責任があります。

CRUDシステムを扱う場合、通常はデータの記録システムではありません。現実の世界では、レコードの本です、そして、あなたのデータベースは、現実の世界のちょうどローカルにキャッシュされた表現です。

たとえば、メールアドレスや政府発行の識別番号など、ユーザープロファイルに表示されるほとんどの情報には、ビジネスの外部に存在する真実の情報源があります。メールアドレスの割り当てと取り消しは、他人のメール管理者が行うあなたのアプリ。SSNを割り当てるのは政府であり、アプリではありません。

したがって、通常、外部から送られてくるデータに対してドメイン検証を行うことはありません。データが適切に形成され、適切にサニタイズされていることを確認するためのチェックを実施している場合があります。しかし、それはあなたのデータではありません-あなたのドメインモデルは拒否権を取得しません。

レイヤーを使用したDDDアプローチでは、CRUD操作がドメインレイヤーを通過するように見えます。しかし、少なくとも私たちの場合、これは意味をなさないようです。

それは右ケースのためにデータベースがレコードの本です

ワルジーはこのように言いました

ただし、多くのレガシーコードに取り組んでいますが、ドメイン内にあるものと外にあるものを特定するためによくある間違いを観察しています。

データモデルの周りにビジネスロジックがない場合にのみ、アプリケーションをCRUDと見なすことができます。この(まれな)場合でも、データモデルはドメインモデルではありません。これは、ビジネスロジックが関与していないため、それを管理するための抽象化が不要であることを意味し、ドメインモデルがありません。

ドメインモデルを使用して、ドメイン内に属するデータを管理します。ドメイン外のデータはすでに別の場所で管理されています-コピーをキャッシュしているだけです。

グレッグヤングは、記録簿が別の場所(つまり、倉庫の床)にあるソリューションの主要な例として倉庫システムを使用しています。彼が説明する実装は、あなたの実装とよく似ています。ウェアハウスから受信したメッセージをキャプチャする1つの論理データベースと、それらのメッセージの分析から導き出された結論をキャッシュする別の論理データベースです。

では、ここに2つの境界コンテキストがあるのでしょうか?それぞれ異なるモデルのinvestment account

多分。他の荷物と一緒に何が付属するのかはっきりしないので、境界付きのコンテキストとしてタグ付けすることには消極的です。コンテキストが2つある可能性があります。ユビキタス言語にわずかな違いがある1つのコンテキストである可能性があります。

可能なリトマステスト:このスペクトルをカバーするために2人のドメインエキスパートが必要なドメインエキスパートは何人ですか、またはコンポーネントについてさまざまな方法で話す1人のドメインエキスパートだけです。基本的に、コンウェイの法則を逆算することによって、いくつの境界のあるコンテキストを持っているかを推測できる場合があります。

境界のあるコンテキストをサービスに合わせると考えると、より簡単になる可能性があります。これらの2つの機能を個別にデプロイできる必要がありますか?はい、2つの境界のあるコンテキストを提案しています。ただし、同期を保つ必要がある場合は、おそらく1つだけです。


検証とデフォルトのロジックがありますが、投資アカウントの生の入力を作成/更新する場合にのみ適用されます。次に、計算エンジンへの入力として使用する場合、投資勘定のはるかに豊富なモデルを使用します。では、ここに2つの境界コンテキストがあるのでしょうか?投資勘定」の異なるモデルと各
wired_in

数年ぶりに戻ってきたところですが、どういうわけか、今まで以上にあなたのコメントが共鳴しています。ここにはたくさんの良いものがありますが、私に1つ明確にしていただけませんか?「ドメインモデルの要点は、結局のところ、データへのすべての更新が現在のビジネスの不変を維持することを保証することです。」これは、情報を保存/更新するアプリの一部に適用されます。他の部分は単なる計算エンジンです。入力としてデータの表現を取り、結果を吐き出します。それはドメインモデルの一部ではないのですか?保存されたデータには影響しないのですか?
Wired_in

2

あなたのドメインでは、データベースが存在することさえ知る必要はありません。

ドメインはビジネスルールに関するものです。データベースを作った会社が廃業したときに生き残る必要があるもの。つまり、会社を存続させたい場合です。これらのルールが、データの永続化方法を変更したことを気にしない場合は、本当に素晴らしいことです。

データベースの詳細が存在し、対処する必要があります。彼らは別の場所に住むべきです。境界を越えてそれらを置きます。その境界を越えて通信する方法、または境界ではない方法を慎重に制御します。

ボブおじさんはあなたのデータを何に入れるかについてこれを言っています:

通常、境界を越えるデータは単純なデータ構造です。必要に応じて、基本的な構造体または単純なデータ転送オブジェクトを使用できます。または、データを関数呼び出しの引数にすることもできます。または、ハッシュマップにパックしたり、オブジェクトに構築したりできます。

重要なことは、分離された単純なデータ構造が境界を越えて渡されることです。エンティティやデータベースの行をだまして渡したくありません。データ構造に依存関係ルールに違反する依存関係を持たせたくありません。

[…]境界を越えてデータを渡す場合、常に内側の円に最も便利な形式になります。

クリーンなアーキテクチャ

彼はまた、外層が内層へのプラグインであるべきであり、内層が外層の存在さえ知らないようにする方法も説明しています。

きれいなアーキテクチャのチートシート

そのようなものに従うと、入力検証ルール、何らかの方法で入力を永続化する必要があるルール、計算を実行するルール、それらの結果を出力に送信するルールを心配できるデータベースを無視するのに最適な場所があります。この種のコードを読む方が実際には簡単です。

それがそうであるか、あなたのドメインが本当にデータベースを操作するためだけのものであると決めるかです。その場合、ドメイン言語はSQLです。それほど問題ない場合でも、ビジネスルールの実装が永続性の変化に耐えることを期待しないでください。それらを完全に書き換える必要があるでしょう。


私たちはORM(Entity Framework)を使用しているため、データベースはすでに抽象化されていますが、データモデル(Entity Frameworkクラス)は、当然データベーステーブルとほぼ1対1です。問題は、画面が各テキストボックスには、データベース(データモデル)のフィールドでテキストボックスのリストだけである(我々のアプリケーションのいくつかの部分では、ユーザは、本質的に単なるデータモデルを更新していることである。
wired_in

したがって、CRUD操作を実行するときに生データ(データモデル)の表現を使用しない理由はわかりません。計算に使用する複雑なドメイン表現があります。これをドメインモデルと見なしていますが、アプリケーションのCRUD部分にその画像をロードする理由がわかりません。
Wired_in 2017

「生データの表現を使用する」という意味を定義します。データが入力され、データがドメインルールに従って検証され、データが何らかの形で保持され、データが計算され、結果が何にでも出力されます。何か不足していますか?
candied_orange 2017

投資勘定科目のユーザーから取得する生データは、計算に使用する場合のように、アプリケーションの主要部分でその投資勘定科目を表す方法ではないと言いたいのです。たとえば、IsManagedAccountというデータベースに保存するブール入力があるとします。ユーザーは、編集画面のラジオボタンを使用してこれを提供します。したがって、データベースから画面までの表現は1対1になります。ドメインモデルを後でアプリケーションで構築するときに、ManagedAccountクラスが存在する可能性があるため、ブールプロパティはありません。2つの構造は大きく異なります。
wired_in

したがって、ユーザーが編集画面で未加工の入力を編集しているだけの場合、なぜドメインの画像を読み込んで、どうしても厳密に型指定されたManagedAccountクラスをIsManagedAccountを持つ単一のクラスであるフラットな表現にマッピングするために、多くの複雑さを追加するのです。プロパティ?
wired_in

1

DDD理論の適用:

そのドメインには2つの境界コンテキストがあります。

  • 投資勘定の計算。投資勘定の数学モデルは、たぶん集合体の1つの要素です。
  • コアファイナンス。クライアントの投資口座は、エンティティの1つです。

各境界付きコンテキストは、異なるアーキテクチャ設計を持つことができます。

例:

クライアント投資アカウントはエンティティ(多分集合体、ドメインによって異なる)であり、データの永続性はエンティティのリポジトリ(RDBまたはOOデータベースのような他のタイプのDB)を介して作成されます。

CRUD操作に対するDDDアプローチはありません。オブジェクトのデータに関連付けられたDBフィールドを持つことは、設計原則に違反します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.