web-dev-qa-db-ja.com

サービスは常にDTOを返す必要がありますか、それともドメインモデルを返すことができますか?

私は大規模なアプリケーションを(再)設計しています。DDDに基づくマルチレイヤーアーキテクチャを使用しています。

データレイヤー(リポジトリの実装)、ドメインレイヤー(ドメインモデルとインターフェイスの定義-リポジトリ、サービス、作業単位)、サービスレイヤー(サービスの実装)を備えたMVCがあります。これまでのところ、すべてのレイヤーでドメインモデル(主にエンティティ)を使用し、ビューモデルとしてのみDTOを使用しています(コントローラーでは、サービスはドメインモデルを返し、コントローラーはビューに渡されるビューモデルを作成します)。

DTOのマッピングと受け渡しについての記事を読んでいます。明確な答えはないことは理解していますが、ドメインモデルをサービスからコントローラーに返すかどうかはわかりません。ドメインモデルを返す場合、ビューに渡されることはありません。これは、コントローラーが常にビュー固有のビューモデルを作成するためです。この場合、正当なようです。一方、ドメインモデルがビジネスレイヤー(サービスレイヤー)を離れるのは適切ではありません。サービスは、ドメインで定義されていないデータオブジェクトを返す必要がある場合があり、その後、マッピングされていないドメインに新しいオブジェクトを追加するか、POCOオブジェクトを作成する必要があります(一部のサービスはドメインモデルを返すため、 DTOを効果的に返します)。

問題は、ビューモデルを厳密に使用する場合、ドメインモデルをコントローラーに戻すことは問題ないか、またはサービスレイヤーとの通信に常にDTOを使用する必要があるかということです。その場合、必要なサービスに基づいてドメインモデルを調整しても問題ありませんか? (率直に言って、サービスはドメインが持っているものを消費する必要があるため、そうは思わない。)厳密にDTOに固執する必要がある場合、それらはサービス層で定義されるべきか? (そうだと思います。)DTOを使用する必要があることは明らかです(たとえば、サービスが多くのビジネスロジックを実行し、新しいオブジェクトを作成するとき)。 s)-ドメインモデルと同じDTOを作成するのはあまり意味がないように思われます)-一貫性と優れた実践を好みます。

記事 ドメインvs DTO vs ViewModel-それらを使用する方法とタイミング? (および他の記事も)私の問題に非常に似ていますが、この質問には答えていません。記事 EFでリポジトリパターンにDTOを実装する必要がありますか? も同様ですが、DDDを処理しません。

免責事項:存在し、派手なためだけにデザインパターンを使用するつもりはありませんが、一方で、アプリケーション全体の設計に役立ち、分離に役立つので、良いデザインパターンとプラクティスを使用したいと思います特定のパターンを使用しても、少なくとも現時点では「必要」ではありません。

いつものように、ありがとう。

129
Robert Goldwein

ドメインモデルがビジネスレイヤー(サービスレイヤー)を離れるとき、適切に感じられない

勇気を出しているように感じますか? Martin Fowlerによると、サービス層はアプリケーションの境界を定義し、ドメインをカプセル化します。つまり、ドメインを保護します。

ドメインで定義されていないデータオブジェクトを返す必要がある場合があります

このデータオブジェクトの例を提供できますか?

厳密にDTOに固執する必要がある場合、サービス層で定義する必要がありますか?

はい、応答はサービスレイヤーの一部であるためです。 「どこか別の場所」と定義されている場合、サービスレイヤーはその「どこかほかの場所」を参照し、ラザニアに新しいレイヤーを追加する必要があります。

ドメインモデルをコントローラーに返すことは問題ありませんか、またはサービスレイヤーとの通信に常にDTOを使用する必要がありますか?

DTOは応答/要求オブジェクトであり、通信に使用すると意味があります。プレゼンテーションレイヤー(MVC-Controllers/View、WebForms、ConsoleApp)でドメインモデルを使用する場合、プレゼンテーションレイヤーはドメインに密結合されます。ドメインを変更するには、コントローラーを変更する必要があります。

ドメインモデルと同じDTOを作成することはあまり意味がないようです)

これは、新しい目にとってDTOの欠点の1つです。今、あなたはコードの複製を考えていますが、プロジェクトが拡大すると、特に異なるチームがいるチーム環境で、それははるかに理にかなっています異なるレイヤーに割り当てられます。

DTOはアプリケーションに複雑さを追加する可能性がありますが、レイヤーも同様です。 DTOはシステムの高価な機能であり、無料ではありません。

DTOを使用する理由

この記事では、DTOを使用するメリットとデメリットの両方を提供します http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html

次のような要約:

使用する場合

  • 大規模プロジェクト向け。
  • プロジェクトの有効期間は10年以上です。
  • 戦略的でミッションクリティカルなアプリケーション。
  • 大規模なチーム(5つ以上)
  • 開発者は地理的に分散しています。
  • ドメインとプレゼンテーションは異なります。
  • オーバーヘッドデータ交換の削減(DTOの本来の目的)

