手册

DDD コード: エンティティ、値オブジェクト、および集計 (Ddd 2)

DDD 戦術パターンはどのように機能しますか?値オブジェクト、エンティティ、集計、ドメイン サービス、アプリケーション サービス、リポジトリの境界と実際の注文例…

DDD - ソフトウェアのビジネス言語

部分 2 的 4

DDD tactical patterns showing value objects, entities, and aggregate boundaries

この記事の質問

最初の部分では、ビジネスの言語とルールから始めました。ここで問題は、これらの決定をコードのどこに保持するかということです。同じ e コマース ドメイン (お金、注文明細、注文と支払いのフロー) を使用します。```text Money + Address + Quantity → Value Object OrderLine + Order → Entity Order (Root) + OrderLine → Aggregate Repository → Aggregate Root'u yükler ve kaydeder


## 最初に説明した概念```text
📦 Value Object
Kimliği olmayan, değeriyle tanımlanan ve değişmez tutulması gereken kavram.

📦 Entity
Nitelikleri değişse de kimliği boyunca aynı kalan nesne.

📦 Aggregate
Birlikte tutarlı kalması gereken nesnelerin transaction sınırı.

📦 Aggregate Root
Aggregate'e dışarıdan girilebilen tek kapı.
```たとえば、2 つの `Money(100, "TRY")` は同じ値を表します。 2 つの注文は、合計が同じであっても、異なる ID を持ちます。

## 値オブジェクトから開始

DDDの考え方をバリューオブジェクトが一番教えてくれます。 `decimal` はお金そのものではありません。通貨、四捨五入、割引、税金のルールが適用されます。これらのルールをサービス層に配布するのではなく、コンセプト内に保存します。```csharp
public sealed record Money(decimal Amount, string Currency)
{
    public Money Add(Money other)
    {
        if (Currency != other.Currency) throw new DomainException("Currency mismatch");
        return new Money(Amount + other.Amount, Currency);
    }
}
```値オブジェクトは不変です。値が変更されると、新しいインスタンスが作成されます。したがって、同じアドレス、電子メール、日付範囲、または通貨値が、異なるトランザクション ステップで予期しない副作用を引き起こすことはありません。比較はコンテキストに基づいて行われます。したがって、フィールドの数に応じて均等コストは O(m) になりますが、ビジネス ルールは 1 か所に留まるため、変更コストは減少します。

## エンティティ: ID とライフサイクル

`Order` はエンティティです。住所または合計を変更できます。やはり同じ順番ですね。違いはセッターの使用ではなく、遷移をジョブの動作としてモデル化することにあります。```text
❌ order.Status = Paid
✓ order.ConfirmPayment(payment)

❌ order.Total = total - discount
✓ order.ApplyDiscount(discount)
````ConfirmPayment` は、支払い証明、注文がキャンセルされていないこと、移行が合法であることを 1 か所でチェックします。エンティティのタスクは、すべてのデータを移動することではなく、ライフサイクルにおける無効な状況を防ぐことです。

## 集約: オブジェクトのグループではなく、一貫性の制限

注文とその明細は、同じトランザクション内で一貫性を保つ必要があります。つまり、明細の数は正であり、合計は明細の合計に等しく、注文の確認後に明細を変更することはできません。したがって、`Order` は `OrderLine` の集約ルートになります。```text
Order aggregate
  ├─ OrderLine
  ├─ ShippingAddress
  └─ Total

