samedi 15 octobre 2022

How to handle complex Aggregate Root invariant in DDD?

I have a library system that allows borrowing books for chosen time. I need to protect it from ordering the books if any of them is already fully booked in any point in this time.

So let's say in our stock we have these books and their counts:

Fellowship of the ring (x10)
The Shining (x1)

The user A decides to order both of these books in a quantity of 1 between 2022-01-01 and 2022-01-20.

When user B wants to order both of these books in quantity of 1 between 2022-01-15 and 2022-01-30 an error should be thrown, because The Shining is not available anymore.

Additionally - there is a configurable margin before and after each order to prepare (eg. 1 day would mean that user B can make the order starting as early as 2022-01-17).

Also at any point in time, library may buy new books and add them to stock, meaning that user B would be able to make an order.

Now the logic to check if books are available needs to find all orders for specified time, including the restocking margin and compare it to the overall available stock.

To simplify it I have split the time into 30min slots, so we can iterate through all slots in a given timeframe and calculate the stock for this slot.

Here is a sketch of my aggregate:

BookOrder

Members:
DateTime From
DateTime To
Book[] BooksOrdered

Methods:
CanOrder(from, to, books, stocksForTimeSpanWithMargin)
Order(from, to, books, stocksForTimeSpanWithMargin)

The problem is that all this logic is quite complex and the only way to enforce it via an aggregate root I can think of is retrieving ALL of the orders and feeding the aggregate with them via constructor. But it certainly wouldn't scale to 10000+ books, 10000+ orders per day for 2 years in future.

To reduce the data pushed into aggregate I could make the query for only specified items in only the specified time slots. It could still be a lot, but significantly less.

However this introduces another problem - part of the logic would be located in the DB query. How would aggregate root know if it received all orders from the timespan? It would have to work only with what it was given.

Aucun commentaire:

Enregistrer un commentaire