詳細があまりないように見えるドメイン駆動設計の1つの部分は、ドメインモデルをインターフェイスから分離する方法と理由です。これは良い習慣だと同僚に納得させようとしていますが、あまり進んでいないようです...
彼らは、プレゼンテーション層とインターフェース層の好きな場所でドメインエンティティを使用します。表示モデルまたはDTOを使用してドメインレイヤーをインターフェイスレイヤーから隔離する必要があると私が彼らに主張したとき、彼らはそのようなことをすることでビジネス価値を見ないことに反対します。だけでなく、元のドメインオブジェクト。
それで、これをバックアップするために使用できるいくつかの具体的な理由を探しています。具体的には:
簡単に言えば、その理由は実装とドリフトの1つです。はい。プレゼンテーションレイヤーは、ビジネスオブジェクトを適切に表現できるように、それらについて知る必要があります。はい、最初は2種類のオブジェクトの実装の間に多くの重複があるように見えます。問題は、時間が経つにつれ、両側で状況が追加されることです。プレゼンテーションが変更され、プレゼンテーションレイヤーのニーズが進化して、ビジネスレイヤーから完全に独立しているもの(たとえば、色)が含まれるようになります。その間、ドメインオブジェクトは時間の経過とともに変化します。インターフェイスから適切な分離が行われていない場合、ビジネスオブジェクトに無害に見える変更を加えることにより、インターフェイスレイヤーを台無しにするリスクがあります。
個人的には、物事に取り組む最善の方法は、厳密に実施されたインターフェースパラダイムを使用することだと思います。つまり、ビジネスオブジェクトレイヤーは、通信できる唯一の方法であるインターフェースを公開します。インターフェースに関する実装の詳細(ドメインオブジェクトなど)は公開されません。はい。これは、ドメインオブジェクトを2つの場所に実装する必要があることを意味します。インターフェース層とBO層。しかし、その再実装は、最初は余分な作業のように見えるかもしれませんが、将来のある時点で大量の作業を節約するデカップリングを実施するのに役立ちます。
私自身、これに苦労しました。 DTOをプレゼンテーションで使用することが理にかなっている場合があります。私のシステムで会社のドロップダウンを表示したいとし、値をバインドする彼らのIDが必要だとしましょう。
まあ、サブスクリプションへの参照があるか、他に何を知っているCompanyObjectをロードする代わりに、名前とIDでDTOを送り返すことができます。これはIMHOの良い使い方です。
別の例を見てみましょう。私は見積もりを表すオブジェクトを持っています、この見積もりは労働力、設備などで構成されている可能性があり、これらのすべての項目を取りそれらを合計するユーザーによって定義された多くの計算がある可能性があります(各見積もりはタイプによって異なる場合があります)計算の)。このオブジェクトを2回モデリングする必要があるのはなぜですか? UIに計算を列挙して表示させることができないのはなぜですか?
私は通常、ドメインレイヤーをUIから分離するためにDTOを使用しません。私はそれらを使用して、ドメインレイヤーを自分の制御の及ばない境界から分離します。誰かがビジネスオブジェクトにナビゲーション情報を入れるという考えはばかげています。ビジネスオブジェクトを汚染しないでください。
誰かが彼らのビジネスオブジェクトに検証を置くという考え?これは良いことだと私は言います。あなたのUIはあなたのビジネスオブジェクトを検証する唯一の責任を持つべきではありません。ビジネスレイヤー[〜#〜]必須[〜#〜]独自の検証を行います。
なぜUI生成コードをbusienssオブジェクトに入れるのですか?私の場合、UIからUIコードを個別に生成する個別のオブジェクトがあります。私はビジネスオブジェクトをXmlにレンダリングする分離オブジェクトを持っています。このタイプの汚染を防ぐためにレイヤーを分離する必要があるという考えは、HTML生成コードをビジネスオブジェクトに配置する理由さえないので、私にとっては非常に異質です...
編集もう少し考えると、UI情報がドメインレイヤーに属している場合があります。これにより、ドメインレイヤーと呼ばれるものが曇る可能性がありますが、UIのルックアンドフィールと機能的なワークフローの両方で非常に異なる動作をするマルチテナントアプリケーションに取り組みました。さまざまな要因に応じて。この場合、テナントとその構成を表すドメインモデルがありました。それらの構成には、たまたまUI情報(たとえば、汎用フィールドのラベル)が含まれています。
永続化するためにオブジェクトを設計する必要がある場合、オブジェクトも複製する必要がありますか?新しいフィールドを追加する場合は、2つの場所に追加できることに注意してください。おそらく、DDDを使用している場合、これはすべて永続化されたエンティティドメインオブジェクトですか?私の例では、彼らはそうでした。
SQLをASP/JSPページに入れないのと同じ理由でこれを行います。
プレゼンテーションとドメインレイヤーで使用するために1つのドメインオブジェクトのみを保持する場合、その1つのオブジェクトはすぐにモノリシックになります。 UI検証コード、UIナビゲーションコード、UI生成コードが含まれ始めます。次に、すぐにその上にすべてのビジネスレイヤーメソッドを追加します。これで、ビジネスレイヤーとUIがすべて混同され、それらすべてがドメインエンティティレイヤーで混乱しています。
その気の利いたUIウィジェットを別のアプリで再利用したいですか?さて、この名前のデータベース、これら2つのスキーマ、およびこれらの18のテーブルを作成する必要があります。また、ビジネス検証を行うには、HibernateおよびSpring(または選択したフレームワーク)を構成する必要があります。ああ、これらの85のその他の非関連クラスも含める必要があります。これらのクラスはビジネスレイヤーで参照されており、たまたま同じファイルにあるだけだからです。
同意しません。
最善の方法は、プレゼンテーションレイヤーのドメインオブジェクトから始めて、それ以外のことを行う必要がなくなるまで始めることです。
一般的な考えに反して、「ドメインオブジェクト」と「値オブジェクト」はプレゼンテーションレイヤーに共存できます。そして、これがこれを行うための最良の方法です。ドメインオブジェクトを使用すると、両方のメリットを享受し、重複(および定型コード)を減らすことができます。リクエスト全体で値オブジェクトを使用するための調整と概念の簡素化。
答えは、アプリケーションの規模によって異なります。
基本的なクラッドアプリケーションの場合、機能はありません。エンティティの上にDTOを追加すると、時間の無駄になります。スケーラビリティを向上させることなく、複雑さが増します。
このサイズのアプリケーションでは、真のライフサイクルとそれに関連付けられたいくつかのビジネスロジックを持つエンティティはほとんどありません。
この場合にDTOを追加することは、いくつかの理由で良い考えです。
単一のエンティティが複数の表示方法を必要とする場合があります。それぞれに異なるフィールドセットが必要です。この場合、前の例と同じ問題に加えて、各クライアントに表示されるフィールドの量を制御する必要があります。クライアントごとに個別のDTOを用意すると、何を表示するかを選択するのに役立ちます。
サーバーとUIで同じモデルを使用しています。そしてそれは苦痛です。いつかそれをリファクタリングする必要があります。
問題は主に、データベース全体を参照せずにドメインモデルを直列化できるように、ドメインモデルをより小さな部分に分割する必要があるためです。これにより、サーバーでの使用が困難になります。重要なリンクがありません。一部のタイプもシリアル化できず、クライアントに送信できません。たとえば、 'Type'または任意のジェネリッククラス。それらは非ジェネリックである必要があり、Typeは文字列として転送される必要があります。これにより、シリアル化のための追加のプロパティが生成されます。これらは冗長で混乱を招きます。
別の問題は、UIのエンティティが実際には適合しないことです。私たちはデータバインディングを使用しており、多くのエンティティには、UI目的のためだけに多くの冗長なプロパティがあります。さらに、エンティティモデルには多くの「BrowsableAttribute」などがあります。これは本当に悪いです。
結局のところ、どちらの方法が簡単であるかが問題だと思います。プロジェクトによっては、問題なく機能し、別のDTOモデルを作成する必要がない場合もあります。
それは大部分の依存関係についてです。組織のコア機能構造には独自の機能要件があり、UIはユーザーがコアを変更および表示できるようにする必要があります。ただし、コア自体はUIに対応する必要はありません。 (それが発生する必要がある場合、それは通常、コアがプロパティデザインされていないことを示しています。)
私の会計システムには、会社の運営をモデル化するための構造と内容(およびデータ)があります。その構造は現実のものであり、私が使用する会計ソフトウェアに関係なく存在します。 (必然的に、特定のソフトウェアパッケージにはそれ自体のために構造とコンテンツが含まれますが、課題の一部はこのオーバーヘッドを最小限に抑えることです。)
基本的に人にはやるべき仕事があります。 DDDは、ジョブのフローと内容に一致する必要があります。 DDDは、可能な限り完全かつ独立して実行する必要があるすべてのジョブを明示することです。次に、UIは、できるだけ透過的かつ生産的にジョブを実行できるようにするのに役立ちます。
インターフェイスは、適切にモデル化された不変の機能コアに提供される入力とビューに関するものです。
くそー、私誓うこれはしつこく言った。
とにかく、それは同じことのもう1つの例です。パルナスの法則は、モジュールは秘密を保持するべきであり、秘密は変更可能な要件です。 (ボブ・マーティンには、これの別のバージョンであるルールがあります。)このようなシステムでは、プレゼンテーションはドメインとは無関係に変更できます。たとえば、価格をユーロで維持し、会社のオフィスでフランス語を使用しているが、価格をドルで表示し、北京語でテキストを表示したい場合などです。 domainは同じです。プレゼンテーションは変更される可能性があります。したがって、システムの脆弱性(つまり、要件の変更を実装するために変更する必要があるものの数)を最小限に抑えるには、懸念事項を分離します。
プレゼンテーションはreferenceドメインレイヤーの可能性がありますが、UIからドメインオブジェクトへの直接のバインドがあってはなりません。ドメインオブジェクトは、適切に設計されていれば、多くの場合、データ表現ではなく動作に基づいているため、UIの使用を目的としていません。 UIとドメインの間にマッピングレイヤーが必要です。 MVVM、またはMVPは、これに適したパターンです。 UIをドメインに直接バインドしようとすると、自分自身に多くの頭痛の種をもたらすことになります。彼らは2つの異なる目的を持っています。
' Value Injecter 'のようなツールの助けを借りて、ビューを操作しながらプレゼンテーションレイヤーで「マッパー」の概念を使用すると、各コードを理解しやすくなります。コードが少ししかない場合は、すぐにはメリットがわかりませんが、プロジェクトがますます成長するときは、サービスのロジックに入る必要がないようにビューを操作しながら非常に満足します。ビューモデルを理解するためのリポジトリ。 View Modelは、腐敗防止レイヤーの広大な世界におけるもう1つの警備員であり、長期的なプロジェクトでは金に見合う価値があります。
ビューモデルを使用する利点がないと思う唯一の理由は、プロジェクトが小さく、ビューがモデルの各プロパティに直接バインドされるほど単純である場合です。しかし、将来的には、要件の変更とビューの一部のコントロールがモデルにバインドされず、ビューモデルの概念がない場合は、多くの場所でパッチの追加を開始し、レガシーコードを作成し始めます。あなたは感謝しません。確かに、リファクタリングを行ってビューモデルをビュービューモデルに変換し、YAGNIの原則に従うことができますが、コードが不要な場合は追加しませんが、私自身は、ビューモデルオブジェクトのみを公開するプレゼンテーション層。
おそらく、UIレイヤーを十分に広い概念で概念化していません。複数の応答形式(Webページ、音声応答、印刷された手紙など)と複数の言語(英語、フランス語など)の観点から考えてください。
ここで、電話の呼び出しシステムの音声エンジンが、Webサイトを実行しているコンピューター(Windowsなど)とは完全に異なるタイプのコンピューター(Macなど)で実行されているとします。
もちろん、「私たちの会社では、英語だけを気にし、LAMP(Linux、Apache、MySQL、およびPHP)でWebサイトを実行し、誰もが同じバージョンのFirefoxを使用している」という罠に陥るのは簡単です。しかし、5年後、10年後はどうでしょうか。
ここで、ドメインエンティティをビューから分離するのが良い方法だと思う理由についての実際の例を示します。
数か月前、私はシンプルなUIを作成して、土壌サンプルの窒素、リン、カリウムの値を一連の3つのゲージで表示しました。各ゲージには赤、緑、赤のセクションがありました。つまり、各コンポーネントが少なすぎたり多すぎたりする可能性がありますが、中央に安全な緑のレベルがありました。
あまり考えずに、ビジネスロジックをモデル化して、これらの3つの化学成分のデータと、3つのケースのそれぞれの許容レベルに関するデータ(使用されている測定単位、つまりモルまたはパーセンテージを含む)を含む個別のデータシートを提供しました。次に、非常に異なるモデルを使用するようにUIをモデル化しました。このモデルは、ゲージのラベル、値、境界値、および色に関係していました。
これは、後で12個のコンポーネントを表示する必要があったときに、追加のデータを12個の新しいゲージビューモデルにマッピングしただけで、画面に表示されました。また、ゲージコントロールを簡単に再利用して、他のデータセットを表示させることもできました。
これらのゲージをドメインエンティティに直接結合した場合、上記の柔軟性はなく、将来の変更は頭痛の種になるでしょう。 UIでカレンダーをモデリングするときに非常によく似た問題に遭遇しました。出席者が10人以上いるときにカレンダーの予定が赤くなる必要がある場合、これを処理するビジネスロジックはビジネスレイヤーに残しておく必要があり、UI内のすべてのカレンダーは、次のように指示されている必要があります。赤くなります。理由を知る必要はありません。
以下の「レイヤー間のデータ伝播」のセクションも参照してください。これは説得力のある議論を示していると思います。
http://galaxy.andromda.org/docs/andromda-documentation/andromda-getting-started-Java/java/index.html