ドメインエンティティをプレゼンテーション層から分離する必要があるのはなぜですか?


85

ドメイン駆動設計の一部で、詳細があまり詳しくないようですが、ドメインモデルをインターフェイスから分離する方法と理由です。これは良い習慣だと同僚に納得させようとしていますが、あまり進んでいないようです...

プレゼンテーションレイヤーとインターフェイスレイヤーで、好きな場所でドメインエンティティを使用します。ドメインレイヤーをインターフェイスレイヤーから分離するために表示モデルまたはDTOを使用する必要があると私が主張するとき、彼らは、維持するUIオブジェクトがあるため、そのようなことを行うことでビジネス価値が見られないと反論します。元のドメインオブジェクトと同様に。

だから私はこれをバックアップするために使用できるいくつかの具体的な理由を探しています。具体的には:

  1. プレゼンテーション層でドメインオブジェクトを使用しないのはなぜですか?
    (答えが明白なものである場合、「デカップリング」、それからこれがこの文脈で重要である理由を説明してください)
  2. ドメインオブジェクトをインターフェイスから分離するために、追加のオブジェクトまたは構成を使用する必要がありますか?

この質問はウィキにあるはずです。
Syed Tayyab Ali

@ m4bwav-単一の正解ではなく、ディスカッションを招待するように表現されているため、wikiである必要があります。
ロブ・アレン

1
@ m4bwav:あなたの質問は、実際の質問というよりも意見の一部として出てきたと思います...私はそれを修正しようとしました(さらに編集したいかもしれません)が、適切な注意を払わないと、これは次のように見える可能性があることに注意してくださいトローリングする。
Shog9 2009年

5
わかりました、バックアップ、私は正当な質問をしています、これはどのように誰かを怒らせるでしょうか?誰をターゲットにしていますか?
マークロジャース

@ m4bwav:あなたはストローマンをターゲットにしています。あなたが質問の中でこれについて話し合う「多数の人々」。
Shog9 2009年

回答:


48

簡単に言えば、その理由は実装とドリフトの1つです。はい。プレゼンテーション層は、ビジネスオブジェクトを適切に表現できるように、それらについて知る必要があります。はい、最初は2つのタイプのオブジェクトの実装の間に多くの重複があるように見えます。問題は、時間が経つにつれて、物事が両側で追加されることです。プレゼンテーションが変更され、プレゼンテーション層のニーズが進化して、ビジネス層から完全に独立したもの(色など)が含まれるようになります。一方、ドメインオブジェクトは時間の経過とともに変化し、インターフェイスから適切に分離されていない場合、ビジネスオブジェクトに一見無害な変更を加えることで、インターフェイスレイヤーを台無しにするリスクがあります。

個人的には、物事にアプローチする最善の方法は、厳密に適用されたインターフェイスパラダイムを使用することだと思います。つまり、ビジネスオブジェクトレイヤーは、通信できる唯一の方法であるインターフェイスを公開します。インターフェイスに関する実装の詳細(つまり、ドメインオブジェクト)は公開されません。はい、これは、ドメインオブジェクトを2つの場所に実装する必要があることを意味します。インターフェイスレイヤーとBOレイヤー。しかし、その再実装は、最初は余分な作業のように見えるかもしれませんが、将来のある時点で大量の作業を節約するデカップリングを実施するのに役立ちます。


2
「ドメインオブジェクトを2つの場所に実装する」とはどういう意味ですか?
jlembke 2009年

10
これは私にはばかげているようです。将来の作業を節約できるのに、なぜ今余分な作業を行うのですか?10回のうち9回は、「TONS」の作業を節約するために変更を加える必要はありません。
ビープ音

13
@LuckyLindy:100回中99回(実際にはそれ以上)、怪我をしないようにシートベルトを着用する必要はありません。しかし、私が本当にそれを必要とするある場合には、それは私が殺されたりひどい怪我をしたりするのを(おそらく)防ぐでしょう。1オンスの予防は1ポンドの治療の価値があります。経験を積むと、これについてのあなたの意見は変わると思います。
ポールソニエ

19

私はこれに自分で苦労しました。DTOをプレゼンテーションで使用することが理にかなっている場合があります。システム内の会社のドロップダウンを表示したいとし、値をバインドするために会社のIDが必要だとします。

サブスクリプションへの参照がある可能性がある、または他に何を知っているかを知っているCompanyObjectをロードする代わりに、名前とIDを指定してDTOを送り返すことができます。これは私見の良い使い方です。

