There seems to be some confusion around these and similar concepts, so I thought it might be an idea to provide some clarification. Now these things aren’t specific to DDD, but they certainly have a lot of relevance there, and often provoke furious debate.
In this series I first mentioned these things back when I introduced Entities and Value Objects, I said that you should try and ensure Entities are valid at all times, and that Value Objects should be immutable. The discussion around Aggregates and Aggregate Roots has also proved to be of some confusion, the definition from Eric Evans of an Aggregate says “A set of consistency rules applies within the Aggregate's boundaries”.
Download the ebook of the series so far (also published on dddstepbystep.com)
The term “valid” has many meanings in many contexts. When it was mentioned with regards to an Entity, I suggested that you should attempt to ensure that your Entities are always in a valid state, and cannot become invalid. I followed up that this could be achieved by removing property accessors, and only using either constructors or strongly named methods.
Let us go back to our Customer example, and presume that for a Customer to be valid within our Domain, it must have a CustomerNumber, a FirstName, and a LastName. It may also have half a dozen other properties.
So we can ensure this Entity never becomes invalid by removing the property accessors for the CustomerNumber, FirstName, and LastName, and providing a single constructor that allows us to create a new Customer … Customer(customerNumber, firstName, lastName)
Now there is no possibility that this Customer can become invalid – it either has these three properties or it cannot be created. If we want to be able to change the Customer’s name, we can create a new method .UpdateName(firstName, LastName)
By taking this approach, we ensure that the entity can never be put into an invalid state, for example a developer setting a .FirstName property, but forgetting to set the LastName at the same time.
Some have taken this concept too far, and assume that as a Customer also has a Policy, that it must always have one of these or it is invalid. Of course, there are things we may want to do with our Customer that will require it to have a Policy, but that does not constitute an invalid Customer, it constitutes a rule that must be applied before we attempt to take the action.
The purpose of ensuring the Entity is always valid prevents us having to do messy things like checking an .IsValid() method every time we want to persist our entity, or we write a function that accepts an instance of our entity. Enforcing an “always valid” approach will mean that we do not have to code multiple guard clauses scattered across our applications.
The term consistency has come up in this series and around DDD mailing lists. In this respect, consistency is the idea that one piece of data in the system is consistent with another. Here is the bad news:
You cannot ever achieve total consistency
OK – headline over. The point is that something in your application will always be inconsistent. The best example is that when your users have chosen to edit the Customer on their screen they have a copy of that data. By the time they have received that data it will potentially be inconsistent with the domain, and with your persistence store – after all this is why we have the concepts of optimistic and pessimistic locking. When they submit a change to the Customer, it is probably minutes out of date.
Back to our headline, when you accept that it is impossible to achieve total consistency, you can deal with the real problem – how you achieve eventual consistency. Eventually messages will make their way through our domain, eventually data will be persisted, eventually you will have consistency.
While our reporting domain may lag behind our primary domain, does it honestly matter? How important is it that they are both totally consistent? You can certainly achieve a close facsimile of total consistency, but it will come at a high price – does the business want to pay for this?
When you let go of the premise that your data is ever really consistent, it now just becomes an issue of an SLA agreement, if the business really wants data that accurate, then explain the costs and tradeoffs and go with it. If after an explanation they understand that “almost consistent” is good enough for almost all applications, then they just have to make a decision about how important this is to them.
Consistency also applies at a much more granular level, with the domain for example. Entities and Aggregates may be valid, but not consistent with each other at all times. Eventually they should become consistent, but ensuring they are all consistent at all times is very tricky to say the least.
While an Aggregate Root is responsible for ensuring consistency with the Aggregate, it is acceptable, and almost inevitable that Aggregates will be inconsistent with each other at some point in their lifetime.
Again, letting go of the myth of total consistency here will give you far more flexibility.
I would hope this is familiar to all – but perhaps some of you saw me mention it and didn’t quite get my context.
The concept of immutability is pretty much what it says – the thing cannot be mutated – or in context, an Immutable Value Object can be created, but can never be changed.
If you want to change an immutable object, then you can create a new one and replace the original.
By making objects immutable, we avoid many problems with validation and consistency, only the constructors on the object matter, and they only need to validate the parameters passed in. It is far easier to check all the parameters at a single time than to check individual properties against each other at a later stage.
03-04-2009 4:47 PM