web-dev-qa-db-ja.com

DDDに個別のドメインモデルと永続性モデルがある

データベースを生成するためのコードファーストアプローチを使用しながら、ドメインドリブンデザインとそれを実装する方法について読んでいます。私が読んで研究したことから、この主題に関して2つの意見があります。

  1. ドメインモデルと永続モデルの両方として機能する1つのクラスがある

  2. 2つの異なるクラスがあり、1つはドメインロジックを実装し、もう1つはコードファーストアプローチに使用します

今、私は意見1)を知っています。ドメインモデルと永続モデルの間に大きな違いがない小さなソリューションを簡略化すると言われていますが、それは単一責任の原則を破り、ORMの規則がDDDに干渉するときに多くの問題を引き起こすと思います。

私が驚いたことは、意見を実装する方法のコード例が多数あることです1)。しかし、オピニオン2)を実装する方法と2つのオブジェクトをマップする方法の単一の例を見つけていません。 (おそらくそのような例がありますが、C#の例は見つかりませんでした)

だから私は自分で例を実装しようとしましたが、それがそれを行うための良い方法であるかどうかはわかりません。

チケットシステムがあり、チケットに有効期限があるとします。ドメインモデルは次のようになります。

/// <summary>
/// Domain Model
/// </summary>
public class TicketEntity
{
    public int Id { get; private set; }

    public decimal Cost { get; private set; }

    public DateTime ExpiryDate { get; private set; }

    public TicketEntity(int id, decimal cost, DateTime expiryDate)
    {
        this.Id = id;
        this.Cost = cost;
        this.ExpiryDate = expiryDate;
    }

    public bool IsTicketExpired()
    {
        if (DateTime.Now > this.ExpiryDate)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

Entity FrameworkをORMとして使用する永続性モデルはほとんど同じに見えますが、ソリューションが大きくなると、そうではない可能性があります

/// <summary>
/// ORM code first Persistence Model
/// </summary>
public class Ticket
{
    [Key]
    public int Id { get; set; }

    public decimal Cost { get; set; }

    public DateTime ExpiryDate { get; set; }
}

これまでのところすべてが素晴らしいようです。さて、私が確信していないのは、リポジトリからTicket永続モデルを取得するのに最適な場所と、それをTicketEntityドメインモデルにマップする方法です。

私はこれをアプリケーション/サービス層で行いました。

public class ApplicationService
{
    private ITicketsRepository ticketsRepository;

    public ApplicationService(ITicketsRepository ticketsRepository)
    {
        this.ticketsRepository = ticketsRepository;
    }

    public bool IsTicketExpired(int ticketId)
    {
        Ticket persistanceModel = this.ticketsRepository.GetById(ticketId);
        TicketEntity domainModel = new TicketEntity(
            persistanceModel.Id,
            persistanceModel.Cost,
            persistanceModel.ExpiryDate);

        return domainModel.IsTicketExpired();
    }
}

私の質問は:

  1. オピニオン1)がオピニオン2)よりも優先される理由はありますか?開発の高速化とコードの再利用以外の理由はありますか?.

  2. モデルをマッピングする私のアプローチに問題はありますか?ソリューションが大きくなると問題が発生する、見逃したものはありますか?

48
Adrian Hristov

オピニオン1)がオピニオン2)よりも優先される理由は何ですか?.

オプション1は、純粋な遅延が原因であり、開発速度の向上を想像したものです。これらのアプリケーションがバージョン1.0のビルドを高速化することは事実です。しかし、それらの開発者がアプリケーションのバージョン3.0に到達したとき、ORMマッパーのためにドメインモデルで行わなければならなかったすべての妥協により、アプリケーションを維持することはそれほど楽しいことではないと思います。

モデルをマッピングする私のアプローチに問題はありますか?ソリューションが大きくなると問題が発生する、見逃したものはありますか?

はい。リポジトリは永続化メカニズムを隠す責任があります。 APIはドメインエンティティでのみ機能し、永続性エンティティでは機能しません。

