web-dev-qa-db-ja.com

ドメイン主導の設計-アグリゲートの更新と永続化

私は次の状況で可能な限り最高の解決策に頭を抱えようとしています:

アグリゲートの一部を更新する場合、アグリゲートの任意の部分である可能性があるため、ルートまたは他のエンティティこれらの変更をdbレイヤーに永続化する方法

StackExchangeには、ORMモデルをドメインオブジェクトとして使用するなどのアドバイスを提供する多くのソリューションがあり、Aggregateの属性を変更し、ORMレイヤーを比較して、変更をデータベースにフラッシュできます。ほとんどの例にはEnity Frameworkへの参照が含まれています私が間違っていない場合。 ここでのソリューションのように、ドメインオブジェクトであるArticleにはORM永続化ロジックが含まれています

DDDについての私の部分的な理解は、ドメインモデルで永続性レイヤーロジックを定義するべきではないということでした。永続性ロジックはリポジトリで定義する必要があります。さまざまな永続化メカニズム(Postgres、MongoDB、S3など)を持つこと。また、永続化ロジックや「元の」SQLオブジェクトを含むドメインモデルを「ポイ捨て」すると、ドメインオブジェクト/集計のテストが非常に難しくなります。

Postgresを使用している場合、これらの変更をORMレイヤーにマップする方法について、簡単でシンプルなソリューションを理解するのに苦労しています。答えがORMモデルとリポジトリ内のドメインモデルとの間の強いマッピングでない限り、そうするのは非常に難しく冗長です。

私は他の解決策を読んで、他にもいくつかの可能性があることを理解しました(それらにはすべて独自の欠点があります)。

  1. ドメインモデルで何かを変更するたびにModelAttributeChangedイベントを生成します。このイベントを返すか、ドメインモデルのどこかに保存できます。このモデルをリポジトリに永続化する場合は、最初にORMモデルにクエリを実行し、コミットする前にこれらの変更をORMモデルにマッピングして戻します。

    changed_name_event = person_aggregate.set_name('Henk')
    Repository.save(person_aggregate, changed_name_event)
    
  2. Aggregateで何かを変更した後、リポジトリのupdateメソッドも明示的に呼び出して、属性を更新します。アグリゲートとリポジトリの両方ですべてを更新する必要があります。また、リポジトリで正しいメソッドを呼び出す前に、アグリゲートのどの属性が変更されるかを事前に知っておく必要があります。

    person_aggregate.change_name('Henk')
    repository.change_person_name(person_aggregate, 'Henk')
    

理想的には、自分のアグリゲートを更新してリポジトリーに保存できるようにしたいだけです。ただし、ORMモデルをAR、集約ルートにマップするため、ORMモデルへのマッピングを「緩め」ます。もちろん、Aggregateに加えたすべての変更を追跡し、リポジトリを呼び出すたびにこれらの変更をORMモデルに適用してデータベースにコミットすることもできます。このソリューションの私の「問題」は、強力なマッピングが必要であり、ネストされたエンティティの変更を追跡することは、難しく、複雑で、エラーが発生しやすいプロセスです。

ドメインロジックを完全に分離するためにこれが必要な悪である場合、問題はありませんが、この抽象化を機能させるために多くのロジックを定義する必要があるように感じます。

1

集計の目的は、複雑なビジネス関係をモデル化し、ビジネスアクションを実行することです。リポジトリの目的は、データストアで通常のCRUD操作を実行することです。

簡単な例である請求書を見てみましょう。請求書は単純なCRUDエンティティではありません。これらは、顧客、製品、住所、支払いなど、いくつかのエンティティの集合体です。 CRUDを使用してこれらのエンティティを個別に操作しますが、請求書に適用される方法を使用して請求書を操作します。

請求書のいくつかの潜在的な方法:

  • 印刷する
  • バランスをとる
  • 製品を追加
  • 数量を変更する

したがって、Invoiceオブジェクトは、Invoiceに適用されるメソッドと、それぞれのリポジトリに適用されるCRUD操作との間のマッピングになります。永続化メカニズムを永続化するエンティティから単に分離するだけでなく、付加価値を追加します。

私は人々がアーキテクチャーを通して作業を始めるとき、彼らはそもそもアーキテクチャーを作成している理由について考えることを忘れていると思います。一連のアーキテクチャルールに準拠するアーキテクチャを作成する必要はありません。ソフトウェアを保守可能にするアーキテクチャを作成します。アーキテクチャは、サービスを提供するためのものであり、逆ではありません。

さらに読む
クリーンアーキテクチャ-ユースケースクラスが多すぎます

1
Robert Harvey

理想的には、自分のアグリゲートを更新してリポジトリーに保存できるようにしたいだけです。

  1. どの(ネストされている可能性がある)フィールドが変更されたかに関係なく、変更するたびに集計全体を保存します。

Repository.save(person_aggregate)

真剣に、私は実際に上記の別の質問に取り組みたいと思います-具体的に示されていないものです(Robert Harveyの回答もこれに触れています)。

「最善の解決策」のようなフレーズは、よくても誤解を招き、最悪の場合は難読化します。あなたがするすべてのデザイン決定はトレードオフです。これらのトレードオフを理解し、それらの間の「最良の」選択を行うことは、まさに建築家の仕事です。残念ながら、あなたが最適化したいものや、システムが許容できる妥協のレベルあなたを知ることはできません。

?複雑さの点で思います。私は手動で変更追跡を実装する道を歩みません(最悪のオプション)。また、イベントソーシングのいくつかのバリアント(2番目に悪いオプション)も紹介しません。また、すべてのユースケースで変更を複製/伝播することもしません。 yoはどこに残りますか?

さまざまなオプション間のトレードオフを合理的に把握しているようです。今、建築家になって、選んでください。

1
king-side-slide