I am looking for advice on where to add validation rules for domain entities, and best practices for implementation. I did search and did not find what i was looking for, or i missed it.
I would like to know what the recommended way is for validating that properties are not null, in a certain range, or length, etc... I have seen several ways using an IsValid() and other discussions about enforcing in the constructor so the entity is never in an invalid state, or using preprocessing and postprocessing, and others using FluentValidation api, how invariants impact DRY and SRP.
Can someone give me a good example of where to put these sorts of checks, when using a App Service, Bounded Context, Domain Service, Aggregate Root, Entity layering. Where does this go, and what is the best approach?
Thanks.
I built a library that can help you.
https://github.com/mersocarlin/ffffd-validation
When modeling your domain entity, it is best to consider real-world implications. Let's say you are dealing with a
Employee
entity.Employees need a name
We know that in the real-world an employee must always have a name. It is impossible for an employee not to have a name. In other words, one cannot 'construct' an employee without specifying its name. So, use parameterised constructors! We also know that an employees name cannot change - so we prevent this from even happening by creating a private setter. Using the .NET type system to verify your employee is a very strong form of validation.
Valid names have some rules
Now it starts to get interesting. A name has certain rules. Let's just take the simplistic route and assume that a valid name is one which is not null or empty. In the code example above, the following business rule is not validated against. At this point, we can still currently create invalid employees! Let's prevent this from EVER occurring by amending our setter:
Personally I prefer to have this logic in the private setter than in the constructor. The setter is not completely invisible. The entity itself can still change it, and we need to ensure validity. Also, always throw exceptions!
What about exposing some form of
IsValid()
method?Take the above
Employee
entity. Where and how would anIsValid()
method work?Would you allow an invalid Employee to be created and then expect the developer to check it's validity with an
IsValid()
check? This is a weak design - before you know it, nameless Employees are going to be cruising around your system causing havoc.But perhaps you would like to expose the name validation logic?
We don't want to catch exceptions for control flow. Exceptions are for catastrophic system failure. We also don't want to duplicate these validation rules in our codebase. So, perhaps exposing this validation logic isn't such a bad idea (but still not the greatest!).
What you could do is provide a static
IsValidName(string)
method:Our property would now change somewhat:
But there is something fishy about this design...
We now are starting to spawn validation methods for individual properties of our entity. If a property has all kinds of rules and behavior attached to it, perhaps this is a sign that we can create an value object for it!
Now our
Employee
entity can be simplified (I have excluded a null reference check):Our client code can now look something like this:
So what have we done here?
We have ensured that our domain model is always consistent. Extremely important. An invalid entity cannot be created. In addition, we have used value objects to provide further 'richness'.
PersonName
has given the client code more control and more power and has also simplifiedEmployee
.