DDD | hierarchy (same types) | constraint - domain-driven-design

I've looked at 2 other questions that seem related:
Is Aggregate Root with Deep Hierarchy appropriate in DDD?
How to define DDD Aggregate root for hierarchical data structure?
However they're not exactly the same as my situation; maybe missing the "constraint" aspect.
My situation: I have an AR named "Study", and a Study can be organized by cluster (borrowing from clustered-sampling concept in survey domain).
Let's say this "Study" takes this parameter "clusteringDepth" (an integer) in is constructor. Let's say: I specify 3 (provinces, counties, cities).
That's just a spec. of a Study. When you actually conduct a study, you create an instance of StudyPlan based on the Study.
So, in this case I will have an instance of StudyPlan that has a list of provinces (first-level clusters). Each province, has a list of counties (second-level clusters), and each county has list of cities (third / final-level clusters).
On each cluster you can attach quota information, and date range (specifying how many interviews you have to raise in that cluster, and the date interval for the interviews). Obviously a parent cluster must maintain invariants like "sum of quotas of child clusters must be less or equal to the quota of this cluster".
Ok..., now, the constraint: you can plan an interview with a respondent. For that you'd create an instance of InterviewPlan. But..., this interviewplan can only be attached to terminal (third-level) clusters.
Of course, it's easy to implement that constraint (e.g.: in the addInterviewPlan method of a cluster, I'd check if the cluster has a parent or no).
But..., for some reason... I think this is not a good DDD design. That constraint sounds too technical; it doesn't go naturally in a normal domain conversation.
My question: am I over-interpreting DDD "language-fluidity/naturalness requirement"? or... am I missing a concept? I mean, should I invent another domain model, something, that can be a child of cluster and have associated interviewPlan?
Thanks,
Raka
Other related: http://git.net/ml/programming.domain-driven-design/2006-06/msg00028.html

I don't think it is too tehnical. Domain experts knows basic math like sum and in this case they even create that tule.
Tehnical invariants imply tehnical things like tables, indexes, columns, rows, IDs, functions etc.

Related

What is an Aggregate Root?