別の例を見てみましょう。私は見積もりを表すオブジェクトを持っています、この見積もりは労働力、設備などで構成されている可能性があり、これらすべての項目を取得して合計するユーザーによって定義された多くの計算がある可能性があります(各見積もりはタイプによって異なる可能性があります計算の)。このオブジェクトを2回モデル化する必要があるのはなぜですか?UIに計算を列挙させて表示させることができないのはなぜですか?

私は通常、ドメインレイヤーをUIから分離するためにDTOを使用しません。私はそれらを使用して、ドメインレイヤーを自分の制御の及ばない境界から分離します。誰かがナビゲーション情報をビジネスオブジェクトに入れるという考えはばかげています。ビジネスオブジェクトを汚染しないでください。

誰かがビジネスオブジェクトに検証を入れるという考えは?さて、これは良いことだと思います。UIは、ビジネスオブジェクトを検証する唯一の責任を持つべきではありません。ビジネス層独自の検証を行う必要があります。

UI生成コードをbusienssオブジェクトに配置するのはなぜですか?私の場合、UIからUIコードseperatleyを生成する個別のオブジェクトがあります。私のビジネスオブジェクトをXmlにレンダリングする個別のオブジェクトがあります。このタイプの汚染を防ぐためにレイヤーを分離する必要があるという考えは、なぜビジネスオブジェクトにHTML生成コードを配置するのでしょうか...

編集 もう少し考えますが、UI情報がドメインレイヤーに属している場合があります。これは、ドメインレイヤーと呼ばれるものを曇らせる可能性がありますが、UIのルックアンドフィールと機能ワークフローの両方で非常に異なる動作をするマルチテナントアプリケーションに取り組みました。さまざまな要因に応じて。この場合、テナントとその構成を表すドメインモデルがありました。それらの構成には、たまたまUI情報が含まれていました(たとえば、汎用フィールドのラベル)。

オブジェクトを永続化できるように設計する必要がある場合、オブジェクトも複製する必要がありますか?新しいフィールドを追加する場合は、2つの場所で追加できることに注意してください。DDDを使用している場合、おそらくこれは別の問題を提起します。すべての永続化されたエンティティはドメインオブジェクトですか?私の例では、彼らがそうであったことを知っています。


テナントごとに異なるラベルは、テナントごとに異なるユビキタス言語を示しているのではないでしょうか。テナント間でドメインを共有し、メタモデルを解釈するための変換層を持つメタモデルの概念が必要だと思います。
ケル2016

16

SQLをASP / JSPページから除外するのと同じ理由でこれを行います。

プレゼンテーションとドメインレイヤーで使用するためにドメインオブジェクトを1つだけ保持すると、その1つのオブジェクトはすぐにモノリシックになります。UI検証コード、UIナビゲーションコード、およびUI生成コードが含まれ始めます。次に、すぐにその上にすべてのビジネス層メソッドを追加します。これで、ビジネスレイヤーとUIがすべて混同され、それらすべてがドメインエンティティレイヤーで混乱しています。

その気の利いたUIウィジェットを別のアプリで再利用したいですか?この名前、これら2つのスキーマ、およびこれらの18のテーブルを使用してデータベースを作成する必要があります。また、ビジネス検証を行うには、HibernateとSpring(または選択したフレームワーク)を構成する必要があります。ああ、これらの85の他の無関係なクラスも含める必要があります。これらは、たまたま同じファイルにあるビジネス層で参照されているからです。


13

同意しません。

最善の方法は、プレゼンテーション層のドメインオブジェクトから始めて、他の方法で実行できるようになるまで続けることだと思います。

一般に信じられていることとは異なり、「ドメインオブジェクト」と「値オブジェクト」はプレゼンテーション層でうまく共存できます。そして、これが最善の方法です。ドメインオブジェクトとの重複(および定型コード)が減り、両方のメリットが得られます。リクエスト間で値オブジェクトを使用するための調整と概念の簡素化。


ご意見ありがとうございます。どこから来たのかわかります。これが成功するプロジェクトを作成するための無限の方法の1つではないと言っているわけではありませんが、保守が難しい大規模で複雑なプロジェクト向けの「ドメイン駆動設計」スタイルに反しているようです。長い目で見れば。
マークロジャース

いいえ、これは間違っています。まさに、非常に多くのサイトがSQLインジェクションに対して脆弱になる理由です。
レミ

7

答えは、アプリケーションの規模によって異なります。


シンプルなCRUD(作成、読み取り、更新、削除)アプリケーション

基本的なcrudアプリケーションの場合、機能はありません。エンティティの上にDTOを追加すると、時間の無駄になります。スケーラビリティを向上させることなく、複雑さを増します。

ここに画像の説明を入力してください


適度に複雑な非CRUDアプリケーション

このサイズのアプリケーションでは、真のライフサイクルとそれに関連するビジネスロジックを持つエンティティはほとんどありません。

