Implementing DDD, page 233:
There are times when an object in a downstream Context must be
eventually consistent with the partial state of one or more Aggregates
in a upstream Context. In that case we'd design an Aggregate in the
downstream consuming Context, because Entities are used to maintain a
thread of continuity of change
According to the author, if eventual consistency is needed, then downstream object should always be an Aggregate Root. Is there a particular reason why it should never be designed as an internal entity?
UPDATE:
One could argue they always need to be the root to prevent having several downstream objects ( ie objects reflecting the state of upstream objects ) with the same id, but if synchronization is one way only ( from upstream to downstream context ), are there really no situations where it's ok for two downstream objects to have identical ids?
thanks
I'll take a crack at this.
He is talking about a downstream bounded context, not a downstream object. That's the important phrase here.
In a different bounded context, you would need to communicate through an aggregate root in that context because a well established rule in DDD is that all communication goes through an aggregate root. You wouldn't call methods on an entity or value object inside that AR directly.
Also - the aggregate root is the unit of consistency in DDD. So as he says - if you need eventual consistency in an object that exists in a downstream bounded context, design an aggregate root (the consistency boundary) in that downstream bounded context.
Related
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.
I have a first aggregate root having a natural Id encapsulating invariants related to a same topic.
Suddently, a new business requirement arises with a new set of invariants on a completely different topic than the first aggregate. It is a great occasion to create a new aggregate root in same bounded context.
However, both aggregate roots have the same natural Id. And both aggregate roots have some identical properties (but not all). Those identical properties can be modified, but I don't want to kick-in a flow of domain events to propagate data changes in those two aggregates (because we cannot modify two aggregates in the same transaction).
An option would be to regroup those aggregate roots. They are in the same bounded context and they have the same natural Id (they "represent" the same thing) so it feels natural. But with that option, the aggregate would become HUGE. Size is not a real problem, but merging really different kinds of invariants bother me.
What about keeping those aggregates separated in the domain, but rely on the same database table to share the data?
Any opinion on that?
On another alternative?
One of the biggest advantage of using aggregates is to enforce invariants and make sure that the aggregate is always in a valid state. This can be guaranteed because the aggregate root ensure the integrity of the aggregate as a whole. If you allow altering aggregate's data with any mechanism other then going through the aggregate root you will no longer be sure that it is in a valid state. So if you share tables between 2 aggregates you will loose one of the main advantages that aggregates offers.
And by duplicating the aggregate, the ubiquitous language will be no longer reflected in the code since there is only one aggregate in the real business.
Regarding your example:
Suddently, a new business requirement arises with a new set of invariants on a completely different topic than the first aggregate.
This sounds like it is another bounded context. So I suggest moving the new aggregate to another bounded context but if you are sure it belongs to the same bounded context then don't create a new aggregate. Just add the new business rules to the existing one. Duplicating aggregate is definitely a bad idea.
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.
Suppose you've got two aggregates in your bounded context which have some constraints amongst each other. Using DDD these inter aggregate constraints can't be enforced in the same transaction i.e. the aggregate boundaries are transactional boundaries.
Would you consider using what in the Microsoft CQRS journey is called a "process manager" to coordinate two aggregates in the same bounded context or is a process manager only used to coordinate between two bounded contexts? What would the equivalent of a process manager that coordinates two or more aggregate roots within the same bounded context be?
An aggregate root defines a bounded context by default, albeit a lower level one (btw the lowest level bounded context you can find is an object, any object). The process manager is the name they used instead of a saga, proabably you can come up with other names too, it doesn't matter, they all have the same purpose.
And yes, I would consider using a saga to achieve eventual consistency. In fact, I think this is the best way and this is exactly what I'm doing in my own apps. Anyway, I'm using a message driven architecture (yes, in a local, non-distributed application) and I have automatically saga support via the service bus (my own, not released yet).
What is important when dealing with eventual consistency is to ensure idempotency everywhere. That is the aggregate roots should reject a duplicate operation and of course the event handler should be able to cope with the fact that the same event can be published more than once. However, be aware that you can't guarantee 100% idempotency but you can get very close to.
How should separate aggregate roots (AR) communicate with one another in an environment built on DDD principles using an event-sourced aggregate back-end?
For instance, I have a Facility aggregate root (AR) which has a factory method responsible for creating a Booking AR. The Booking is a time-sensitive combination of a Person AR and a Facility AR. A Person can only be booked in a single Facility.
In DDD, I would have held references to the Booking in Person, and Person in Facility. However, when generating events for use in event-sourcing I think that trying to handle the event deserialization from the back-end would become prohibitive. Therefore, I've taken to only holding references to the value object-based unique id's. This brings up a new problem, however, when a method on an AR needs to call another method on another AR -- how do you handle that situation? Hit the event source repository from the domain AR?
What is the general use case in this scenario? Am I approaching this all wrong?
Aggregate Root boundaries define a consistency boundary.
Inside the aggregate, consistency is guaranteed.
Outside... it's not.
So you should not have operations that spans several aggregates and have to be consistent.
If you need a transaction that spans two aggregates, you should review your aggregate boundaries.
For things that happen outside the aggregate you should have an event handler that will send a command to other aggregates.
If the logic of actions between aggregates is more complicated, you can define a process, a state machine that will listen to events and send commands to aggregates.
Processes can be used to define long running transactions (with compensation instead of rollback), or take business decisions based on what's happening in the system at a large scale (even between bounded contexts).
When using Event Sourcing and CQRS the most elegant (at least in my opinion) way of inter-AR communication is messaging. You can look at Ncqrs project (it will be easier if you are a .NET guy), particularly 'Messaging' branch. The idea is, ARs implement IMessageHandler interface for every message type they handle and AR base class exposes method Send for sending there messages. By means of this API clients can invoke model behavior and model itself can communicate (between ARs).