No, it is not a duplication question.
I have red many sources on the subject, but still I feel like I don't fully understand it.
This is the information I have so far (from multiple sources, be it articles, videos, etc...) about what is an Aggregate and Aggregate Root:
Aggregate is a collection of multiple Value Objects\Entity references and rules.
An Aggregate is always a command model (meant to change business state).
An Aggregate represents a single unit of (database - because essentialy the changes will be persisted) work, meaning it has to be consistent.
The Aggregate Root is the interface to the external world.
An Aggregate Root must have a globally unique identifier within the system
DDD suggests to have a Repository per Aggregate Root
A simple object from an aggregate can't be changed without its AR(Aggregate Root) knowing it
So with all that in mind, lets get to the part where I get confused:
in this site it says
The Aggregate Root is the interface to the external world. All interaction with an Aggregate is via the Aggregate Root. As such, an Aggregate Root MUST have a globally unique identifier within the system. Other Entites that are present in the Aggregate but are not Aggregate Roots require only a locally unique identifier, that is, an Id that is unique within the Aggregate.
But then, in this example I can see that an Aggregate Root is implemented by a static class called Transfer that acts as an Aggregate and a static function inside called TransferedRegistered that acts as an AR.
So the questions are:
How can it be that the function is an AR, if there must be a globaly unique identifier to it, and there isn't, reason being that its a function. what does have a globaly unique identifier is the Domain Event that this function produces.
Following question - How does an Aggregate Root looks like in code? is it the event? is it the entity that is returned? is it the function of the Aggregate class itself?
In the case that the Domain Event that the function returns is the AR (As stated that it has to have that globaly unique identifier), then how can we interact with this Aggregate? the first article clearly stated that all interaction with an Aggregate is by the AR, if the AR is an event, then we can do nothing but react on it.
Is it right to say that the aggregate has two main jobs:
Apply the needed changes based on the input it received and rules it knows
Return the needed data to be persisted from AR and/or need to be raised in a Domain Event from the AR
Please correct me on any of the bullet points in the beginning if some/all of them are wrong is some way or another and feel free to add more of them if I have missed any!
Thanks for clarifying things out!
I feel like I don't fully understand it.
That's not your fault. The literature sucks.
As best I can tell, the core ideas of implementing solutions using domain driven design came out of the world of Java circa 2003. So the patterns described by Evans in chapters 5 and six of the blue book were understood to be object oriented (in the Java sense) domain modeling done right.
Chapter 6, which discusses the aggregate pattern, is specifically about life cycle management; how do you create new entities in the domain model, how does the application find the right entity to interact with, and so on.
And so we have Factories, that allow you to create instances of domain entities, and Repositories, that provide an abstraction for retrieving a reference to a domain entity.
But there's a third riddle, which is this: what happens when you have some rule in your domain that requires synchronization between two entities in the domain? If you allow applications to talk to the entities in an uncoordinated fashion, then you may end up with inconsistencies in the data.
So the aggregate pattern is an answer to that; we organize the coordinated entities into graphs. With respect to change (and storage), the graph of entities becomes a single unit that the application is allowed to interact with.
The notion of the aggregate root is that the interface between the application and the graph should be one of the members of the graph. So the application shares information with the root entity, and then the root entity shares that information with the other members of the aggregate.
The aggregate root, being the entry point into the aggregate, plays the role of a coarse grained lock, ensuring that all of the changes to the aggregate members happen together.
It's not entirely wrong to think of this as a form of encapsulation -- to the application, the aggregate looks like a single entity (the root), with the rest of the complexity of the aggregate being hidden from view.
Now, over the past 15 years, there's been some semantic drift; people trying to adapt the pattern in ways that it better fits their problems, or better fits their preferred designs. So you have to exercise some care in designing how to translate the labels that they are using.
In simple terms an aggregate root (AR) is an entity that has a life-cycle of its own. To me this is the most important point. One AR cannot contain another AR but can reference it by Id or some value object (VO) containing at least the Id of the referenced AR. I tend to prefer to have an AR contain only other VOs instead of entities (YMMV). To this end the AR is responsible for consistency and variants w.r.t. the AR. Each VO can have its own invariants such as an EMailAddress requiring a valid e-mail format. Even if one were to call contained classes entities I will call that semantics since one could get the same thing done with a VO. A repository is responsible for AR persistence.
The example implementation you linked to is not something I would do or recommend. I followed some of the comments and I too, as one commenter alluded to, would rather use a domain service to perform something like a Transfer between two accounts. The registration of the transfer is not something that may necessarily be permitted and, as such, the domain service would be required to ensure the validity of the transfer. In fact, the registration of a transfer request would probably be a Journal in an accounting sense as that is my experience. Once the journal is approved it may attempt the actual transfer.
At some point in my DDD journey I thought that there has to be something wrong since it shouldn't be so difficult to understand aggregates. There are many opinions and interpretations w.r.t. to DDD and aggregates which is why it can get confusing. The other aspect is, in IMHO, that there is a fair amount of design involved that requires some creativity and which is based on an understanding of the domain itself. Creativity cannot be taught and design falls into the realm of tacit knowledge. The popular example of tacit knowledge is learning to ride a bike. Now, we can read all we want about how to ride a bike and it may or may not help much. Once we are on the bike and we teach ourselves to balance then we can make progress. Then there are people who end up doing absolutely crazy things on a bike and even if I read how to I don't think that I'll try :)
Keep practicing and modelling until it starts to make sense or until you feel comfortable with the model. If I recall correctly Eric Evans mentions in the Blue Book that it may take a couple of designs to get the model closer to what we need.
Keep in mind that Mike Mogosanu is using a event sourcing approach but in any case (without ES) his approach is very good to avoid unwanted artifacts in mainstream OOP languages.
How can it be that the function is an AR, if there must be a globaly unique identifier to it, and there isn't, reason being that
its a function. what does have a globaly unique identifier is the
Domain Event that this function produces.
TransferNumber acts as natural unique ID; there is also a GUID to avoid the need a full Value Object in some cases.
There is no unique ID state in the computer memory because it is an argument but think about it; why you want a globaly unique ID? It is just to locate the root element and its (non unique ID) childrens for persistence purposes (find, modify or delete it).
Order A has 2 order lines (1 and 2) while Order B has 4 order lines (1,2,3,4); the unique identifier of order lines is a composition of its ID and the Order ID: A1, B3, etc. It is just like relational schemas in relational databases.
So you need that ID just for persistence and the element that goes to persistence is a domain event expressing the changes; all the changes needed to keep consistency, so if you persist the domain event using the global unique ID to find in persistence what you have to modify the system will be in a consistent state.
You could do
var newTransfer = New Transfer(TransferNumber); //newTransfer is now an AG with a global unique ID
var changes = t.RegisterTransfer(Debit debit, Credit credit)
persistence.applyChanges(changes);
but what is the point of instantiate a object to create state in the computer memory if you are not going to do more than one thing with this object? It is pointless and most of OOP detractors use this kind of bad OOP design to criticize OOP and lean to functional programming.
Following question - How does an Aggregate Root looks like in code? is it the event? is it the entity that is returned? is it the function
of the Aggregate class itself?
It is the function itself. You can read in the post:
AR is a role , and the function is the implementation.
An Aggregate represents a single unit of work, meaning it has to be consistent. You can see how the function honors this. It is a single unit of work that keeps the system in a consistent state.
In the case that the Domain Event that the function returns is the AR (As stated that it has to have that globaly unique identifier),
then how can we interact with this Aggregate? the first article
clearly stated that all interaction with an Aggregate is by the AR, if
the AR is an event, then we can do nothing but react on it.
Answered above because the domain event is not the AR.
4 Is it right to say that the aggregate has two main jobs: Apply the
needed changes based on the input it received and rules it knows
Return the needed data to be persisted from AR and/or need to be
raised in a Domain Event from the AR
Yes; again, you can see how the static function honors this.
You could try to contat Mike Mogosanu. I am sure he could explain his approach better than me.

