aggregate-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Aggregate Design Patterns

聚合设计模式

Design aggregates with clear boundaries, invariants, and consistency guarantees.
设计具有清晰边界、不变量和一致性保障的Aggregate(聚合)。

Overview

概述

  • Defining transactional consistency boundaries
  • Enforcing business invariants across related entities
  • Designing aggregate roots and their children
  • Handling references between aggregates
  • Optimizing aggregate size for performance
  • 定义事务一致性边界
  • 在关联实体间执行业务不变量
  • 设计Aggregate Root(聚合根)及其子实体
  • 处理聚合间的引用
  • 优化聚合规模以提升性能

Core Concepts

核心概念

┌─────────────────────────────────────────────────────────┐
│                 ORDER AGGREGATE                         │
│  ┌─────────────────────────────────────────────────┐   │
│  │         Order (Aggregate Root)                   │   │
│  │  • id: UUID (UUIDv7)                            │   │
│  │  • customer_id: UUID (reference by ID!)         │   │
│  │  • status: OrderStatus                          │   │
│  └─────────────────────────────────────────────────┘   │
│           │                      │                      │
│  ┌────────────────┐    ┌────────────────┐              │
│  │  OrderItem     │    │  OrderItem     │              │
│  │  (child)       │    │  (child)       │              │
│  └────────────────┘    └────────────────┘              │
│                                                         │
│  INVARIANTS enforced by root:                          │
│  • Total = sum of items                                │
│  • Max 100 items per order                             │
│  • Cannot modify after shipped                         │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│                 ORDER AGGREGATE                         │
│  ┌─────────────────────────────────────────────────┐   │
│  │         Order (Aggregate Root)                   │   │
│  │  • id: UUID (UUIDv7)                            │   │
│  │  • customer_id: UUID (reference by ID!)         │   │
│  │  • status: OrderStatus                          │   │
│  └─────────────────────────────────────────────────┘   │
│           │                      │                      │
│  ┌────────────────┐    ┌────────────────┐              │
│  │  OrderItem     │    │  OrderItem     │              │
│  │  (child)       │    │  (child)       │              │
│  └────────────────┘    └────────────────┘              │
│                                                         │
│  INVARIANTS enforced by root:                          │
│  • Total = sum of items                                │
│  • Max 100 items per order                             │
│  • Cannot modify after shipped                         │
└─────────────────────────────────────────────────────────┘

Four Rules

四条规则

  1. Root controls access - External code only references aggregate root
  2. Transactional boundary - One aggregate per transaction
  3. Reference by ID - Never hold references to other aggregates
  4. Invariants enforced - Root ensures all business rules
  1. 聚合根控制访问 - 外部代码仅引用Aggregate Root
  2. 事务边界 - 每个事务仅涉及一个聚合
  3. 通过ID引用 - 绝不持有其他聚合的对象引用
  4. 强制执行不变量 - 聚合根确保所有业务规则都被遵守

Quick Reference

快速参考

python
from dataclasses import dataclass, field
from uuid import UUID
from uuid_utils import uuid7

@dataclass
class OrderAggregate:
    """Aggregate root with invariant enforcement."""

    id: UUID = field(default_factory=uuid7)
    customer_id: UUID  # Reference by ID, not Customer object!
    _items: list["OrderItem"] = field(default_factory=list)
    status: str = "draft"

    MAX_ITEMS = 100

    def add_item(self, product_id: UUID, quantity: int, price: Money) -> None:
        """Add item with invariant checks."""
        self._ensure_modifiable()
        if len(self._items) >= self.MAX_ITEMS:
            raise DomainError("Max items exceeded")
        self._items.append(OrderItem(product_id, quantity, price))

    def _ensure_modifiable(self) -> None:
        if self.status != "draft":
            raise DomainError(f"Cannot modify {self.status} order")
See aggregate-root-template.py for complete implementation.
python
from dataclasses import dataclass, field
from uuid import UUID
from uuid_utils import uuid7

