4. More and more entities: Complexity!
Product
Customer
Order
5. And a couple of iterations later...
OrderItem
Customer
Order
Product
Invoice
….
….
….
….
...
….
6. And after some more iterations...
OrderItem
Customer
Order
Product
Invoice
….
….
….
….
...
….
….
….
….
….
….
….
….
….
….
….
….
….
7. Complex data layer: Queries!
SELECT *
FROM ….
WHERE id IN (
SELECT id FROM product
INNER JOIN invoice …
INNER JOIN orderitem ...
INNER JOIN order
INNER JOIN …
INNER JOIN …
WHERE order.customerId = ?
AND …
AND …
) AND … IN (
SELECT id FROM product
INNER JOIN invoice …
INNER JOIN orderitem ...
WHERE …
) AND … IN (
SELECT id FROM product
INNER JOIN invoice …
INNER JOIN orderitem ...
WHERE …
)
…...
12. Anemic domain model
public class OrderLine {
private int quantity;
private BigDecimal price;
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
}
13. Result
Data inconsistency!
● Domain constraints not enforced by all services
● Multiple concurrent transactions over huge relational data model lead to inconsistencies
17. Domain Driven Design:
It is difficult to guarantee the consistency of changes to objects in a model with
complex associations. Invariants need to be maintained that apply to closely
related groups of objects, not just discrete objects.
[Domain Driven Design - Eric Evans]
20. Aggregate
• The root ENTITY is ultimately responsible for checking invariants.
• Nothing outside the AGGREGATE boundary can hold a reference to anything inside, except to the
root ENTITY. The root ENTITY can hand references to the internal ENTITIES to other objects, but
those objects can use them only transiently, and they may not hold on to the reference.
• As a corollary to the previous rule, only AGGREGATE roots can be obtained directly with database
queries. All other objects must be found by traversal of associations.
• A delete operation must remove everything within the AGGREGATE boundary at once.
• When a change to any object within the AGGREGATE boundary is committed, all invariants of the
whole AGGREGATE must be satisfied.
[Domain driven design - Eric Evans]
21. Aggregate pitfalls
Don’t make your aggregates too big
● Remember editing an aggregate requires checking all business invariants which requires to
load all state of the aggregate.
● This results in huge transactions and memory usage
● Large aggregates means more chance that users interfere by editing parts of the same
aggregate
○ which should result in either an optimistic lock exception or in case of pessimistic locks
not being able to edit an aggregate.
22. Aggregate advantages
An aggregate is a small collection of entities that are kept consistent by invariant checking
● The aggregate can only check it invariants on its own internal state
● With (unit) tests you can easily prove that your aggregates stay consistent, because you don’t
need the state of any other part of the system
● Using small aggregates reduces the complexity of your application
○ Testing is simpler
○ Fewer moving state when processing an update
23. Long running business transactions across multiple
aggregates: Webshop
● A customer can only order a product if there is still stock in the inventory
● An order can only succeed if the customer has paid the order amount
25. Solution: Separate aggregates using eventual
consistency
Product
(AggregateRoot)
productId
amountInStock
productPrice
Payment
(AggregateRoot)
amount
isPaid
OrderManager
(AggregateRoot)
1. Order request
1.1 Reserve
Stock
1.1 Initiate
payment 2. Payment
Successful
3. Payment
failed
2.1 Order
fulfilled
3.1 Unreserve
stock
26. Invariants across multiple aggregates
Any rule that spans AGGREGATES will not be expected to be up-to-date at all times.
Through event processing, batch processing, or other update mechanisms, other
dependencies can be resolved within some specific time. [Domain Driven Design]
29. Advantages CQRS
● We model business actions (commands) and important business events (event)
○ The intent of a business transactions is better captured in commands than in just crud
operations on a database
● Separate read model allows for scaling reads independently
● We can observe a business interaction from the outside (by observing the events) without
knowing the inner details of the aggregate (state and business invariants)