DDD: University as an aggregate root

For some time I am dealing with Domain-Driven Design. Unfortunately I have some problems regarding the Aggregate.
Say, I like to model the structure of an university. The university has some departments (faculties) and every department has some classes. There is a rule that every department needs to be unique and so every class in it. For instance the names of the classes needs to be unique. If I understand it right, then "University" seems to be my aggregate root and "department" and "class" are entities within this aggregate.
There is another aggregate root "Professor", because they are globally accessible. They will be assigned to a class. I´m unsure if it is allowed because an aggregate root should only point to another aggregate root and not to its content.
How to handle this?
Appreciate your help,
thanks in advance!
Say, I like to model the structure of an university. The university has some departments (faculties) and every department has some classes. There is a rule that every department needs to be unique and so every class in it. For instance the names of the classes needs to be unique.
Really? why? What's the business value of that rule? What does it cost the business (the university) if there happen to be two classes with the same name. Does that mean the same name across all time, or just during a given semester?
Part of the point of DDD is that the design of the solution requires exploration of the "ubiquitous language" to get a full understanding of the requirement.
In other words, you may be having trouble finding a good fit for this requirement in the design because you haven't yet discovered all of the entities that you need to make it work the way the business experts expect.
Udi Dahan points out that the uniqueness rule may not belong in the domain at all:
Rules that are not part of genuine domain logic do not have to be implemented in the domain model, suggested he, because they do not model the domain.
So if you have a constraint like this, but the constraint isn't a consequence of the domain itself, then the constraint can be correctly implemented elsewhere.
Greg Young has also written about set validation, specifically addressing concerns about eventual consistency.
But broadly, yes -- if you really have a collection of entities, and a domain rules that span multiple elements in the collection, then you need some aggregate that maintains the integrity of the boundary that the collection lives in.
The entities aren't necessarily what you think. For instance, if you need names to be unique, and the rest of the class entity is just along for the ride, then you may be able to simplify the rules by creating a name registry aggregate; Professors reserve names for their classes, and if the reservation is available, then the reserved name can be applied to the class entity.
If your core business really were naming things, with lots of special invariants to consider, you might build out a big model around this. But that's not particularly likely; perhaps you can just slap a table or two into a relational database -- that's a good solution for a set validation problem -- and get on with the valuable part of the project.
There is another aggregate root "Professor", because they are globally accessible. They will be assigned to a class. I´m unsure if it is allowed because an aggregate root should only point to another aggregate root and not to its content.
class.assign(professorId);
is the usual sort of answer here -- you pass around the surrogate key that identifies the aggregate root. Every entity in your domain should have one.
A couple of cautions here: I have found that real world entities (people, in particular) aren't a useful starting point for figuring out what aggregates are for. Primarily, because they end up being representations, primarily, of data where the invariant is enforced outside the domain model.
Also, I've found that starting from the nouns - class, department, professor - tends to put the focus on CRUD, which generally isn't a very interesting problem.
Instead, I recommend thinking about doing something useful -- a use case where there are business rules to enforce, when the business model gets to say "no, the business won't let you do that right now".
Ask yourself these questions:
How many universities will be in your system? If this is only one, it is not your aggregate root.
If you have multiple universities in your system, would be someone working across universities? May be universities are your system tenants?
What happens with a class if some department is dissolved? Will it immediately disappear? I doubt it.
The same as above with university to department relationship
It is not a problem with a Department to hold reference to its classes as a list of value objects that will contain the Class aggregate root id and the class name. The same is valid for departments dealing with their classes.
Vernon's Effective Aggregate Design might help too.
I'm not very experienced in DDD either but here some tips I use to use:
Is it possible to have a Class without a Department assigned? If that is the case then the Department is the aggregate root and Class is another aggregate with a reference to the root, the Department. You can even define a factory method "addClass()" within your Department with the info that a Class needs to be created, so nobody should be allowed to create a Class without a Department.
Why defining a Class a an Aggregate instead of a Value Object? Because Value Objects are distinguished by their properties' value rather than an ID. I would say that even having two Classes with the same name, same students, same info, etc, etc. the business would still want to differentiate each one. It is not the same with a 1 cent coin which with you only care about the value (given by the color, size, weight,...) but you can always replace it with another one with same attributes' value, that is 1 cent. Also assigning another Professor to the class, the class remains the same, it is not immutable as a Value Object should be.
I guess a Professor must be uniquely identified, and he can maybe be assigned to different Classes or even Departments. So to me it is another Aggregate root separated from the department.