@dataclass
class OrderAggregate:
    """Aggregate root with invariant enforcement."""

    id: UUID = field(default_factory=uuid7)
    customer_id: UUID  # Reference by ID, not Customer object!
    _items: list["OrderItem"] = field(default_factory=list)
    status: str = "draft"

    MAX_ITEMS = 100

    def add_item(self, product_id: UUID, quantity: int, price: Money) -> None:
        """Add item with invariant checks."""
        self._ensure_modifiable()
        if len(self._items) >= self.MAX_ITEMS:
            raise DomainError("Max items exceeded")
        self._items.append(OrderItem(product_id, quantity, price))

    def _ensure_modifiable(self) -> None:
        if self.status != "draft":
            raise DomainError(f"Cannot modify {self.status} order")
完整实现请查看 aggregate-root-template.py

Key Decisions

关键决策

DecisionRecommendation
Aggregate sizeSmall (< 20 children), split if larger
Cross-aggregate refsAlways by ID, never by object
ConsistencyImmediate within, eventual across
EventsCollect in root, publish after persist
See aggregate-sizing.md for sizing guidelines.
决策项建议方案
聚合规模保持小型(子实体少于20个),若超出则拆分
跨聚合引用始终通过ID引用,绝不使用对象引用
一致性保障聚合内强一致性,聚合间最终一致性
事件处理在聚合根中收集事件,持久化后发布
规模设计指南请查看 aggregate-sizing.md

Anti-Patterns (FORBIDDEN)

反模式(禁止使用)

python
undefined
python
undefined

NEVER reference aggregates by object

NEVER reference aggregates by object

customer: Customer # WRONG → customer_id: UUID
customer: Customer # WRONG → customer_id: UUID

NEVER modify multiple aggregates in one transaction

NEVER modify multiple aggregates in one transaction

order.submit() inventory.reserve(items) # WRONG - use domain events
order.submit() inventory.reserve(items) # WRONG - use domain events

NEVER expose mutable collections

NEVER expose mutable collections

def items(self) -> list: return self._items # WRONG → return tuple(self._items)
def items(self) -> list: return self._items # WRONG → return tuple(self._items)

NEVER have unbounded collections

NEVER have unbounded collections

orders: list[Order] # WRONG - grows unbounded
undefined
orders: list[Order] # WRONG - grows unbounded
undefined

Related Skills

相关技能

  • domain-driven-design
    - DDD building blocks (entities, VOs)
  • distributed-locks
    - Cross-aggregate coordination
  • idempotency-patterns
    - Safe retries
  • domain-driven-design
    - DDD基础组件(实体、值对象)
  • distributed-locks
    - 跨聚合协调
  • idempotency-patterns
    - 安全重试

References

参考资料

  • Aggregate Sizing - When to split
  • Invariant Enforcement - Business rules
  • Eventual Consistency - Cross-aggregate
  • Aggregate Sizing - 拆分时机
  • Invariant Enforcement - 业务规则
  • Eventual Consistency - 跨聚合

Capability Details

能力详情

aggregate-root

aggregate-root

Keywords: aggregate root, consistency boundary, transactional Solves: Design aggregate roots, control child access, enforce boundaries
关键词: aggregate root, 一致性边界, 事务性 解决问题: 设计聚合根, 控制子实体访问, 执行边界约束

invariants

invariants

Keywords: invariant, business rule, validation, specification Solves: Enforce business rules, validate state, specification pattern
关键词: invariant, 业务规则, 校验, 规格模式 解决问题: 执行业务规则, 校验状态, 规格模式应用

aggregate-sizing

aggregate-sizing

Keywords: aggregate size, small aggregate, performance Solves: Right-size aggregates, when to split, performance trade-offs
关键词: aggregate size, 小型聚合, 性能 解决问题: 合理设置聚合规模, 拆分时机判断, 性能权衡

cross-aggregate

cross-aggregate

Keywords: reference by ID, eventual consistency, domain events Solves: Reference other aggregates, coordinate changes, eventual consistency
关键词: 按ID引用, 最终一致性, 领域事件 解决问题: 引用其他聚合, 协调变更, 最终一致性实现