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.
A domain entity in DDD must implement the domain logic or behavior related to the entity data (the object accessed in memory). For example, as part of an order entity class you must have business logic and operations implemented as methods for tasks such as adding an order item, data validation, and total calculation.
Entities are Domain concepts that have a unique identity in the problem domain. Entities represent domain objects and are primarily defined by their identity, continuity, and persistence over time, and not only by the attributes that comprise them.
In DDD, validation rules can be thought as invariants. The main responsibility of an aggregate is to enforce invariants across state changes for all the entities within that aggregate. Domain entities should always be valid entities. There are a certain number of invariants for an object that should always be true.
The main difference between entities and value objects lies in the way we compare their instances to each other. The concept of identifier equality refers to entities, whereas the concept of structural equality - to value objects. In other words, entities possess inherent identity while value objects don't.
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:
StatusHistory
within the Document
entity. StatusHistory
is a list of StatusUpdate
value objects.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.
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 love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With