Based on the following definitions from Domain-Driven Design: Tackling Complexity in the Heart of Software,
An aggregate is:
A cluster of associated objects that are treated as a unit for the purpose of data changes. External references are restricted to one member of the AGGREGATE, designated as the root. A set of consistency rules applies within the AGGREGATE'S boundaries.
I don't think the Aggregate root should hold a reference to the repository. Since the Aggregate root is the only one that should be holding references to its entities and aggregates, they should be private.
How can my repository persist and restore this private data ?
Edit:
Let's take the classic Order, OrderLines example.
An order is the Aggregate root.
It's lines are Entities.
Since the Aggregate root(order) is the only object allowed to hold references to its entities (order lines), I do not understand how would I persist order lines from the repository.
As far as I understand the aggregate root, it must be the place to access all the entities inside it's scope. That means, as long as traditional ORM is used, that you can access the OrderLines throug the Order.
Further it is not forbidden for anyone to grab a reference to the entitiy inside the root, but these references must be volatile (i.e. short lived) and you must obtain the rerefence via the aggregate root.
In terms of DDD you will use a repository to hide data access, the factory might in turn use a factory to assemble the object. The facotry knows well about the internal structure of the object and must be able to build up a new object or restore one from the data the repository hands over.
Perhaps you might also look into CQRS + Event Sourcing which provides a different approach to persisting entities.
Well, most folks consider the repository to be a logical feature of hte aggregate root (since there's only one per aggregate, in traditional DDD), so it does & should have access to the orderlines.
If you really want them to be private, though, you would need to resort to reflection, or else have the aggregate root entity return them in some persistable fashion (perhaps w/ an internal call of some kind).
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
I saw many different approaches and I am fairly new to domain-driven design approach. What I am struggling with is to understand one complex (at least for me) thing. I know the whole DDD is complex to understand on first but I am trying to find any resources I can on it.
Example: I have an order and order can have operations. Operations can not be accessed without order and they make no sense without an order. So order entity will be my aggregate root. Operations will be entity too because each operation will have an id (am I right on this one?). Each operation can have subitems (array of strings for example and these can be added or removed from any operation).
Now what I am struggling to understand and what I found everywhere is that every modification should be called and set only through aggregate root... But is it okay to have private methods like setters and getters on the Operation entity itself but these would be called only through the aggregate root (order entity)?
Sorry if I missed something basic, as the whole DDD concept for me is new and I am trying to explore it.
Thanks.
A couple of DDD concepts to arrive at the answer:
Aggregates are Transaction Boundaries.
Aggregates act as gatekeepers for all changes to domain elements enclosed within itself.
Data changes to an Aggregate and its enclosed domain elements are committed atomically. Either everything within the Aggregate stays in sync, or the whole state change operation fails.
The rule also means that one should not access Domain Elements within the Aggregate directly. It would be best if you did not manipulate the domain objects outside the context of the Aggregate.
If Operation is an entity under Order aggregate, then Order is responsible for ensuring operations satisfy the business invariants (a.k.a validations).
Aggregates are loaded in entirety.
Since an Aggregate represents the transaction and consistency boundary of a domain concept, its data is loaded in entirety to guarantee that all Business Invariants are satisfied. Data here means data of all underlying entities and value objects.
If you cannot load the entire data, you cannot guarantee that the change satisfies all business invariants. It may also mean that a data-intensive entity within the Aggregate may need to become an Aggregate itself.
You are protecting the data sanctity and operational consistency of the system if you adhere to these rules. Within the Aggregate itself, how you organize state changes is wholly left to you.
IMHO, I would go with your approach of enclosing all Operation related behaviors, data attributes, and invariants within the Operation entity. Order is responsible for protecting the data within its boundary, but it need not own the methods/logic of doing everything.
You can create state change methods within the Operation entity too, just like you would have done in the Order aggregate, but invoke them from the order object.
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)
In the Guide/eBook: .NET Microservices: Architecture for Containerized .NET Applications (related to the eShopOnContainers) in the chapter "Designing the infrastructure persistence layer" (page 213) is explained in general how an aggregate root can perform CUD operations against a persistent data source.
Two important starting points are mentioned :
An aggregate is ignorant of methods of persistency and infrastructure following the Persistence Ignorance and the Infrastructure Ignorance principles (page 218). An aggregate is determined by the business and not by the infrastructure.
One should only define one repository per aggregate root to maintain transactional consistency between the objects within the aggregate (page 213)
Unfortunately, in all further examples that are mentioned the aggregate root and all underlying objects that fall under it are within one and the same persistent data source.
The pattern then is as follows:
A repository is created containing that aggregate
In this repository a Unit of Work is injected during creation. This Unit of Work contains methods such as SaveChangesAsync, SaveEntitiesAsync, Update
and so on.
In a command, the Unit of Work manages the transactions to
this one data source such as a database or similar.
I want to expand this pattern that the aggregate can write its data over 2 or more physical data sources depending on the underlying object type.
Starting from starting point 1, it is perfectly justified to have a root aggregate and its underlying object to be updated to different data sources depending on the type of underlying object. Examples mentioned are : a Database and an XML file, a database and a NOSQL 'database',a database and a service, a database and an IoT device. Because an aggregate must be ignorant to methods of persistence and infrastructure, to my opinion there is no need to argue about the design of the aggregate. I think nowhere in the book it is written that a aggregate root should persist within one data source.
At the same time, starting point 2 also seems perfectly justified. Because the complete set of objects within the aggregate root is edited, and the successful persistence of the entire package is coordinated from one repository and (preferably) from one Unit of Work.
The question is:
How deals Domain Driven Design if within the aggregate - depending on the type of the underlying object - it is hydrated over different data sources?
Should I use one custom Unit of Work and make the decision where to write to within this UoW ?
I'm aware of the next question , but having studied the code I think it only deals with inheritance of repositories that deal with different data sources, but still serving one data source at the time and that is not what I'm after.
I want to expand this pattern that the aggregate can write its data over 2 or more physical data sources depending on the underlying object type.
Why do you want to do that on purpose?
In most cases, the persistence implementation is chosen to serve the domain, rather than the other way around. So the happy path typically involves choosing a persistence solution that can record the state of the entire aggregate, and storing the entire thing within a single transaction.
So if you find yourself trying to store an aggregate in two different places, you should take a hard careful look at why.
One common answer is that you want to be able to query the aggregate state efficiently. cqrs is a common solution here - rather than persisting the aggregate in two different data stores, you persist it to one and replicate it to another. The queries can run very efficiently against the replica (although there is of course some additional latency between a change to the aggregate and the reflection of that change in the query results).
Another common answer is that you really have two aggregates that reference each other. Nothing wrong with storing two aggregates in different places. You may be better served by making the distinction between the two explicit in your code.
Dan Pritchett
Jimmy Bogard
How deals Domain Driven Design if within the aggregate - depending on the type of the underlying object - it is hydrated over different data sources?
Badly, just like everybody else.
1)
a) Entities within an Aggregate should only be accessed via Aggregate root. While it is possible for the root to pass transient references to internal entities to external objects ( for the duration of a single operation ), I assume in most cases if external object needs to performs some operation on internal entity, it should call method(s) defined on the Aggregate root ( contrived example - Order.SetOrderLineTitle(...) )?
2) Only AGGREGATE roots can be obtained directly. All other objects must be found by traversal of associations.
a) When we say that external objects should access non-root entities by traversal of associations, do we mean they should call methods on Aggregate root ( e.g. Order.SetOrderLineTitle(...)), which in turn would perform operations on internal objects or do we mean that Aggregate root should pass a reference to internal entity to an external object or both?
Thank you
1) Yes, this is the best way for the aggregate to maintain its integrity. Some say that this can result in aggregates with very large number of methods, however in that case there may be multiple aggregates at play.
2) Ideally, the aggregate would perform the required operation without passing references. There may be a case where passing a reference makes sense, but this should be implemented with care as it makes reasoning about integrity more difficult.
I assume in most cases if external object needs to performs some
operation on internal entity, it should call method(s) defined on the
Aggregate root
Just to add a slightly different take on this, the reverse approach might also be used. Adding methods to the Aggregate Root in most cases forces you to divide your domain in very small Aggregates lest the roots become bloated, violating SRP. This slicing might come at the cost of sacrificing the natural business cohesion of your Aggregates.
Instead, you could decide that in most cases you will let external objects get transient references to internal entities and manipulate them as they wish. In rarer cases, especially ones that imply enforcing invariants that span across multiple entities, it would be a better idea to implement these operations directly on the Root.
That approach is discussed here : https://groups.google.com/forum/#!topic/dddcqrs/mtGanS39XYo
the way I see it is although an aggregate root is responsible for the
life cycle of entities within, that doesn't mean that it should be the
exclusive interface ( other than returning a specific entity) to all
methods called on any item within the aggregate.
Overall, the final decision will depend on whether you want to design your aggregates primarily with domain/functional cohesiveness in mind or you first want to think of them as transactional safeguards.