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.
Related
I am attempting to build an application in a DDD way. Imagine the Aggregate root is a 'Page' which has other aggregates such as Author, Commenter, Comments, Status etc...
A page can also have various settings such as:
Private page
Allow comments
Allow anonymous comments
Lock after x Date
Slug
I am trying to consider the best way to model these 'settings'. Currently I am looking to have a Settings collection that has each individual setting as a value object. As you can see some of these are essentially boolean values and others might contain specific values such as a date. Given there might be dozens of settings, some with defaults, do I model the 'settings' collection with each specific setting, or just as a collection with the applicable settings?
Is there a 'better' or standard DDD way to approach this problem? I was considering using the specification pattern here but have concluded it doesn't really apply
Sorry a cheeky second question....
A page can have one of many statuses (e.g. draft, published, scheduled, archived) but only one status at a given time. Similar question in terms of the best way to model this. As a status represents something that has an identity I have implemented the status as an entity for the moment. I was wondering would a better approach be to model this as a workflow or a status history even?
First let me say that the aggregate you are planning to create could be too big, double check that since creating an aggregate implies some trade offs like that you can only access the child entities from the aggregate root, and that all changes in the aggregate are atomic.
To avoid having a too big aggregate you could have AuthorId as a VO inside Page instead of the full Author entity.
About the settings thing, as far I know DDD doesn’t have some directives to design this. But I’d try to have Settings collection of some interface, the I’d have an implementation for each setting type: Boolean, date...
Most DDD Books (e.g. Patterns and Principles of DDD) recommend strongly to load the whole aggregate when getting the data from the database. The reason for that is that aggregates are consistent boundaries.
But there common cases where this would result in overwhelming performance problems.
Here is a real example I am facing:
I have an aggregate root which is an workobject entity with its properties. There are other entities in this aggregate:
List of attached documents of the workobject. Each document is an entity.(The class document contains the metadata of the real document).
List of comments. Each comment is an entity`.
List of activities. Each activity is an entity which represents an activity that is done on this workobject.
List of ArchivedFiles. Each ArchivedFile is an entity which represents an document which is already archived in an external system. (The class ArchivedFile contains the metadata of the real archived file)
These entities belong to the aggregate, because changes on the workobject would mostly affect the state of these entities, too.
Now I have the following problem:
In the UI, there is a place where a user gets all the workobjects that are in his/her inbox. This could be more than 100 workobjects or even more. But it does not make sense to load the whole aggregate (comments,activies,documents) for each workobject at that point. This would slow down the application resulting in a terrible user experience.
The idea is to show just the properties of the workobject to the user in a datagrid. If a user makes a specific event like clicking on a specific workobject, a specific form is loaded where detailed information of the specific workobject is loaded. That would be an appropriate point to load the whole aggregate (i.e., comments,activies,documents). But most of the DDD-Books (e.g. Patterns and Principles of DDD) warn to not use lazy loading inside an aggregate, but to load the whole aggregate when loading the aggregate root.
How should we solve this problem by still respecting the DDD-rules?
How should we solve this problem by still respecting the DDD-rules?
Usual answer: don't use the aggregate pattern when the thing you want is a report.
Lazy loading is a "code smell" when performing domain dynamics; if you are leaving a lot of data behind when making a change, that strongly suggests that the information left behind belongs in a different aggregate.
But for an operation that is effectively read only, like a report? We're not going to be changing anything, so we don't need the constraint that ensure that our changes our correct, so we don't need the information we use to describe the constraint.
For more ideas about separating reads from writes, review the patterns described under the umbrella cqrs ("command query responsibility segregation").
I have recently dived into DDD and this question started bothering me. For example, take a look at the scenario mentioned in the following article:
Let's say that a user made a mistake while adding an EstimationLogEntry to the Task aggregate, and now wants to correct that mistake. What would be the correct way of doing this? Value objects by nature don't have identifiers, they are identified by their structure. If this was a Web application, we would have to send the whole EstimationLogEntry value object as a request parameter, along with the new values, just so we could replace the old value object with the new one. Should EstimationLogEntry be an entity?
It really depends. If it's a sequence of estimations, which you append every time, you can quite possibly envision an operation which updates the value only of the VO. This would use VO semantics (the VO is called to clone itself in-mem with the updated value on the specific property), and the command can just be the estimation (along with a Task id).
If you have an array of VO's which all semantically apply to Task (instead of just the "latest" or something)... it's a different matter. In that case, you'd probably have to send all of them in the request, and you'd have to include all properties too, but I'd say that the need to change just one, probably implies a need to reference them, which in turn implies a need to have an Entity instead of a VO.
DDD emphasizes the Ubiquitous language and many modelling questions like this ones will derive their answer straight from that language.
First things first, if there's an aggregate that contains a value object, there's a good chance that the value object isn't directly created by the user. That is, the factory that creates the value object lives on the aggregates API. The value object(s) might even be derived directly from the aggregates state instead of from any direct method call. In this case, do you want to just discard the aggregate and create a new one? That might make sense depending on your UL.
In some cases, like if you have immutable value objects (based on your UL), you could simply add a new entry into the log entry that "reverses" the old entry. An example of this would be bank accounts and transactions. If bank accounts are aggregate roots and transactions are the value objects. If a transaction is erroneously entered, you can simply write a reversing transaction to void it.
It is definitely possible that you want to update the value object but that must make sense in your UL and it's implementation must also be framed around your UL. For example, if you have a scheduling application and an aggregate root is a person's schedule while the value objects are meetings. If a user erroneously enters a meeting, what your aggregate root should do would be to invalidate the old meeting (flip a flag, mark its state cancelled e.t.c) and create a new one. These actions fit the UL for your scheduling app. The same thing as what you are calling "updating the entry" above.
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.
I'm trying to improve my design using some DDD concepts. Currently I have 4 simple EF entites as shown in the following image:
There are multiple TaskTemplates each of them storing multiple TasksItemTemplates. The TaskItemTemplates contains various information (description, images, default processing times).
Users can create new concrete Tasks based on a TaskTemplate. In the current implementation, this will also create a TaskItem for every TaskItemTemplate, but in the future it might be possible to select one some relevant TasksItemTemplates.
I wonder how to model this requirement in DDD. The reference from TaskItem to TaskTemplateItem is not allowed, because TaskTemplateItem is not an aggregate root. But without this reference it is not possible to get the properties of the TaskTemplateItem.
Of course I could just drop the reference and copy all properties from TaskTemplateItem to TaskItem, but actually I like the possibility to update TaskItems by updating the TaskTemplateItems.
Update: Expected behaviour on Task(Item)Template updates
It should be possible to edit TaskTemplate and TaskItemTemplate and e.g. fix Typos in Name or Description. I expect these changes to be reflected in the Task/TaskItem.
On the other hand, if the DefaultProcessingTime is modified, this should not change the persisted DueDate of a TaskItem.
In my current Implemenation it is not possible to add/remove TaskItemTemplates to a persisted TaskTemplate, but this would be a nice improvement. How would I implement something likes this? Add another entity TaskTemplateVersion between TaskTemplate and TaskItemTemplate?
Update2: TaskItemTemplateId as ValueObject
After reading Vaughn's slides again, I think with a simple modification, my model is correct according to DDD:
Unfortunately I do not really understand, why this Design is better (is it better?). Okay, there won't be unnecessary db queries for TaskItemTemplates. But on the other side I almost ever need a TaskItemTemplate when working with a TaskItem and therefore everything gets more complicated. I cannot any longer do something like
public string Description
{
get { return this.taskItemTemplate.Description; }
}
Based on the properties that you list beneath TaskItem and TaskItemTemplate I'd say that they should be value objects instead of entities. So if there isn't a reason (based on the information in your question there isn't) to make them entities, change them to immutable value objects.
With that solution, you just create a TaskItem from a TaskItemTemplate by copying its data.
Regarding the update scenario that you describe, it see the following solution:
TaskItems are created from a specific version of the TaskItemTemplate. Record that version with a TaskItem.
The TaskTemplate is responsible for updating its items and keep track of their version.
If a template changes, notify all Tasks that are derived from the template if immediate action is required. If you just want to be able to "pull in" the template changes at a later time (instead of acting when the template changes), you just compare the versions.
To make informed decisions, it is very important that you fully understand the pros and cons of immutability. Only then you will see a benefit in modelling things as value objects. One source on the topic that I find very valuable is Eric Lippert's series on immutability.
Also, the book Implementing DDD by Vaughn Vernon explains the concepts of value objects and entities very well.