Is there any drawbacks when a concept is modeled in a bounded context as a root entity and in another bounded context as a child entity (same identity in both BC's)?
From Eric Evans DDD:
ENTITIES other than the root have local identity, but it only needs to
be unique within the aggregate, since no outside object can ever see
it out of the context of the root ENTITY.
The concept would have global identity even when it plays the role of child entity.
I think Evan's point is to avoid modification of the child entity outside its aggregate, but in another BC no invariants would be violated.
What do you think?
Using a global id here is perfectly fine. I think Eric meant that the id should be unique at least within its parent aggregate.
I have a lot of similar cases in the systems we work on, and that's the exact way we've designed it.
The drawbacks, as I see it, are the leaking of concepts between Bounded Contexts when sharing Entities.
At first it may seem like a good idea in terms of preventing duplication however you will pay for it later. I can see a scenario where changes in one context make sense but not in the other.
This is fine; the 'child entity' is an immutable value object in the context of the 'root entity'. In other words, the root entity may reference child entities, but it cannot alter their attributes.
Related
I have some Entities and I am trying to follow Domain Driven Design practices to identify Aggregates. I somehow cant do this because I either break the rule of Entities not being allowed to reference non-root Entities of other Aggregates, or I cant form Aggregates at all.
I have the following Entities: Organisation, JobOffer, Candidate, and JobApplication.
An Organisation creates JobOffers but may only have a limited amount of active JobOffers.
A Candidate creates JobApplications but may only have a limited amount of active JobApplications.
A JobApplication references a JobOffer that it is meant for.
Based on that I have to know how many JobOffers an Organisation has before I can create a new one (enforcing limits), I assume Organisation should be an Root-Entity that owns JobOffers. The same applies to Candidates and JobApplications. Now I have two Aggregates: Organisation with JobOffers and Candidate with JobApplications. But... I need to reference JobOffer from JobApplication... and that breaks the rule that I cant reference non-Root-Entities.
I have looked for and found similar questions on this forum but I somehow still cant figure it out, so sorry in advance - I appreciate any help.
I general, you should avoid holding object references to other aggregates but rather reference other aggregates by id. In some cases it can be valid to reference some entity within in another aggregate, but again this should be done via id as well.
If you go this way you should reference a composite id. Aggregates are meant to depict logical boundaries and also transactional boundaries. Child entity ids which are modelled as part of the aggregate only need to be unique inside the boundaries of that aggregate. This makes it a lot easier to focus on stuff just inside those boundaries when performing actions in your system. Even if you are using UUIDs (or GUIDs), if you really need to reference a child entity of another aggregate - let's say you have good reasons for that - you should model the id graph via the aggregate root which means always knowing the id of the other aggregate in combination with the id of the entity you are interested in. That means referencing a composite id.
But: whenever I think I need to reference a child entity of another aggregate root at first I investigate this more deeply. This would mean that this child entity might be important as a stand-alone entity as well.
Did I miss to discover another aggregate root?
In your case, looking at your domain model diagram, I suspect JobOffer should be an aggregate on its own. Of course I don't know your domain but I can at least guess that there might be some transactions performed in your system allowing to mutate job offers on its own without requiring to consider organization specific business invariants. If this is the case, you should rethink the domain model and consider making JobOffer an aggregate root on its own. In this case your initial problem get's resolved automatically. Also note that modelling job offers as aggregates can make actions performed on organizations simpler as well as you do not need to load all the job offers for that organization when loading the organization aggregate. This might of course not be relevant in your case and really depends on the maximum amount of job offers for an organization.
So I think, depending on your business requirements and domain logic invariants I would recommd one of the folllwing two options:
Reference the foreign child entity only through a composite id including the id of other the aggregate + the child entity id (e.g. by creating some value object that represents this reference as a strong type)
Make JobOffer an aggregate on its own if the mentioned considerations hold true in your case
If we are working on a sub-domain where we're only dealing with a read-only scenario, meaning that our entities and value objects will not be changed, does it make sense to create aggregates composed by roots and its children or should each entity of this context map to a single aggregate?
Imagine that we've entity A and entity B.
In a context where modifications are made, we create an aggregate composed by entity A and entity B, where A is the aggregate root (let's say that B can't live without A and there are some invariants involved).
If we move the same entities to a different context where no modifications are made, does it make sense to keep this aggregate or should we create an aggregate for entity A and a different one for entity B?
In 2019, there's fairly large support for the idea that in a read only scenario, you don't bother with the domain model at all.
Just load the data directly into whatever read only data structure makes sense to support the use case.
See also: cqrs.
The first thing is if B cant live without A and there are some invariants involved, to me A is an Aggregate root, with B being an entity that belongs to it.
Aggregate roots represent a real world concept and dont just exist for the convenience of modification. In many of our applications, we don't modify state of our aggregate roots once created - i.e. we in effect have immutable aggregate roots. These would have some logic for design by contract checks/invariant checks etc but they are in effect anaemic as there is no "Update" methods due to its immutability. Since the "blue book" was written by Eric Evans, alot of things have changed, e.g. the concept of NoSql database have become very popular, functional programming concepts have become very influential rising to more advanced DDD style architectures being recommended such as CQRS. So for example, rather than doing updates to a database I can append (i.e. insert) instead. This leads to aggregates no longer having to be "updated". This leads to leaner anaemic types but this is what we want in this context. The issue before with anaemic types was that "update logic" for a given type was put elsewhere in the codebase instead of being put into the type itself. However if you do not require "update logic" in the first place then you dont have that problem!
If for example there is an Order with many OrderItems, we would create an Order aggregate root and an OrderItem entity. Its a very important concept to distill your domain to properly identify what are aggregates, entities and value types.
Then creation of domain services, repositories etc just flows naturally. For example, aggregate roots and repositories are 1 to 1 i.e. in the example above we would have an Order repository and not have an OrderItem repository. That way your main domain concepts are spread throughout your code in a predictable and easy to understand way.
Finally, in your specific question I would not treat them as the same entities. In one context, you seem to need modification logic - in the other they you dont - they are separate domain concepts to me.
In context where modifications are made: A=agg root, B=entity.
In context without modifications: A=agg root (immutable), B=entity(immutable)
I mean, is there any PersonAggregate class? I understand it doesn't exist. I only have an entity acting as aggregate root. Is it correct?
I only have an entity acting as aggregate root. Is it correct?
That's correct.
The aggregate is implicit - it's the boundary that separates two disjoint sets of state that can be modified independently of each other. Equivalently, the aggregate is a graph of business state within a model that can be modified without consulting state outside the graph, and vice versa.
The aggregate root is explicit. That's the single entity in the graph that is exposed - which is to say that it serves as the entry point through which all modifications to the graph must pass.
Hypothetically, you could implement an aggregate that has two different exposed entities that can each execute commands to modify the state; Evans introduced the notion of a single aggregate root because multiple entry points is difficult to get correct.
I have seen both solutions used in projects, but most often people do not use this suffix.
One interesting solution for this is make aggregate classes public and non-aggregate classes package(default). You'd see directly from your IDE which classes have which visibility and you can determine easily where is an aggregate. Additionally non-public class cannot be used outside package which is an original intent.
My understanding is an Aggregate Root is an Entity but an Entity might not be an Aggregate Root. Therefore, I view 'Aggregate Root' as more of a stereotype.
Not in domain-driven design. That would be exposing technological jargon, essentially implementation detail, to the domain experts
After reading Evans and Vernon I still have one fundamental Question.
I'm aware that of course one entity (instance) can only be in one aggregate.
But can an entity class be used in multiple aggregates (classes)?
For clarification, I ask on the class level.
Other formulation: Can two different aggregate root classes (!) aggregate the same entity class? Of course any of the entity instances has to belong to only one instance of one of the two aggregate root classes.
For Value Object classes this seems to be possible. At least I have the impression that a value object class for example for "money" can be used in different aggregate types.
As you rightly pointed out, Entity instances shouldn't be shared between aggregates, as one aggregate wouldn't be aware of changes to the entity made through another aggregate and couldn't enforce its invariants.
Entity classes could theoretically be shared between 2 aggregates, but, by the same reasoning, only if the set of entity instances in an Aggregate is disjoint from the other. This raises questions :
Why would you want that in the first place ? If there are two big categories of instances of the same class, isn't this a sign that there are two semantically different concepts, which should each have their own class, or at least subclass ?
How do you prevent an entity instance belonging to one aggregate from being added to the other, at runtime (bug), or at programming time (uneducated developer decision) ?
Value Objects escape these issues because they are usually immutable or treated as such -- you don't modify a VO, you modify its parent Entity so that it points to a whole new VO instance. Also, as Value Objects don't have an identity, it doesn't make much sense to say that the "same" VO is in two aggregates at the same time. You can thus safely reuse a VO type in different aggregate classes.
I think Udi's blog post here is very relevant - he suggests that entities can not only be part of multiple aggregates but also be an aggregate root themselves. It is a bit of a funny one to get your head around! http://udidahan.com/2009/06/29/dont-create-aggregate-roots/
I've read countless posts on differences between Entities and Value objects and while I do think that at least conceptually I understand how the two differ, it appears that in some of these posts authors consider a particular domain concept to be a VO simply because it is immutable ( thus its state will never change, at least within that particular domain model ).
Do you agree that if the state of an object will never change within particular domain model, then this object should never be an entity? Why?
thank you
Do you agree that if the state of an object will never change within
particular domain model, then this object should never be an entity?
Why?
I'd say 90+% of entities will change at some point in their lifetime. But some entities might be unchangeable because of their nature in the domain - a PrepaidPhoneCard, a TransferOrder in a banking system for instance.
Some also like to make their Entities immutable by default because it helps shaping a design that preserves invariants and makes domain operations explicit : http://www.jefclaes.be/2013/04/designing-entities-immutability-first.html
The object could be an entity if you need to identify it.
According to the DDD book, if an object has identity and lifecycle but will not change over time, you could also consider the object as an event.
In two words: yes, they can.
Eric Evans in his book tells about a "thread of continuity" inherent to entities. In layman terms, an entity can be POSTed by a front-end as JSON, get converted into a DTO by a framework, then into a domain object, then into a DTO again and then finally get stored in a database table. During all these transformations the entity will be easily distinguishable because it possesses one or more unique business ids.
With this in mind, aren't some forms of immutability a form of another thread of continuity? Imagine copy-on-write: all of the immutable object's copies are formally different objects representing it at different points of its lifetime. Yet, there is a unique id allowing us to say it's the same entity.
Now, let's talk about the "extreme" form of immutability: read-only objects. Can an entity be a read-only object? Sure, a good example is a credit card statement.
Summing up:
One entity can exist in many forms. In fact, you will almost always have multiple representations of your entity in a program without being aware about it.
A true requirement an entity is an existence of a unique business identity (not a surrogate id that is used for technical purposes) that makes it distinguishable from other entities.
Entities can be immutable, whether we talk about COW or read-only objects.