In the Vaughn Vernon red book sample project https://github.com/VaughnVernon/IDDD_Samples he organized the project in this way:
Bounded Context (1)
---- "Layers" or "Hexagonal areas" (1.1)
-------- A group of related aggregates (1.1.1)
----------- Agreggates and related entities and value objects
-------- Other group of related aggregates (1.1.1)
----------- Agreggates and related entities and value objects
For example:
iddd_agilepm (1)
---- application (1.1)
------- ...
------- domain (1.1)
---------- ...
---------- product (1.1.1)
------------- product aggregate and related entities and value objects
------------- release
---------------- release aggregate and related entities and value objects
------------- sprint
---------------- sprint aggregate and related entities and value objects
------------- backlogitem
---------------- backlogitem aggregate and related entities and value objects
---------- ...
----- ports/adapters (1.1)
-------- ...
iddd_collaboration
Is there a formal definition to "A group of related aggregates" inside a bounded context?
Is there a formal definition to "A group of related aggregates" inside a bounded context?
No. There is no standardized language that describes a group of related aggregates that is smaller than "bounded context".
The closest language I have seen is Udi Dahan's use of "autonomous component"; his example was something like a sales context, where you might have one business policy for your low volume customers and a completely different policy for your high volume "premium" customers. So we're serving the same business capability, but using different implementations to provide that capability.
But, as far as I can tell, it's "accidentally similar" to the sort of cluster of aggregates that you are thinking about, but not actually a match.
Related
I'm wondering how to approach making something like a denormalized universal relationships table within a Domain Design project (using NodeJS, NestJS). The relationships, similar to a 'like' in social media that can be applied to different item types, would potentially cross bounded contexts, but would not need to have knowledge of the context's domain and internal logic.
In database terms, this is the concept, though not generally good practice:
Table: Universal_Relationships
Rel_ID | Res_A_ID | Res_A_Type | Res_B_ID | Res_B_Type
12 23 2 344 6
Table: Resource_Types
Type_ID | Type_Name
2 Map_Location
6 Research_Reference
8 Photo
10 Artwork
11 Video
12 Note
[…]
Table: Map_Locations
Place_ID | Marker_Title | Coord_X (or Lat) | Coord_Y (or Long) | Description
2 Eugene 44.064319 -123.0825664 City
Table: Research_Reference
Ref_ID | Title | Publisher | Abstract
6 Tourist Guide Collins Guide to ...
Any help much appreciated, thanks
I suggest modeling a relationship as an aggregate (different kinds of relationships might be different aggregates or you might just have Relationship be an aggregate); since the relationships are between things between aggregates in different bounded contexts, this is probably going to be its own bounded context.
The aggregate is basically just holding references (by ID, not references in the programming language sense) to the roots of the related aggregates (if the relationship is free-form in terms of what can be related, these IDs would also encode the type of aggregate).
It bears noting that as we're crossing bounded contexts (which generally could conceivably start operating at network distance from each other), it's reasonably likely that some level of eventual consistency will come into play: I'd advise against trying to enforce strong foreign key-style constraints on the relationships unless you're absolutely sure that you'll never run bounded contexts at network distance from each other (and make it clear that this relationship bounded context will prevent that from being done).
I'm struggling to understand how to model my problem:
A Company can have many Teams.
Each Team must have a unique name per Company.
Reports for a particular Team must be retrievable, along with a list of all reports for a Company.
Just now, I have 3 Bounded Contexts's - Company, Team and Report. I believe I should move Team inside Company to enforce my unique name invariant - however, as I understand it:
"Nothing outside the Aggregate boundary can hold a reference to
anything inside, except to the root Entity".
If I can only reference an AR from my Report AR, I cannot store which Team my report belongs to - just the company.
I have considered that Team may exist as it's own BC and also within the Company BC. Creation of a Team would then only happen from within the Company BC as an Entity. Here, the naming and invariant enforcement of that Team name can be ensured. The Team BC would then still exist and a Report can still hold reference to the TeamId from the Report AR.
However, this would result in duplication of TeamId and TeamName - both within the Company BC and Team BC.
Does this approach sound ok, or am I missing something?
I'm confused if I have 3 BC's that should be 2 BC's, or missing a Team Entity concept within Company BC.
Maybe I'm confusing Bounded Contexts I only have/need Aggregate Roots - I'm not sure!
Gulp, help!
In your example Company and Team cannot be Bounded Contexts, it is entity (Company or Team can be Aggregation Root, it depends on the task), Company has Name identity, Team has CompanyName + TeamName identity.
Bounded Context is a cohesive set of models, which should reflect the meaning of the selected subdomain. Team and Company can form one BC, Reporting is another context.
If in your example Reporting is simply aggregate some information for easy display to the user, then this Reporting Bounded Context doesn't contain any Aggregation Roots, because there's no business logic and rules. In Reporting you should use simple DTOs to display the data.
Having a class Customer that has a list of up to 10 Orders:
Customer
--------
+orders:Order[0..10]
But that means Customer is associated with Order class via aggregation, also:
Customer Order
-------- <>-------------------> --------
+orders:Order[0..10]
Should I also indicate 0-10 in the class association? Because I saw many diagrams do but on the other hand, this is specified in the attribute of Customer.
In fact you have to choose how you want to show the fact that a customer has a list of up to 10 Orders. You can depict it as an attribute or an aggregation or both but this latest option could be confusing. In all case if you want to model that as association (or composition or aggreagation) you have to show the multiplicity otherwise it would not be clear...
For more information take look a the 9.5.3 section of UML 2.5 specification
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:
Consumable
ConsumableType
ConsumableActivity
Package
PackageItem
Consumer
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:
Center Create "Type A" 10
Center Create "Type B" 20
Center Send "Type A" 5 ConsumerId=25
Center Send "Type B" 15 ConsumerId=25
ConsumerId=25 Receive "Type A" 5
ConsumerId=25 Receive "Type B" 15
ConsumerId=25 Consume "Type A" 3
ConsumerId=25 Consume "Type B" 1
ConsumerId=25 Consume "Type A" 2
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.
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.
Marked my aggregate roots with 1;2;3. Looks quite nice - almost like grapes.
Thing I dislike is an entity that's marked with red arrow.
Let's imagine that:
AR #1 is company
AR #2 is office
AR #3 is employee
Entity marked with red arrow is named Country
Company sets the rules from which countries it hires employees (on hiring, company.Countries.Contains(employee.Country) must be true)
I somehow see this quite unimportant part of domain (maybe it does not sound like that in this example one), and I would like to avoid promoting Country to aggregate root.
Glossary about aggregate roots says:
Transient references to the internal members can be passed out for use within a single operation only.
So - does introducing something like 'EmployeeCountry', removing reference to company Country and checking if Employee country matches any company country on hiring operation sounds reasonable?
Any other ideas?
How can I get my grapes look like they should?
In this context Country is just a value object, not an entity - much less an aggregate root - so there's no reason to change anything about your design (without more information).
Additionally, note that the warning you cite pertains to internal members of aggregate roots, not aggregates themselves. There's nothing wrong with maintaining references to aggregates in multiple places. Aggregate roots are supposed to encapsulate child objects so that there's a single place to enforce business rules for related objects.
You can see this clearly in several places in Evans' "Domain-Driven Design" (a.k.a., "The Blue Book"). For example, see the diagram on page 127 (in the introduction to aggregate roots), which shows a Car aggregate that has a reference to an Engine aggregate.