使用しない場合

  • 中小規模のプロジェクト(最大5メンバー)
  • プロジェクトの有効期間は2年程度です。
  • GUI、バックエンドなどの個別のチームはありません。

DTOに対する引数

DTOを使用した引数

  • DTOがなければ、プレゼンテーションとドメインは密接に結合されます。 (これは小さなプロジェクトには問題ありません。)
  • インターフェイス/ APIの安定性
  • 絶対に必要な属性のみを含むDTOを返すことにより、プレゼンテーション層の最適化を提供する場合があります。 linq-projection を使用すると、エンティティ全体をプルする必要はありません。
  • 開発コストを削減するには、コード生成ツールを使用します
133
Yorro

私の経験では、実用的なことをすべきです。 「最高のデザインとは、最もシンプルなデザインです」-アインシュタイン。それは心です...

ビューモデルを厳密に使用する場合、ドメインモデルをコントローラーに返すことは問題ありませんか、またはサービスレイヤーとの通信に常にDTOを使用する必要がありますか?

絶対に大丈夫です!ドメインエンティティ、DTO、およびビューモデルがある場合、データベーステーブルを含めると、アプリケーションのすべてのフィールドが4か所で繰り返されます。ドメインエンティティとビューモデルがうまく機能する大規模なプロジェクトに取り組んできました。これに対する唯一の例外は、アプリケーションが分散されており、サービス層が別のサーバーに存在する場合です。この場合、DTOはシリアル化の理由で回線を介して送信する必要があります。

その場合、必要なサービスに基づいてドメインモデルを調整しても問題ありませんか? (率直に言って、サービスはドメインが持っているものを消費するはずなので、そうは思いません。)

ドメインモデルは通常、ビジネスロジックを反映したものであり、通常はそのロジックの消費者によって形作られないため、私は同意し、ノーと言います。

DTOのみに固執する必要がある場合、それらをサービス層で定義する必要がありますか? (私はそう思う。)

あなたがそれらを使用することに決めた場合、私は同意し、はいと言います、それは一日の終わりにDTOを返すので、サービス層は完璧な場所です。

幸運を!

9
Justin Ricketts

DDDアプローチを採用することにしたので、アプリケーションは十分に大きく複雑なようです。サービス層のpocoエンティティまたはいわゆるドメインエンティティと値オブジェクトを返さないでください。これを行うには、サービスレイヤーが不要になったので削除してください!ビューモデルまたはデータ転送オブジェクトは、ドメインモデルメンバーにマップする必要があるため、サービス層に存在する必要があります。では、なぜDTOが必要なのですか?多数のシナリオを持つ複雑なアプリケーションでは、ドメインとプレゼンテーションビューの懸念を分離する必要があります。ドメインモデルはいくつかのDTOに分割でき、いくつかのドメインモデルはDTOにまとめることができます。したがって、モデルと同じであっても、レイヤードアーキテクチャでDTOを作成することをお勧めします。

サービスレイヤーとの通信には常にDTOを使用する必要がありますか?はい、ドメインモデルメンバーとサービスレイヤーのリポジトリと通信し、それらをDTOにマッピングして返すため、サービスレイヤーごとにDTOを返す必要がありますMVCコントローラーへ、またはその逆。

必要なサービスに基づいてドメインモデルを調整しても大丈夫ですか?サービスはリポジトリおよびドメインメソッドとドメインサービスと通信するだけで、ニーズに基づいてドメイン内のビジネスを解決する必要があります。必要なものをドメインに伝えるタスク。

DTOのみに固執する必要がある場合は、サービスレイヤーで定義する必要がありますか?はい、サービスレイヤーのドメインメンバーにマップする必要があるため、DTOまたはViewModelを後でインサービスにしてみてください。アプリケーションのコントローラーにDTOを配置するアイデア(サービス層で Request Response パターンを使用してみてください)、乾杯!

7
Ehsan

これまでのところ、すべてのレイヤーでドメインモデル(主にエンティティ)を使用し、ビューモデルとしてのみDTOを使用します(コントローラーでは、サービスはドメインモデルを返し、コントローラーはビューに渡されるビューモデルを作成します)。

ドメインモデルはアプリケーション全体に対して用語( ユビキタス言語 )を提供するため、ドメインモデルを広く使用することをお勧めします。

ViewModels/DTOを使用する唯一の理由は、アプリケーションでView(あらゆる種類のプレゼンテーションレイヤー)とModel(ドメインモデル)を分離するための MVCパターン の実装です。この場合、プレゼンテーションとドメインモデルは疎結合です。

サービスは、ドメインで定義されていないデータオブジェクトを返す必要がある場合があり、その後、マッピングされていないドメインに新しいオブジェクトを追加するか、POCOオブジェクトを作成する必要があります(一部のサービスはドメインモデルを返すため、 DTOを効果的に返します)。

アプリケーション/ビジネス/ドメインロジックサービスについてお話しすると思います。

可能な場合は、ドメインエンティティを返すことをお勧めします。追加情報を返す必要がある場合、複数のドメインエンティティを保持するDTOを返すことは許容されます。

