The aggregate boundary is not a modelling preference — it is the answer to which invariants must hold at every instant, and everything else can be eventually consistent.
// inside: the total must always equal the sum of the lines
final class Order
{
public function addLine(Sku $sku, int $qty, Money $unit): void
{
$this->lines[] = new Line($sku, $qty, $unit);
$this->total = $this->recalculate();
}
}
// outside: stock levels. eventually consistent, via an event.
One transaction per aggregate is the rule that follows, and a use case needing two is telling you either that the boundary is wrong or that the second requirement is not really immediate. Referencing other aggregates by identity rather than by object reference is what keeps them separable, and it is the part that feels wrong to anyone used to an ORM navigating relations freely.