Aggregate
A cluster of domain objects that are treated as a single unit for data changes and consistency.
An aggregate is a cluster of domain objects that must always be consistent with each other. You treat them as a single unit when saving, loading, and applying business rules.
The classic example: an Order with its OrderLines. You don't save an order line on its own, because it makes no sense without the order. The order is the aggregate root: the entry point through which all changes to the cluster go.
In practice, this means you don't keep a repository per SQL table. You keep a repository per aggregate. Even if the data spans multiple tables, a single repository loads and saves the whole aggregate in one transaction. This guarantees consistency without complex transaction coordination across multiple repositories.
Aggregates also define transaction boundaries. Changes within one aggregate are atomic. Changes across different aggregates are eventually consistent. This constraint forces you to think carefully about what data truly belongs together.
Getting the aggregate boundaries right is one of the hardest parts of domain modeling. Too large, and you get contention and slow writes. Too small, and you end up needing distributed transactions to keep things consistent. Event Storming is a practical technique for discovering these boundaries before writing code.
References
- Database Transactions in Go with Layered Architecture — Explains aggregates as sets of data that must be transactionally consistent, with one repository per aggregate rather than per table. Shows the UpdateFn pattern for loading and storing aggregates.
- Common Anti-Patterns in Go Web Applications — Mentions aggregates and the repository pattern as DDD-inspired techniques for saving domain objects transactionally, regardless of the number of database tables.
- DDD: A Toolbox, Not a Religion — Discusses why DDD terminology like aggregates and bounded contexts can be confusing at first, and how to use DDD as a practical toolbox rather than dogma.
- Event-Driven Architecture: The Hard Parts — Connects the aggregate pattern from DDD to event ordering, suggesting the aggregate as the smallest transactional boundary for determining which events need strict ordering.
- Synchronous vs Asynchronous Architecture — Discusses using incremental versions within an aggregate to handle out-of-order events and maintain consistency in asynchronous systems.