Aggregate
A boundary inside which consistency rules are enforced together.
An aggregate is a consistency boundary around a cluster of related objects. The aggregate root is the main entry point that protects invariants for that boundary. This is one of the most important tactical DDD ideas because it helps prevent a model from becoming a free-for-all of direct object mutations.
An order and its order lines may need to stay consistent together. Inventory reservations might belong to a different boundary. If every object can change every other object directly, important rules become fragile and persistence gets harder to reason about.
Aggregates help by saying: this cluster of objects changes together, and external code should go through one root to modify it. That root protects invariants and coordinates internal changes. This keeps consistency local and prevents arbitrary graph mutation.
The design challenge is finding the right aggregate size. Too small and invariants leak. Too large and the system becomes chatty, slow, and hard to evolve.
A boundary inside which consistency rules are enforced together.
The main entry point that guards the aggregate and exposes valid behavior.
Clearer invariants and fewer hidden side effects across the model.
Order aggregate may own its lines, total calculations, and state transitions. Payment authorization may be a different aggregate or even a different bounded context, depending on the business rules.
package org.javaomnibus.ecommerce.domain;
import java.util.ArrayList;
import java.util.List;
public final class Order {
private final OrderId id;
private final List<OrderLine> lines = new ArrayList<>();
public Order(OrderId id) {
this.id = id;
}
public void addLine(ProductId productId, int quantity) {
if (quantity <= 0) {
throw new IllegalArgumentException("Quantity must be positive");
}
lines.add(new OrderLine(productId, quantity));
}
}