Assume that I have two aggregates e.g. Document and Binder. A Document could be standalone so we have modeled it as an Aggregate and in similar way we modeled Binder also an aggregate. Now the problem is that a Document could be inside a Binder as well, now how to model this scenario. When a Document is inside a Binder to work on the Document we may have to check some invariant related to Binder before allowing the user to work on the Document.
One way I could think of is having two model
Document (an Aggregate)
BoundedDocument (an Entity inside Binder Aggregate)
Is there a better way to model this scenario.
From what I understand you should have two separate Aggregates, Document and Binder, and use a Saga (Process manager) to eventually bring the entire system in a valid state. In other words, you should model the modification of a binded document as a business process.
This Saga would be started with all the informations regarding the modification of the document (i.e. all the modified properties in the document) then it would send a command to the Binder that would check its own invariant and if all is OK then it would send the update command to the Document aggregate. It should also react to all the events that could bring the system to an invalid state, i.e. events generated by the Binder Aggregate because there is the possibility that the documents in the binder enter in an invalid state because of the Binder Aggregate mutation.
A different architecture would be to send the update command directly to the Document Aggregate, without checking the invariant. Then, the Saga would react to the document update events by sending a command to the Binder Aggregate. If the Binder says that it is not OK then the Saga would send compensating commands to the binded Document. This design would be more permissive with invalid documents but it is simpler.
Both the designs would eventually bring the system in a valid state but the first would minimize the times that an invalid document exists at the cost of increased complexity because the Saga would need to be started and would store the document modification information.
The alternative is that you create a new nested-entity inside the Binder Aggregate, namely the BindedDocument but this entity doesn't seem to be conceptually different from the Document Aggregate. This is reflected by the code duplication that you would have.
Related
I've stumbled upon a problem: "I can't split my domain models into aggregate roots".
I'm a junior developer and novice at DDD. I really want to understand it, but sometimes it's really confusing.
From this point I want to describe my domain briefly.
My poject dedicates to provide users opportunity to create any kind of documents by themselve. Users can create a new type of document. Each new type consists of its attributes. Then a user of this application can create a concrete document based on its type. User can also send the document for approval. An approval flow is different for each types.
So, we have the following models:
DocumentType/ DocumentTemplate - acts as a template based on which
concrete documents are created. It has one to many relationship with
Document.
DocumentsAttribute - represents an attribute of document.
It has many to many relationship with DocumentType.
AttributeValue - when a concrete document is created, It looks at
its type and creates values for attributes, which has
its type. Many to many relationship with Document and Attribute.
Document - represents a concrete document that is created by users.
There are others models but I don't think that they make sense.
As you understand, here I apply Entity Attribute Value (EAV) pattern of data model. You can see a diagram that shows relationships in the database.
And my problems are:
I have a lot of entities in my model besides I have described.
I think that Document is definitely an aggregate root in my Domain. Because such things as ApprovalProcess which is aggregate cannot live out of it.
Here is the first question:
ApprovalProcess consists of its steps. Each step is an entity since it is mutable. A step has its state that can be changed. ApprvalProcess's state depends on its steps. Here we have a business invariant: "ApprovalProcess can be approved only if all its steps is approved".
I think that it is an aggregate root because it has the business invariant and contains entities that cannot live out of it. And we don't want to allow to have direct access to its steps in order to keep ApprovalProcess consistent.
Am I mistaken that ApprovalProcess is an aggregate root? May it is just an aggregate?
Can one aggregate root exist within another one as it's part? Does it mean that ApprovalProcess is just aggregate because Document is responsible for access to its parts? But when ApprovalProcess's step is approved, Document delegates an operation to ApprovalProcess.
For example:
Document doc = new Document(...);
doc.SendForAooroval(); //ApprovalProcess is created.
doc.ApproveStep(int stepId); // Inside the method Document delegates responsibility for approvement to ApprovalProcess.
Or I should leave Document and ApprovalProcess separately. Hence Document is going to refer to ApprovalProcess by Identity. And we have the following scenario:
Document doc = documentRepository.Get(docId);
doc.SendForAooroval();// A domain event "DocumentCreatedEvent" is raised.
DocumentCreatedEventHandler:
ApprovalProcess approvalProcess = new ApprovalProcess(event.DocId); // ApprovalProcessCreatedEvent is raised
approvalProcessRepository.Add(approvalProcess);
approvalProcessRepositroy.UnitOfWork.Save(); //commit
But if ApprovalProcess's state changes, Document's state also changes. ApprovalProcess is approved then Document is also approved. Another word ApprovalProcess is kind of part of Document's state. Only thanks to it we can know that Document is approved.
And the biggest problem that I'm experiencing:
DocumentType is also an aggregate root. It consists of its attributes and ApprovalScheme. I haven't mentioned ApprovalScheme yet on purpose to keep my explanation as simple as possible. ApporvalScheme consists also from some entities. It's just an approval flow for DocumentType. ApprovalProcess is created according to ApprovalScheme of DocumentType which has Document. ApprovalScheme cannot exist without DocumentType. One to one relationship.
Document refers by identity to its DocumentType. Is it correctly?
At the begining of this task I thought that DocumentType should be a part of Document.
DocumentType has many Documents but in my domain It doesn't make sense. It doesn't represent the state of DocumentType. DocumentType can be marked as deleted but can't be deleted.
Document and DocumentType are two different aggregate roots. Am I right?
Thank you so much If you read it. Thank you a lot for you attention and help!
Sorry for my terrible English.
Am I mistaken that ApprovalProcess is an aggregate root? May it is
just an aggregate? Can one aggregate root exist within another one as
it's part?
These questions doesnt make any sense to me. An aggregate is a group of entities and value objects, where one of the entities is the parent of the group. The aggregate root is the parent entity of an aggregate. A particular case is when the aggregate is just an entity. The entity alone is an aggregate and the entity is the aggregate root of course.
I think that I would try to model your problem from another point of view: as a state machine.
I see ApprovalProcess as a flow a document follows, not as an entity. I don't know the flow diagram of the process, but I guess that what you call "steps" would be the "states" a document can have during the process, and you have transitions between steps, so that first when you create a new document, it is at a starting step, and through the lifetime of the document, it pass from a step to another, till it reaches a final step (e.g. document approved).
So the document entity would have behaviour that changes its a state.
For example, in Java you can implement the state pattern (a state machine) with enums.
[ Follow up from this question & comments: Should entity have methods and if so how to prevent them from being called outside aggregate ]
As the title says: i am not clear about what is the actual/precise purpose of entity as a child in aggregate?
According to what i've read on many places, these are the properties of entity that is a child of aggregate:
It has identity local to aggregate
It cannot be accessed directly but through aggregate root only
It should have methods
It should not be exposed from aggregate
In my mind, that translates to several problems:
Entity should be private to aggregate
We need a read only copy Value-Object to expose information from an entity (at least for a repository to be able to read it in order to save to db, for example)
Methods that we have on entity are duplicated on Aggregate (or, vice versa, methods we have to have on Aggregate that handle entity are duplicated on entity)
So, why do we have an entity at all instead of Value Objects only? It seams much more convenient to have only value objects, all methods on aggregate and expose value objects (which we already do copying entity infos).
PS.
I would like to focus to child entity on aggregate, not collections of entities.
[UPDATE in response to Constantin Galbenu answer & comments]
So, effectively, you would have something like this?
public class Aggregate {
...
private _someNestedEntity;
public SomeNestedEntityImmutableState EntityState {
get {
return this._someNestedEntity.getState();
}
}
public ChangeSomethingOnNestedEntity(params) {
this._someNestedEntity.someCommandMethod(params);
}
}
You are thinking about data. Stop that. :) Entities and value objects are not data. They are objects that you can use to model your problem domain. Entities and Value Objects are just a classification of things that naturally arise if you just model a problem.
Entity should be private to aggregate
Yes. Furthermore all state in an object should be private and inaccessible from the outside.
We need a read only copy Value-Object to expose information from an entity (at least for a repository to be able to read it in order to save to db, for example)
No. We don't expose information that is already available. If the information is already available, that means somebody is already responsible for it. So contact that object to do things for you, you don't need the data! This is essentially what the Law of Demeter tells us.
"Repositories" as often implemented do need access to the data, you're right. They are a bad pattern. They are often coupled with ORM, which is even worse in this context, because you lose all control over your data.
Methods that we have on entity are duplicated on Aggregate (or, vice versa, methods we have to have on Aggregate that handle entity are duplicated on entity)
The trick is, you don't have to. Every object (class) you create is there for a reason. As described previously to create an additional abstraction, model a part of the domain. If you do that, an "aggregate" object, that exist on a higher level of abstraction will never want to offer the same methods as objects below. That would mean that there is no abstraction whatsoever.
This use-case only arises when creating data-oriented objects that do little else than holding data. Obviously you would wonder how you could do anything with these if you can't get the data out. It is however a good indicator that your design is not yet complete.
Entity should be private to aggregate
Yes. And I do not think it is a problem. Continue reading to understand why.
We need a read only copy Value-Object to expose information from an entity (at least for a repository to be able to read it in order to
save to db, for example)
No. Make your aggregates return the data that needs to be persisted and/or need to be raised in a event on every method of the aggregate.
Raw example. Real world would need more finegrained response and maybe performMove function need to use the output of game.performMove to build propper structures for persistence and eventPublisher:
public void performMove(String gameId, String playerId, Move move) {
Game game = this.gameRepository.load(gameId); //Game is the AR
List<event> events = game.performMove(playerId, move); //Do something
persistence.apply(events) //events contains ID's of entities so the persistence is able to apply the event and save changes usign the ID's and changed data wich comes in the event too.
this.eventPublisher.publish(events); //notify that something happens to the rest of the system
}
Do the same with inner entities. Let the entity return the data that changed because its method call, including its ID, capture this data in the AR and build propper output for persistence and eventPublisher. This way you do not need even to expose public readonly property with entity ID to the AR and the AR neither about its internal data to the application service. This is the way to get rid of Getter/Setters bag objects.
Methods that we have on entity are duplicated on Aggregate (or, vice versa, methods we have to have on Aggregate that handle entity
are duplicated on entity)
Sometimes the business rules, to check and apply, belongs exclusively to one entity and its internal state and AR just act as gateway. It is Ok but if you find this patter too much then it is a sign about wrong AR design. Maybe the inner entity should be the AR instead a inner entity, maybe you need to split the AR into serveral AR's (inand one the them is the old ner entity), etc... Do not be affraid about having classes that just have one or two methods.
In response of dee zg comments:
What does persistance.apply(events) precisely do? does it save whole
aggregate or entities only?
Neither. Aggregates and entities are domain concepts, not persistence concepts; you can have document store, column store, relational, etc that does not need to match 1 to 1 your domain concepts. You do not read Aggregates and entities from persitence; you build aggregates and entities in memory with data readed from persistence. The aggregate itself does not need to be persisted, this is just a possible implementation detail. Remember that the aggregate is just a construct to organize business rules, it's not a meant to be a representation of state.
Your events have context (user intents) and the data that have been changed (along with the ID's needed to identify things in persistence) so it is incredible easy to write an apply function in the persistence layer that knows, i.e. what sql instruction in case of relational DB, what to execute in order to apply the event and persist the changes.
Could you please provide example when&why its better (or even
inevitable?) to use child entity instead of separate AR referenced by
its Id as value object?
Why do you design and model a class with state and behaviour?
To abstract, encapsulate, reuse, etc. Basic SOLID design. If the entity has everything needed to ensure domain rules and invariants for a operation then the entity is the AR for that operation. If you need extra domain rules checkings that can not be done by the entity (i.e. the entity does not have enough inner state to accomplish the check or does not naturaly fit into the entity and what represents) then you have to redesign; some times could be to model an aggregate that does the extra domain rules checkings and delegate the other domain rules checking to the inner entity, some times could be change the entity to include the new things. It is too domain context dependant so I can not say that there is a fixed redesign strategy.
Keep in mind that you do not model aggregates and entities in your code. You model just classes with behaviour to check domain rules and the state needed to do that checkings and response whith the changes. These classes can act as aggregates or entities for different operations. These terms are used just to help to comunicate and understand the role of the class on each operation context. Of course, you can be in the situation that the operation does not fit into a entity and you could model an aggregate with a V.O. persistence ID and it is OK (sadly, in DDD, without knowing domain context almost everything is OK by default).
Do you wanna some more enlightment from someone that explains things much better than me? (not being native english speaker is a handicap for theese complex issues) Take a look here:
https://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-2
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-3
It has identity local to aggregate
In a logical sense, probably, but concretely implementing this with the persistence means we have is often unnecessarily complex.
We need a read only copy Value-Object to expose information from an
entity (at least for a repository to be able to read it in order to
save to db, for example)
Not necessarily, you could have read-only entities for instance.
The repository part of the problem was already addressed in another question. Reads aren't an issue, and there are multiple techniques to prevent write access from the outside world but still allow the persistence layer to populate an entity directly or indirectly.
So, why do we have an entity at all instead of Value Objects only?
You might be somewhat hastily putting concerns in the same basket which really are slightly different
Encapsulation of operations
Aggregate level invariant enforcement
Read access
Write access
Entity or VO data integrity
Just because Value Objects are best made immutable and don't enforce aggregate-level invariants (they do enforce their own data integrity though) doesn't mean Entities can't have a fine-tuned combination of some of the same characteristics.
These questions that you have do not exist in a CQRS architecture, where the Write model (the Aggregate) is different from a Read model. In a flat architecture, the Aggregate must expose read/query methods, otherwise it would be pointless.
Entity should be private to aggregate
Yes, in this way you are clearly expressing the fact that they are not for external use.
We need a read only copy Value-Object to expose information from an entity (at least for a repository to be able to read it in order to save to db, for example)
The Repositories are a special case and should not be see in the same way as Application/Presentation code. They could be part of the same package/module, in other words they should be able to access the nested entities.
The entities can be viewed/implemented as object with an immutable ID and a Value object representing its state, something like this (in pseudocode):
class SomeNestedEntity
{
private readonly ID;
private SomeNestedEntityImmutableState state;
public getState(){ return state; }
public someCommandMethod(){ state = state.mutateSomehow(); }
}
So you see? You could safely return the state of the nested entity, as it is immutable. There would be some problem with the Law of Demeter but this is a decision that you would have to make; if you break it by returning the state you make the code simpler to write for the first time but the coupling increases.
Methods that we have on entity are duplicated on Aggregate (or, vice versa, methods we have to have on Aggregate that handle entity are duplicated on entity)
Yes, this protect the Aggregate's encapsulation and also permits the Aggregate to protect it's invariants.
I won't write too much. Just an example. A car and a gear. The car is the aggregate root. The gear is a child entity
I am trying to get to grips with the ideas behind DDD and apply them to a pet project we have, and I am having some questions that I hope that someone here would be able to answer.
The project is a document management system. The particular problem we have regards two notions that our system handles: That of a Document and that of a DocumentStatus.
A Document has a number of properties (such as title, author, etc). Users can change any of the Document's properties through out its life time.
A Document may be, at any time, be at a particular state such as NEW, UNDER_REVISION, REVISED, APPROVED etc. For each state we need to know who made that change to that state.
We need to be able to query the system based on a document status. An example query would be "Get me all documents that are in the REVISED state".
"Get me all documents whose status has been changed by user X"
The only time that a Document and a DocumentStatus need to be changed in the same transaction is when the Document is created (create the document and at the same time assign it a status of NEW).
For all other times, the UI allows the update of either but not both (i.e. you may change a document's property such as the author, but not its state.) Or you can update its state (from NEW to UNDER_REVISION) but not its properties.
I think we are safe to consider that a Document is an Entity and an Aggregate Root.
We are buffled about what DocumentStatus is. One option is to make it a Value Object part of the Document's aggregate.
The other option is to make it an Entity and be the root of its own aggregate.
We would also liked to mention that we considered CQRS as described in various DDD documents, but we think it is too much of a hassle, especially given the fact that we need to perform queries on the DocumentStatus.
Any pointers or ideas would be welcomed.
Domain
You say you need to be able to see past status changes, so the status history becomes a domain concept. A simple solution would then be the following:
Define a StatusHistory within the Document entity.
The StatusHistory is a list of StatusUpdate value objects.
The first element in the StatusHistory always reflects the current state - make sure you add the initial state as StatusUpdate value object when creating Document entities.
Depending on how much additional logic you need for the status history, consider creating a dedicated value object (or even entity) for the history itself.
Persistence
You don't really say how your persistence layer looks like, but I think creating queries against the first element of the StatusHistory list should be possible with every persistence mechanism. With a map-reduce data store, for example, create a view that is indexed by Document.StatusHistory[0] and use that view to realize the queries you need.
If you were only to record the current status, then that could well be a value object.
Since you're composing more qualifying - if not identifying - data into it, for which you also intend to query, then that sounds to me as if no DocumentStatus is like another, so a value object doesn't make much sense, does it?
It is identified by
the document
the author
the time it occurred
Furthermore, it makes even more sense in the context of the previous DocumentStatus (if you consider more states than just NEW and UNDER_REVISION).
To me, this clearly rules out modeling DocumentStatus as a value object.
In terms of the state as a property of DocumentStatus, and following the notion of everything is an object (currently reading David West's Object Thinking), then that could of course be modeled as a value object.
Follows How to model an entity's current status in DDD.
I'm very new to CQRS/DDD, so there may be big holes in my understanding.
But let's suppose I have an aggregate object, Widget. Widget is composed with Note objects and Note objects can have a File object attached to them.
In CQRS I might have a command called AddNoteToWidget. I know from my reading that both command and event objects should be simple DTO's (I know they can also come in other forms, but the key thing being that they contain no behaviour).
I also understand that entities should never contain references to repositories since they should be persistence unaware.
Would my AddNoteToWidget contain a reference to the File object and just be serialized along with the command? If this is the case then my File object should be a value object. However, I have modelled it as an entity with it's own repository because I wanted to have central consistent file storage across the whole system.
From reading your question as well as the comments on it, it is clear that you currently treat File as both a sub-entity and an aggregate root. This is a problem, you should decide for one of the two:
Model File as an aggregate. Now only the ID of a File must be used outside of that aggregate, never the File itself. Also, File objects are retrieved through their own repository.
Model File as entity within the Widget aggregate. This means that you have the file readily available whenever you have a Widget. File objects don't have their own repository, they are loaded together with a Widget through the WidgetRepository.
Which of the two is better in your case I cannot tell from your question. As a guideline, aggregate boundaries are consistency boundaries, and aggregates are always persisted atomically. An app service should only modify a single aggregate.
I think the main problem that you currently have can be summarized as follows:
Repositories handle only whole Aggregates, never single Entities that are part of an Aggregate.
Of course, there may be simple aggregates that consist only of one entity, in that case, the entity and the aggregate are the same.
In a demo project I am setting up as a proof of concept I am finding myself with a lot of duplicated DTOs and fields. For instance considering 1 root object representing an item or inventory, I would have the following classes and properties
CreateItem [ Code, Description, Weight ]
Entity on aggregate root [ Code, Description, Weight ]
ItemCreated event [ Code, Description, Weight ]
Item read model [ Code, Description, Weight ]
Query request object [ Code, Description, Weight, Page, PageSize ]
Response DTO [ Code, Description, Weight ]
and so on
All these objects are a result of separating my app into the traditional Domain, Application, Presentation layers.
How are you managing all this duplication? Tools like AutoMapper and such help to convert between them, but if I wanted to add a new property to Item that would be used everywhere I would have to update all these models.
Because the domain model may not be exactly the same as the application read model, I understand the need for separate definitions, however this can very quickly become a maintenance nightmare.
Charles,
An approach that might help you get rid of some bits of duplication could be the following:
do not add public properties on the entity. As you are using event sourcing, the internal state of the entity will be restored by replaying the events associated with the entity in question. And nobody from outside the entity should know how the reconstructed state of the entity is represented - a series of private fields, an array of string objects, whatever. After all, you can choose to have no internal representation of its state, but implement all the behavior (all the methods) by simply replaying the events each and every time :) So, at one extreme, you may have 1 single field on the entity = a collection of events.
Item read model and Response DTO... Make them the same thing! As you are using cqrs, that is, you have already segregated the read model from the write model, there is no need to make a lasagna out of the read-side of the application. It is OK to have a minimum number of abstraction layers on the read-side. The read model is already behavior-less, it is data only. It's a DTO that gets constructed from events, gets persisted into a data storage with a (more or less) denormalized schema and, upon user request, is retrieved from the storage and presented on the UI or so. It's pure data that gets transferred from one place to another. Though, if, for some reason, you have to return to the end user (human or machine) some other data in addition to the data from the read model object, apply basic object composition. Compose two or more behavior-less objects into one such object. And send the latter on the wire.
speaking of composition, you may even define a (value) type such as ItemDescriptor [Code, Description, Weight] in a shared library and use it when defining the CreateItem command, the ItemCreated event, the read model, the query request object or so. If you are using a language that supports mixins, then mix that ItemDescriptor in :) Else, basic composition may be applied.
Furthermore, the "maintenance nightmare" can be ameliorated to some extent if packaging by feature would be used instead of packaging by layer.
Also, perhaps this post might help a bit.