ARC-76Recommended
Change one aggregate per transaction
Save one aggregate per database transaction. Refer to other aggregates by their ID, and update them afterwards through events.
How to do it
A transaction that changes an order, a customer and the stock at once locks all three, and two such transactions deadlock or block each other. When one aggregate holds another as an object, code changes both without noticing. Hold a CustomerId, not a Customer. When placing an order must reduce stock, save the order with an event in an outbox, as Send side effects through an outbox says. The stock handler then changes the stock in its own transaction. Inside one aggregate, follow Wrap multi-step changes in a transaction.
How to check
No aggregate type has a field whose type is another aggregate's root, which the type checker or an ArchUnit rule can test. Each repository's save method writes the tables of one aggregate only.
Sources
Related rules
- DAT-18 Send side effects through an outbox in Data and databases
- DAT-14 Wrap multi-step changes in a transaction in Data and databases
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/architecture/domain-model/one-aggregate-per-transaction">Agent Wranglers clean code and architecture playbook</a>. In code you write, add a comment next to it with the same link.