ドメインエンティティ上でプロキシを生成する第3部のフレームワークを使用するユーザーは、ドメインエンティティをサービスから公開するのが困難な場合がありますが、それは使用方法が間違っているだけです。

問題は、ビューモデルを厳密に使用する場合、ドメインモデルをコントローラーに戻すことは問題ないか、またはサービスレイヤーとの通信に常にDTOを使用する必要があるかということです。

99,9%の場合にドメインエンティティを返すだけで十分だと思います。

DTOの作成とそれらへのドメインエンティティのマッピングを簡素化するために、 AutoMapper を使用できます。

3
Ilya Palkin

次の2つの質問を分析することをお勧めします。

  1. 上位レイヤー(つまり、ビューとビューのモデル/コントローラー)は、ドメインレイヤーが公開するのとは異なる方法でデータを消費していますか?多くのマッピングが行われている場合、またはロジックが関係している場合は、デザインを再検討することをお勧めします。データの実際の使用方法に近いはずです。

  2. 上位レイヤーを深く変更する可能性はどのくらいありますか? (例:ASP.NET for WPFの交換)。これが非常に異なり、アーキテクチャがそれほど複雑でない場合は、できるだけ多くのドメインエンティティを公開した方がよい場合があります。

私はそれが非常に広範なトピックであり、それが実際にあなたのシステムがどれほど複雑で、その要件であるかを恐れています。

2
jnovo

私はこのパーティーに遅れていますが、これは非常にありふれた重要な質問であり、私は応答を強いられたと感じました。

「サービス」とは、Evanが ブルーブック で説明している「アプリケーション層」を意味しますか?私はあなたがそうすると仮定しますが、その場合、答えはnotDTOを返すべきであるということです。 「Isolating the Domain」というタイトルの青い本の第4章を読むことをお勧めします。

その章で、エヴァンスはレイヤーについて次のように述べています。

複雑なプログラムをレイヤーに分割します。凝集性があり、下のレイヤーのみに依存するデザインを各レイヤー内で開発します。

これには十分な理由があります。 ソフトウェアの複雑さの尺度としての部分順序 の概念を使用する場合、レイヤーをその上のレイヤーに依存させると複雑さが増し、保守性が低下します。

これをあなたの質問に当てはめると、DTOは実際にはユーザーインターフェイス/プレゼンテーションレイヤーの懸念事項であるアダプターです。リモート/プロセス間通信はまさに DTOの目的 であることを忘れないでください言語)。

アプリケーション層がこれらのDTOに依存している場合、それより上位の層に依存しているため、複雑さが増します。これにより、ソフトウェアの保守が難しくなることを保証できます。

たとえば、システムが他の複数のシステムまたはクライアントタイプとインターフェイスし、それぞれが独自のDTOを必要とする場合はどうなりますか?アプリケーションサービスのメソッドが返すDTOをどのように確認しますか?選択した言語が戻り型に基づいてメソッド(この場合はサービスメソッド)のオーバーロードを許可していない場合、どのようにその問題を解決しますか?そして、あなたが方法を見つけたとしても、なぜプレゼンテーション層の懸念をサポートするためにアプリケーション層に違反するのですか?

実際には、これはスパゲッティアーキテクチャで終わる道の一歩です。私はこの種のデボルブとその結果を自分の経験で見てきました。

現在作業している場所では、アプリケーション層のサービスはドメインオブジェクトを返します。インターフェイス(UI /プレゼンテーション)レイヤーはドメインレイヤーに依存しているため、これを問題とは見なしません。ドメインレイヤーはbelowitです。また、次の理由により、この依存関係は「参照専用」タイプの依存関係に最小化されます。

a)インターフェイス層は、アプリケーション層への呼び出しによって取得された読み取り専用の戻り値としてこれらのドメインオブジェクトにのみアクセスできます。

b)アプリケーション層のサービスのメソッドは、その層で定義された「生の」入力(データ値)またはオブジェクトパラメーター(必要に応じてパラメーター数を減らす)のみを入力として受け入れます。特に、アプリケーションサービスneverは、ドメインオブジェクトを入力として受け入れます。

インターフェイスレイヤーは、インターフェイスレイヤー自体で定義されたマッピング手法を使用して、ドメインオブジェクトからDTOにマッピングします。繰り返しますが、これにより、DTOは、インターフェイス層によって制御されるアダプターであることに焦点を当て続けます。

2
BitMask777

私の経験では、OO UIパターン(裸のオブジェクトなど)を使用している場合を除き、ドメインオブジェクトをUIに公開するのは悪い考えです。これは、アプリケーションが成長するにつれて、UIのニーズが変化し、オブジェクトがそれらの変化に対応するように強制するためです。最終的に、UIとDOMAINの2つのマスターにサービスを提供しますが、これは非常につらい経験です。私を信じて、あなたはそこにいたくありません。 UIモデルには、ユーザーと通信する機能があり、DOMAINモデルはビジネスルールを保持し、永続化モデルはデータの効果的な保存を処理します。これらはすべて、アプリケーションのさまざまなニーズに対応しています。私はこれについてのブログ投稿を書いている最中です。完了したら追加します。

1
max_cervantes