Reputation: 282
I am kindly asking for your guidance on where the logic connecting various entities and aggregate roots should reside. In our upcoming project, the code architecture will combine Domain-Driven Design (DDD), Clean Architecture (CA), Command Query Separation (CQS), and use-cases based on REST. Despite reading two books on these topics, numerous articles, and even consulting with Chat-GPT, there is still one aspect we don't fully understand: where to place the logic that connects multiple aggregate roots and domains in an ERP system.
I've considered many possibilities, but none seem satisfactory.
From my understanding:
Could you please explain where the logic that connects multiple aggregate roots and domains should be placed?
Let me present the best workflow I've found so far. Let's take the Order Management domain as an example. There are three entities: Order, OrderLine, and OrderBatch. The domain layer will contain logic to ensure data correctness. Each entity will have value objects and methods for validating aspects such as quantity or stock, ensuring they aren't too low, and the SKU number. The persistence layer, in this case, is Entity Framework Core, which handles mapping to the RDBMS. We wont use the repository pattern (an extra abstraction layer is unnecessary, we won't be changing the ORM). So far, so good.
Now, let's discuss the challenges. We have a use case called "UpdateOrderBatch," which updates the quantity ordered in a particular batch. The controller will call the use case, which will then use... well what exactly?
Here is some pseudo-code:
USECASE UpdateOrderBatch
SELECT data for the entire aggregate root of the order (Orders, OrderLines, OrderBatches)
SELECT all related aggregate roots
The entire business logic validation lives here (like checking if stock can be decreased)
CALL reusable service methods (InventoryManagementService.DecreaseBatchStock, OrderService.SaveOrder, etc.)
Upvotes: -1
Views: 73
Reputation: 53
If I understand correctly your problem the answer is domain events. Assuming you are using a RDBMS, ie SQL DB.
You have an order aggregate that contains some entities (one of which is the aggregate root entity) and value-objects. If you want to make a change to this aggregate and make sure that let’s say the inventory aggregate is also updated your aggregate needs to create a domain event (ex. BatchUpdatedEvent). The suggested way to do this is to have something like an AggregateRoot base class that will have a ‘List’ field and a protected method addDomainEvent that you can call inside your domain model (BatchUpdatedEvent will extend your custom DomainEvent class/record) and has no interaction with any infrastructure. Then in your application service you will iterate through the aggregate’s domain events and publish them (I prefer to do this after the DB transaction for saving the aggregate changes completes). To publish the events you can either use some pub-sub/queue tool like Kafka especially if the communication is across different micro-services (but not necessarily) or your can use some library (ex. MediatR for .NET, ApplicationEventPublisher for SpringBoot Java) if both aggregates are within the same service. Then you will define a DomainEventHandler for the given event that will make the updates to another aggregate and store it in the database. Note that with this approach the second aggregate is eventually consistent as the second aggregate is stored in the database in a different transaction. For more details you can read the papers by Vaughn Vernon on Designing Aggregates or even better check his (red) book called Implementing Domain-Driven Design.
A couple of good resources to get you started:
https://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/
https://www.dddcommunity.org/library/vernon_2011/
Upvotes: 0