この場合にDTOを追加することは、いくつかの理由から良い考えです。

  • プレゼンテーション層は、エンティティが持つフィールドのサブセットのみを表示できます。エンティティをカプセル化します
  • バックエンドとフロントエントの間に結合はありません
  • エンティティ内にビジネスメソッドがあり、DTOにはない場合、DTOを追加すると、外部コードがエンティティの状態を台無しにすることはできません。

ここに画像の説明を入力してください


複雑なエンタープライズアプリケーション

単一の事業体は、複数の表示方法を必要とする場合があります。それらのそれぞれは、異なるフィールドのセットを必要とします。この場合、前の例と同じ問題が発生し、さらに各クライアントに表示されるフィールドの量を制御する必要があります。クライアントごとに個別のDTOがあると、表示するものを選択するのに役立ちます。

ここに画像の説明を入力してください


4

サーバーとUIで同じモデルを使用しています。そして、それは苦痛です。いつかリファクタリングする必要があります。

問題は主に、データベース全体を参照せずにドメインモデルをシリアル化できるように、ドメインモデルをより小さな部分に分割する必要があるためです。これにより、サーバーでの使用が難しくなります。重要なリンクがありません。一部のタイプもシリアル化できず、クライアントに送信できません。たとえば、「Type」または任意のジェネリッククラス。それらは非ジェネリックである必要があり、Typeは文字列として転送される必要があります。これにより、シリアル化用の追加のプロパティが生成されます。これらは冗長で混乱を招きます。

もう1つの問題は、UIのエンティティが実際には適合しないことです。データバインディングを使用しており、多くのエンティティにはUIの目的でのみ多くの冗長プロパティがあります。さらに、エンティティモデルには多くの「BrowsableAttribute」などがあります。これは本当に悪いです。

結局、どちらが簡単かという問題だと思います。プロジェクトによっては、正常に機能し、別のDTOモデルを作成する必要がない場合があります。


2
データバインディングを使用する場合は、linqクエリを実行し、匿名型にバインドします。これにより、階層をフラット化して変更できます。これを使用して、フィルタリングと並べ替えを非常にうまく実装することもできます。
JoshBerke 2009年

@ジョシュ:アドバイスありがとうございます。これは部分的に機能する可能性があります。私自身はGUIプログラマーではなく、GUIの概念にはあまり関わっていません。問題は、データが操作されてサーバーに送り返される場合に発生します。
Stefan Steinegger 2009年

3

ほとんどの場合、依存関係についてです。組織のコア機能構造には独自の機能要件があり、UIを使用してコアを変更および表示できるようにする必要があります。ただし、UIに対応するためにコア自体は必要ありません。(それが発生する必要がある場合、それは通常、コアがプロパティ設計されていないことを示しています。)

私の会計システムには、私の会社の運営をモデル化することになっている構造と内容(およびデータ)があります。その構造は現実のものであり、私が使用している会計ソフトウェアに関係なく存在します。(必然的に、特定のソフトウェアパッケージには、それ自体のために構造とコンテンツが含まれていますが、課題の一部は、このオーバーヘッドを最小限に抑えることです。)

基本的に人にはやるべき仕事があります。DDDは、ジョブのフローと内容に一致する必要があります。DDDは、完全かつ独立して実行する必要のあるすべてのジョブを可能な限り明示的にすることです。次に、UIにより、ジョブを可能な限り透過的に、可能な限り生産的に実行できるようになります。

インターフェイスは、適切にモデル化された不変の関数型コアに提供される入力とビューに関するものです。


3

くそー、私はこれが永続性を言ったことを誓います。

とにかく、それは同じことのもう1つの例です。パーナスの法則では、モジュールは秘密を保持する必要があり、秘密は変更される可能性のある要件です。(Bob Martinには、これの別のバージョンであるルールがあります。)このようなシステムでは、表示ドメインとは無関係に変更できます。たとえば、ユーロで価格を維持し、会社のオフィスでフランス語を使用しているが、北京語でテキストを使用してドルで価格を提示したい会社などです。ドメインは同じです。プレゼンテーションは変更される可能性があります。したがって、システムの脆弱性、つまり要件の変更を実装するために変更する必要のあるものの数を最小限に抑えるには、懸念事項を分離します。


2

プレゼンテーションはドメインレイヤーを参照する場合がありますが、UIからドメインオブジェクトに直接バインドすることはできません。ドメインオブジェクトは、適切に設計されている場合、データ表現ではなく動作に基づいて設計されていることが多いため、UIの使用を目的としていません。UIとドメインの間にマッピングレイヤーが必要です。MVVM、またはMVPは、これに適したパターンです。UIをドメインに直接バインドしようとすると、多くの頭痛の種が発生します。それらには2つの異なる目的があります。


