Reputation: 500
Imagine two aggregates Product
and Order
. An Order
instance can have multiple Product
s as order line items and this association is done using an OrderLine
class.
Here are the classes:
public class Order {
.
.
Set<OrderLine> orderLines;
public void addProductToOrder(Product product) {
...
}
.
.
}
public class Product {
.
.
int stock
boolean isProductOutOfStock(int quantity) {
return stock - quantity < 0;
}
.
.
}
Now imagine the scenario where I want to add a product
to an Order
. So the application service method would be something like:
{
order.addProductToOrder(Product product);
}
product.isProductOutOfStock
check inside order.addProductToOrder
is not advised.domain service
?Upvotes: 0
Views: 236
Reputation: 9112
Given that an aggregate (by definition) must hold its own invariants only
I would restate as:
Given that an aggregate should enforce its own invariants
The invariant in this case would be something like:
"An order cannot be created with products that are out of stock."
And, in your case, it is the Order that is enforcing that invariant. The Product is simply providing a method that allows the Order to enquire about the product stock level.
So, in principle, your approach is fine.
However, be aware that that product and associated stock level will have been retrieved by the Application layer from the repository before it is added to the order. Therefore the value of the (int) stock property in the Product is only as fresh as the last retrieval from the database. Therefore two Orders being created at the same time could result in the first-to-complete assuming enough stock and the second-to-complete also assuming enough stock (without being aware that the first to complete order depleted that stock).
You'll need a strategy to solve that.
Upvotes: 1