web-dev-qa-db-ja.com

ドメイン駆動設計、2つのアグリゲートが同じルートを持つことはできますか?

さまざまな機能をさまざまなクラスに分離する目的で、次の2つの集約があります。

  1. ActiveEmployee

    • AssignTask()
    • ReassignManager()
    • 非アクティブ化(文字列の理由)
  2. InactiveEmployee

    • GetReasonForDeactivation()
    • 復元()

両方の集計は、同じルートdbo.Employeeを共有します。

両方の集約の主キーとしてのEmployeeIDサーバー。

リポジトリは、ブールフラグdbo.Employee.IsActiveに基づいて、最初のインスタンスまたは2番目のインスタンスをインスタンス化します。

1つのトランザクションで変更できるのは1つの集約のみであるというルールに従っているため、同じトランザクションで両方の集約が同じIDでロードされ、ID 3のInactiveEmployeeとID 3のActiveEmployeeになるという状況には決して遭遇しません。

これは良いDDDですか? DDDでは、ルートが同じ2つのアグリゲートを使用できますか?フラグに基づいて集計タイプを区別できますか?

更新1:

両方の集計が同じルートを共有すると言ったとき、私が意味したのは、両方の集計がdbo.Employeeテーブルの行を表すということです。

私の理解では、Aggregateのルートは、ドメインで一意に定義されるエンティティです。それは、そのエンティティが実際のクラスとして存在しなければならないという意味ではなく、アイデンティティが重要です。 Inactive/ActiveEmployeeを参照する他のすべてのAggregateは、オブジェクトインスタンスへの参照ではなく、EmployeeIDへの参照を保持します。

4
omittones

DDDは主キー、行、またはテーブルに関するものではないことを理解する必要があります。これらは、DDDを実装するための手段にすぎません。

集約ルートは、ルートを介して集約のすべての機能とデータにアクセスする必要があるため、通常はクラスとして実装されます。したがって、テーブルの主キーが持つことのできない何らかの動作が必要です。これの主な利点は、集約のカプセル化です。そのロジックは完全に集約内に含まれ、外部にリークしないため、アプリケーションの結合が(結果として複雑さが大幅に)減少します。

つまり、各アグリゲートには独自のアグリゲートルートがあるため、2つのアグリゲートが同じルートを持つことはできません(アグリゲートが存在する場合、事実上1つのアグリゲートが存在します)。

あなたの場合、おそらく2つの独立した集計(ActiveEmployee、InactiveEmployee)が同じテーブルによってサポートされているはずです(これは完全にDDDのスコープ外なので問題ありません)。ただし、ドメインモデルには実際にはdbo.Employeeエンティティがないことを思い出してください。これは、下位(永続性)レイヤー上の単なるテーブルです。

10
qbd

Employeeが集約ルートの場合、すべての外部オブジェクトはEmployeeのみを参照できます(ActiveEmployee/InactiveEmployeeは参照できません)。

アグリゲートの外部からの参照は、アグリゲートのルートにのみ行く必要があります。 Martin FowlerによるDDD集計

それはあなたの意図ではないと思います。
あなたの例では、ActiveEmployeeInactiveEmployeeはどちらも独立した集約ルートであると思います。
これら2つは完全に異なります。それらは異なるAPIを公開し、異なる処理を必要とします。それらはいくつかの情報(従業員テーブル)を共有しますが、それ以外は相互のやり取りはありません。最初に従業員のステータスを確認しないと、相互に代用できず、APIを呼び出すことができません。

この状況は、私にとって Liskov代入原理 の違反によく似ています。

3
DanielS

したがって、OPが行ったのは、ActiveCustomerとInactiveCustomerと呼ばれる2つの集約ルートを作成し、それらにCustomerタイプのプロパティを追加したことだと思います。これは、自分のシステムで顧客を表すエンティティです。

ここで混乱/問題が生じたと思います。事実上、これにより、集計ルートがエンティティのラッパーになりましたが、それ以上になるはずです。

データベース、テーブル、永続化に関係することについて考えるのをやめる必要があります。そのようなものはドメインに存在しません。代わりに、ActiveCustomerとInactiveCustomerを確認してください。同じプロパティの多くを持っている可能性がありますが、動作は異なります。その動作を構築します。

永続性に関して言えば、EF、NHIbernateなどのDBアクセス機能を含むインフラストラクチャプロジェクトがあります。その中で、オブジェクトをテーブルにマップできます。私が始めたのは、EFがマップする内部データ状態クラスをAggregates内に作成することです。したがって、すべてのパブリックゲッターとセッター、およびIDが含まれているCustomerDataStateのようなものがあるかもしれません。 EFまたはNHibernateを使用して、その状態オブジェクトにデータを入力します。これにより、集約がセットアップされます。その状態クラスは集計を通じて公開されないため、ドメインモデルのユーザーに関する限り、ユーザーはActiveCustomerまたはInactiveCustomerを操作しているだけです。

したがって、Active/InactiveCustomerアグリゲートは、一部の永続化メディアからロードできるCustomerDataStateからロードまたは再水和されます。

DDDを使用する最善の方法は、データベースを無視し、それを忘れて、存在しないふりをすることです。 Aggregateがどのように永続化されるかについて考え始めるとすぐに、道に迷いました。ですから、列やテーブルについての考えが頭に浮かんだら、すぐに自分を揺さぶって一歩下がってください。

1
PendorPaul