1

おそらく、UIレイヤーを十分に広い意味で概念化していないのでしょう。複数の形式の応答(Webページ、音声応答、印刷された手紙など)および複数の言語(英語、フランス語など)の観点から考えてください。

ここで、電話呼び出しシステムの音声エンジンが、Webサイトを実行するコンピューター(おそらくWindows)とはまったく異なるタイプのコンピューター(Macなど)で実行されているとします。

もちろん、「私の会社では英語しか気にせず、WebサイトをLAMP(Linux、Apache、MySQL、PHP)で実行し、誰もが同じバージョンのFirefoxを使用している」という罠に陥りがちです。しかし、5年または10年でどうでしょうか?



1

ビューを操作しながら、プレゼンテーション層で「バリューインジェクター」などのツールと「マッパー」の概念を使用すると、コードの各部分をはるかに簡単に理解できます。コードが少しある場合、すぐには利点がわかりませんが、プロジェクトがますます大きくなると、サービスのロジックに入る必要がないようにビューを操作しながら非常に満足します。ビューモデルを理解するためのリポジトリ。ビューモデルは、腐敗防止層の広大な世界におけるもう1つの警備員であり、長期的なプロジェクトでは金でその重量に見合う価値があります。

ビューモデルを使用する利点が見当たらない唯一の理由は、プロジェクトが小さくて単純で、ビューをモデルの各プロパティに直接バインドできる場合です。しかし、将来的に、要件の変更とビューの一部のコントロールがモデルにバインドされず、ビューモデルの概念がない場合は、多くの場所でパッチの追加を開始し、レガシーコードを使用し始めます。あなたは感謝しないでしょう。確かに、ビューモデルをview-viewmodelで変換し、YAGNIの原則に従って、必要がない場合はコードを追加せずにリファクタリングを行うことができますが、私自身にとっては、追加するために従わなければならないベストプラクティスです。ビューモデルオブジェクトのみを公開するプレゼンテーション層。


1

これは、ドメインエンティティをビューから分離することが良い習慣であると思う理由の実際の例です。

数か月前、土壌サンプル中の窒素、リン、カリウムの値を一連の3つのゲージで表示する簡単なUIを作成しました。各ゲージには赤、緑、赤のセクションがありました。つまり、各コンポーネントが少なすぎるか多すぎる可能性がありますが、中央には安全な緑のレベルがありました。

あまり考えずに、ビジネスロジックをモデル化して、これら3つの化学成分のデータと、3つのケースのそれぞれで許容されるレベルに関するデータ(使用されている測定単位、つまりモルまたはパーセンテージを含む)を含む別のデータシートを提供しました。次に、非常に異なるモデルを使用するようにUIをモデル化しました。このモデルは、ゲージラベル、値、境界値、および色を考慮していました。

つまり、後で12個のコンポーネントを表示する必要が生じたときに、追加のデータを12個の新しいゲージビューモデルにマッピングすると、それらが画面に表示されました。また、ゲージコントロールを簡単に再利用して、他のデータセットを表示させることもできました。

これらのゲージをドメインエンティティに直接結合した場合、上記の柔軟性はなく、将来の変更は頭痛の種になります。UIでカレンダーをモデル化するときに、非常によく似た問題に遭遇しました。10人以上の参加者がいるときにカレンダーの予定を赤に変える必要がある場合、これを処理するビジネスロジックはビジネスレイヤーに残しておく必要があり、UIのすべてのカレンダーは、次のように指示されていることを知る必要があります。赤くなります。理由を知る必要はありません。


-1

一般化されたセマンティクスとドメイン固有のセマンティクスの間に追加のマッピングを追加する唯一の賢明な理由は、ドメインセマンティクスとは異なる一般化された(ただしマッピング可能な)セマンティクスに基づく既存のコード本体(およびツール)がある(アクセスできる)ことです。

ドメイン駆動設計は、機能ドメインフレームワークの直交セット(ORM、GUI、ワークフローなど)と組み合わせて使用​​すると最適に機能します。ドメインセマンティクスを公開する必要があるのは、外層の隣接関係のみであることを常に忘れないでください。通常、これはフロントエンド(GUI)と永続的なバックエンド(RDBM、ORM)です。効果的に設計された介在レイヤーは、ドメイン不変である可能性があり、ドメイン不変である必要があります。


パラ1:個別のアプリ間で実際に共有しない限り、不要な抽象化(再利用可能なコンポーネントなど)を作成しないでください。パラ2:汎用GUIが非常に多くの異なるドメインでどのように機能するのか疑問に思います。備考:この業界はとても壊れていて、もう面白くありません...
alphazero 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.