Dış dünya → Order.AddLine() / Order.ConfirmPayment()
Dış dünya ↛ OrderLine'a doğrudan yazmaz
```集約を大きくすると、セキュリティではなく、ロックとバージョンの競合が発生します。書き込みリクエストではできるだけ単一の集計を更新します。オブジェクト参照ではなく ID によって別の集約に接続します。調整が必要な場合は、ドメイン イベントまたはアプリケーション オーケストレーションを使用します。これにより、オプティミスティック同時実行の競合と不必要なインストール コストが制限されます。

## ドメインサービスとアプリケーションサービス

ルールが本来的に単一の集計に属さない場合、それはドメイン サービスである可能性があります。たとえば、為替レートに基づいた価格設定などです。対照的に、アプリケーション サービスはユースケースを管理します。つまり、注文をロードし、動作を呼び出し、保存し、トランザクションを完了します。

|レイヤー |責任 |
| --- | --- |
|値オブジェクト / エンティティ / 集計 |ビジネスルールと不変条件の維持 |
|ドメインサービス | Aggregate | に属さない純粋なドメイン アカウント
|アプリケーションサービス |ユースケースのオーケストレーション、トランザクション、アダプター呼び出し |

アプリケーション サービスにルールを置くことは、貧血モデルをサービス層に戻すことです。

## リポジトリ: テーブル API ではありません

リポジトリは、ドメインにメモリ内のコレクションのような感覚を与えます。これは SQL または ORM の詳細ではありません。テーブルごとにリポジトリを作成するのではなく、集計ルートにのみリポジトリを使用します。子エンティティを `OrderLineRepository.Find()` に直接置き換えると、ルートが維持するルールがバイパスされます。```text
order = orderRepository.get(orderId)
order.confirmPayment(payment)
orderRepository.save(order)
```この制限により、テスト時に模擬リポジトリを使用してインフラストラクチャに依存せずにドメインの動作を検証することも可能になります。 ORM の空のコンストラクターや積極的な読み込み要件によってドメイン モデルが形成されるべきではありません。マッピングはアダプターの責任です。

## 誤った信頼を生み出す一致```text
❌ Value Object = küçük DTO
✓ Value Object değer, doğrulama ve davranış taşır.

❌ Aggregate = mümkün olduğunca büyük nesne grafiği
✓ Aggregate = küçük tutulmuş transaction ve consistency boundary.

❌ Domain Service = iş kuralı çöplüğü
✓ Yalnızca tek Aggregate'e ait olmayan saf domain davranışı.

❌ Repository = her tablo için CRUD API
✓ Repository = Aggregate Root'un kalıcılık sınırı.

申請チェックリスト

  1. MoneyEmailAddressQuantity などの概念はプリミティブとして流通していますか?
  2. すべてのエンティティの動作は実際に無効な状態を防止しますか?
  3. 書き込みリクエストは複数の集計をアトミックに更新しようとしますか?
  4. アプリケーション サービスは意思決定を行いますか? それとも単に調整するだけですか?
  5. リポジトリは集約ルートのみをインストールしますか?

最初に最もコストのかかるビジネス ルールから始めます。システム全体を一度に戦術的な DDD に変えないでください。

この記事で覚えておくべきこと

価値オブジェクトは、概念の価値とルールを伝えます。エンティティはアイデンティティとライフサイクルを維持します。 Aggregate は、一貫性を保つために小さなトランザクション制限を設定します。リポジトリは、この制限を永続化します。

戦術的 DDD の目標は、クラスを追加することではなく、ビジネス ルールが間違った層に漏洩するのを防ぐことです。

次のセクションでは、より大きなシステム内でこれらの境界、つまり境界コンテキスト、コンテキスト マッピング、モノリス内の分解についてどのように扱うかを検討します。

FAQ

Frequently asked questions

値オブジェクトとは何ですか?

概念は同一性を持たず、その値によって定義され、一定に保たれなければなりません。

エンティティとは何ですか?

性質が変化しても、そのアイデンティティ全体が同じままであるオブジェクト。

「値オブジェクト = 小さい DTO」は正しいですか?

値オブジェクトは、値、検証、および動作を保持します。

このセクションでは何を修正しますか?

最初の部分では、ビジネスの言語とルールから始めました。ここで問題は、これらの決定をコードのどこに保持するかということです。同じ e コマース ドメイン (お金、注文明細、注文と支払いのフロー) を使用します。最初の部分では、ビジネスの言語とルールから始めました。ここで問題は、これらの決定をコードのどこに保持するかということです。同じ e コマース ドメイン (お金、注文明細、注文と支払いのフロー) を使用します。

学到的工程原理

  • Value Object は、プリミティブ データをビジネス セマンティクスおよび検証と組み合わせます。
  • 集計は小さく、明確な一貫性制限がある必要があります。
  • アプリケーション サービスはプロセスを管理します。ドメインの動作が決定します。

继续阅读

继续阅读

系列中的下一个

随笔

DDD は大規模システムでどのように動作しますか?

DDD は大規模システムでどのように拡張されますか?有界コンテキスト、コンテキスト マッピング、コンウェイの法則、モジュラー モノリス、マイクロサービス境界、トランザクション アウトボックスの決定…

系列中的下一个

同系列

Paylaş