リポジトリは、ドメインエンティティとの間の変換を実行します(それらを永続化できるようにするため)。 fetchメソッドは通常、ADO.NETまたはEntity FrameworkのようなORMを使用して、データベースオブジェクト/エンティティをロードします。次に、それを正しいビジネスエンティティに変換し、最後にそれを返します。

それ以外の場合は、すべてのサービスに永続性に関する知識を持たせ、ドメインモデルでの作業を強制するため、2つの責任があります。

DDD定義に従ってアプリケーションサービスを操作する場合は、アプリケーションサービスの代わりになるコマンド/クエリの分離パターンを確認することをお勧めします。コードがよりクリーンになり、ドメインモデルをラップするはるかに軽量のAPIも得られます。

24
jgauffin

今年、私が働いていた大きなプロジェクトでこのジレンマに陥りましたが、それは本当に難しい決断でした...このトピックについて時間内に話したいと思いますが、私はあなたの考えを再開します。

1)永続性とドメインモデルは同じもの

ゼロから設計されたデータベースを使用する新しいプロジェクトに参加している場合は、おそらくこのオプションをお勧めします。はい、ドメインとそれに関する知識は絶えず変化し、データベースに影響を与えるリファクタリングが必要になりますが、ほとんどの場合価値があると思います。

Entity FrameworkをORMとして使用すると、ほとんどfluent mappings を使用して、ドメインモデルをORMの問題から完全に解放できます。

良い部品:

  • 高速、簡単、美しい(データベースがその問題用に設計されている場合)

不良パーツ:

  • おそらく、開発者は、ドメインに変更やリファクタリングを行う前に、データベースに影響を与えることを恐れて2度考え始めます。この恐怖はドメインにとって良くありません。
  • ドメインがデータベースから離れすぎている場合は、ドメインをORMと調和して維持することが困難になります。ドメインに近づくほど、ORMの構成が難しくなります。 ORMに近づくほど、ドメインは汚れてきます。

2)2つの分離されたものとしての永続性とドメインモデル

それはあなたがあなたがあなたのドメインで好きなことをすることを自由にしてくれるでしょう。リファクタリングを恐れず、ORMやデータベースからの制限もありません。このアプローチは、レガシーデータベースまたは設計が不適切なデータベースを処理するシステムに推奨されます。これは、おそらくドメインをめちゃくちゃにすることになるでしょう。

良い部品:

  • ドメインを完全に無料でリファクタリング
  • Bounded Context のようなDDDの別のトピックを簡単に掘り下げることができます。

不良パーツ:

  • レイヤー間のデータ変換の取り組みが増えました。開発時間(おそらくランタイムも)が遅くなります。

  • しかし、プリンシパル、そして私を信じて、さらに害を与えるもの:ORMを使用することの主な利点を失うでしょう!Like tracking changes 。たぶん GraphDiff のようなフレームワークを使用することになるか、ORMを放棄して純粋なADO.NETにアクセスすることになるでしょう。

モデルをマッピングする私のアプローチに問題はありますか?

@jgauffinに同意します:「マッピングが行われるのはリポジトリ内です」。このようにして、永続性モデルがリポジトリ層から出ることはありません。優先的には、(リポジトリ自体を除いて)それらのエンティティを誰も見るべきではありません。

11

オピニオン1)がオピニオン2)よりも優先される理由は何かありますか?開発の高速化とコードの再利用以外の理由があります。

私は大きなものを見ることができます(先の意見):「持続性モデル」はありません。必要なのは、データベースのリレーショナルモデルとドメインオブジェクトモデルだけです。 2つの間のマッピングデータ構造ではなくアクションのセットです。さらに、これはまさにORMが行うことになっていることです。

ほとんどのORMは、最初から提供すべきものをサポートしています。これらのアクションをドメインエンティティに触れずにコードで直接宣言する方法です。 Entity Frameworkの流暢な構成により、たとえば、それを行うことができます。

あなたはそこに見つけることができる多くの実装がそうするので、あなたは永続モデルがDDDでのSRPと踏みつけに違反しないという印象の下にあるかもしれません。しかし、それはそのようである必要はありません。

3
guillaume31