Correct design of aggregate roots

Somewhere far, far away in a domain galaxy there is mention of
'Measurement values' and 'Places'
Each 'Measurement value' comes from/belongs to a specific 'Place'
Each 'Measurement value' is registered on a given date & time and of a given, specific type (eg. waterflow, wind, etc)
Each 'Place' has a name and a collection of 'Measurement Values' that gets registered
Given my current model where 'Places' are the aggregate root that holds 'Measurement values' I have a dilemma:
Users wishes to view one type of measurement values at a time and there are quite a lot of measurement values.
To load all measurement values when only some of them are needed seems unneccessary..
Eg. Im stuck on how to organize/model the need "Show me waterflows (measurement values) in River X (Place) between time A and B"
Is it allowed to instantiate River X aggregate root only partially loaded with the type of measurement values concerned in a given use case?
Are there other ways of modelling measurement values and their origin?
Please let med know your thoughts...
I think that your aggregate is consistent as it is. Your dilemma as nothing to do with domain model but rather than with a presentation model.
I will consider the possibility to deserialize each measurement in a NoSQL instance, in this way your presenteation layer could filter and make any query without affecting the consistency of domain layer.
Correct me if I'm wrong but it sounds very much like the data model and storage are impacting the design of your system? If this is so it may be the cause of your dilemma. A key part of the benefit modeling using aggregates is it is free of dependencies. Dependencies such as databases and data models. There is no direct 'view' of an aggregate, so it's not shaped by the view. This makes aggregates much easier to design. They are much more focused on solving the problem. And are therefore great candidates for doing complex stuff.
If it turns out you don't need aggregates to model your domain. You can then just focus on an efficient storage and retrieval mechanism.
In other words...
Don't tie yourself up in knots doing DDD if you don't need to.
If it helps I created an infographic on common DDD mistakes. You may find it helpful. You can find it here.
By the way, I think DDD is a great way to go, but only if your domain warrants it. Appologies if I have misunderstood you.
I fail to see the real problem. You said that each Measurement is tied to a specific Place, then you don't have to load all Measurements.
Using correct data layer configuration, you can load the required Measurement by selecting/loading/instantiating only it's parent (Place).

UML Relationships. Aggregation

I have a problem with my UML diagram and I'll be happy if you help me. I have relationships like
Object A (1)<>----(0..*) Object B
Object B (1)<>----(0..*) Object A
and I'd like to unite them. How can I do it? Thanks a lot.
Can you please define the term "unite them"? What exactly would you like to achive? An example could probably help.
Meanwhile, I can try to guess and give you two possible solutions. Maybe they help you to rephrase your question or even to find the solution:
In the Solution 1, I've just made a single relationship that describes both of yours. This can be used if there is only a single and clear criterion of the linkage between the objects. A typical n..m relationship. Objects A will each hold a collection of related objects B and vice versa.
For example a Person (A on the diagram) can join several Clubs (B) and a Club can have several members - there is only one logical relation behind this situation - membership.
Solution 2 is where there are actually 2 different ways to relate between those elements, each one 1..n. So, A holds a collection of Bs and B holds collection of As, but they are unrelated.
Extending the same example - a Person (A) can join only 1 Club (B) and a Club can have many members and hold their reference (col_a on the diagram). In the same time, a Club can have only 1 owner, and a Person can own several Clubs (col_b). Here we have two different logical relations - membership and ownership.
Of course, other multiplicities and navigabilities are possible, this is just an example to give you an idea.
Does one of these situations sound like yours?
UPDATE (after the 1st comment):
So, here is the updated solution 1:
This is an aggregation used here, and this is more a Group-member relationship. It suits perfectly the description of my first solution up there. Members (B) can be "shared" between the Groups (A) and Gruop does not have any special control over their lifetime.
The real Whole-part relationship would employ composition instead of aggregation (visually depicted with a black diamond, instead of a white one). Its semantics it that Whole object has a full control over the life of the contained objects (parts). In consequence, the Parts cannot be shared between several Wholes and must be destroyed if the Whole itself is destroyed.
Now you just need to find out which situation describes your problem the best, pick-up on of this solutions and eventually fine tune the multiplicities.
Here is a way you could represent this scenario in UML.
One server can contain 0 or many Functions (ie. aggregate relationship).
Each function must belong to one server. Or if it is a distributed function then it can belong to many servers.

Domain-Driven Design Confusion

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.

Resources