Reputation: 376
I am learning DDD concepts and to strengthen my understanding I am working on some real world examples.
I know that an aggregate should have only one entry point through the root entity and an aggregate should have only one repository (please correct me if I understood it totally wrong)
Now assume that there are consumables with specific types and these consumables are sent from a distribution center. Sending specific types of consumables depends on their quantity, I mean if one of the consumers has a critic quantity 10 for type A and B and those item quantities fall under 10 then the distribution center sends type A and B consumables. Here both the sender and consumer wants to track where the sent package is or if it is delivered or sent at all.
So here, as entities, we have:
I am confused about the first three entities: which one should be the aggregate root? In a fast look it seems that the consumable is a strong candidate but on the other hand we do not care about every consumable, we are only interested in their quantity. We don't record 10 different type A consumables but only have a type A record with quantity which changes according to activities. At this point Consumable entity seems redundant, by just looking at activities we can derive the quantity. For example starting from scratch:
Here we can derive that there are 5 Type A and B consumables at the center and 0 Type A, 14 Type B consumables at consumer with id 25 for now.
Of course this is not an effective approach while after there are much more activities it will take some time to derive consumable quantities, so there should be a static quantity field for every consumable type both for consumers and the distribution center in which we can read the current quantity at once.
I hope you get why I am confused, the consumable entity looks like a root entity but actually it doesn't really fit in to be a root entity if not an entity also.
Can anyone suggest me some improvements about this design or and further reading recommendations which are not limited to customer-product-order-orderline nightmare?
Edit : What is the relation with Consumable and ConsumableType ? What if I want to conduct CRUD operations on ConsumableType (to make the user add new types, change or delete them) but the root entity is Consumable. In order to DDD to preserve data integrity we should't load any repository other than the root entity repository.
Edit 2: Think about a Product entity and its Category entity. The Product seems to be the root entity but we know that products cannot exist without a category. So is the Category entity the root? If so, according to DDD rules, we can access products only by traversing. But in our context the Product is our focus. Then it is supposed that we have two aggregates: Product Aggregate and Category Aggregate. But this time we violate the data integrity because a category may be deleted without deleting products having this category. So I am confused a lot and couldn't find a proper solution.
Upvotes: 0
Views: 812
Reputation: 2691
I am confused about the first three entities: which one should be the aggregate root?
I am going to say that, most likely, your aggregate is Package even though there is the possibility that this example should be split into two or more separate bounded contexts. (creation and order fulfillment are natural boundaries)
What is the relation with Consumable and ConsumableType ?
It depends on your bounded context. Without knowing any more about ConsumableType other than it is designated by "A" or "B", I would have to say that it is more than likely a value object of Consumable.
What if I want to conduct CRUD operations on ConsumableType (to make the user add new types, change or delete them) but the root entity is Consumable
This is most likely a different bounded context altogether (context of some manager or something that doesn't fall within the general workflow we're modeling) for which more investigation about this context is suggested.
[Different Example]
So is the Category entity the root?
The aggregate root is what the user in the context interacts with. Assuming ALOT because you don't fully explain the context in this example, most likely the Product is the aggregate root because that is what the user cares most about. Same as the above example, Product would have a repository that would load it's assigned category to it. Loading the list of categories or hierarchy is best served by a domain service in this case because it doesn't belong to any particular entity instance.
[Another Example]
in your first case, how can, for example a system administrator, list all available font colors or add a new one?
Again, the context of a system administrator is not the same context as the user who chooses the font color. Remember, each context is a single workflow. In complex workflows, there can be multiple users in the same context, but for the simple workflows like the CRUD operations an administrator might perform, generally there is only one role for this type of workflow. Under the system administrator, AvailableFontColor might be an entity with a Color value property within the Content Decoration Options Administration bounded context.
Can anyone suggest me some improvements about this design or and further reading recommendations which are not limited to customer-product-order-orderline nightmare?
I would suggest that you learn more about bounded contexts and why they are one of your most useful (and most hampering at times) tools in modeling a business domain. Also, don't expect to have this perfected to a science within a week.
I have been modeling software using various techniques for over 8 years now and there are still times where I have trouble deciding if I modeled something correctly or not. I think one of the greatest benefits of DDD is that it encourages you to embrace the fact that you probably won't model correctly from the beginning so you should make it easy to change the model and refactor often as you learn more about your domain rather than just going with what you have and ending up with 15 different convoluted cludges around your original model because you didn't fully understand the domain from the beginning.
Upvotes: 2