I’ve been following intently the conversation that has been going around recently surrounding Domain Driven Design and validation within the domain. I have been swirling it around in my head for a bit, and I’m still not quite sure that I am 100% in the game, but I wanted to get my thoughts out on paper (or at least on my blog) so that others would have a chance to respond.
In case you have not been following it, the core of the discussion has been revolving around the appropriate place for validation to reside in your application. For many the result was surprising…it should never be in your entities. And interestingly enough, this conclusion seemed to be supported fairly universally by the people responding to this post.
While I guess this should be surprising for me, especially considering the fact that I recently helped design a system where there is a significant amount of validation within entities, I can’t honestly say that it did. The idea of having domain entities validate themselves never really set easy with me. But at the same time, I struggled a bit with the proposed solutions for it. I mean, I can completely understand how contextual validation is, but moving it out of the entities can leave the validation strewn about in the application. And don’t think that just because you are still using “IsValid” on your entities that you are doing something wrong, even Jimmy was proposing this not too long ago, we all have a long way to go guys. He may have been talking about external validator classes, but he was still proposing this validation being kicked off from within the entity. Or as Sean referred to it, “Reactive Validation”.
Now, some of you may be saying “so what if validation is contextual, the entity will have context so you can execute validation based on that context”. And yes, that is true to a certain extent. The entity will have knowledge of its own context, but validation could easily be based on context outside of the entities. Or it could be based on context which has little bearing on the domain at all. The example given in a comment on Jimmy’s post revolved around some data coming in from the UI being invalid for a particular context, while being perfectly acceptable when coming in through a batch process.
While this may seem like an edge case, these are the kinds of business rules that trip up our applications all the time. These are the types of rules that just scream “technical debt” because as soon as we see something like that come up we immediately get out the duct tape and glue gun. We obviously can’t redesign our application for a single screwy business rule, but sadly they rarely come in singles.
So context is the problem, sweet sweet context. What is valid in situation A may or may not be valid in situation B. In the system I referred to above, we had two levels of validation. We had persistence valid and business rules valid. We recognized that valid was not black and white, and therefore created a finite amount of grayness that fit in with a database persistence model. At least in this case we could save off an entity to the database that was technically invalid, so that a user could come back later, finish it up, and make it valid. I’m starting to see now that the idea was there, but it stopped short of what was needed.
One of the ideas that comes out of the idea of moving validation outside of the entities, is that you can no longer simply as an entity, are you valid? So some people began to suggest that you simply never allow invalid entities. You should always make sure that your entities are valid, which is possible if you are pushing your validation into a service layer. If the data is coming in via a message or view model then you can validate the data before the entity ever sees it. This way you could operate on purely valid entities. But again, what is valid?
If I take this approach and say that I’ll only ever create valid entities, then it is really only valid within a particular context. If I create an entity via one service, validate it, and then persist it, what happens when it gets pulled up and passed to another service? I’m either missing something here or this can create issues. You would have to validate the entity immediately upon retrieval or you would have “invalid” entities. The issue in my mind is how do you immediately know what context to validate within before you create the entity? Would this happen within the repository? That isn’t kosher at all. But if we aren’t doing it within the repository then we are returning potentially invalid entities from the repository. At least invalid by the context that we are currently operating within.
Sean’s recommendation would be to create different version of your entities that were valid under different contexts, but that doesn’t make sense to me. If I am already having different validations in different contexts, then if I am going to have different entities in different contexts then why not just move my validation back into my entities, since I am going to have one for each context? It just doesn’t jibe with me, and I’m not sure you could make it work without a lot of headaches. Someone prove me wrong!
Putting all of that aside, if we are to move validation out of our entities, then how should we validate them consistently? My mind right now is still clinging to the concept of having IValidator classes which are capable of validating entities or groups of entities in different contexts. It may sound like you’d end up with hundreds of validation classes, but I would think that any given entity or aggregate would only have a handful of different contexts in which they are validated. The trick would be to make sure that they were validated properly in the correct places, but I guess that is what tests are for!
So anyways, after putting some serious thought into it (and reading many a blog post about it) here is what I think:
- Validation should not be inside of domain entities except for under the most simplistic of circumstances.
- Validation does need to be put into well defined areas of the application, it should not just be strewn throughout. If you aren’t using well defined command objects or have a strict service layer, then you are probably just better off putting it in your business objects because you’ll have no consistent means of ensuring validation.
- You should have a consistent strategy for validation, in order to make redundant validation as easy as possible. It is likely that for many entities their validation will always look the same.
- I’m not sure that I agree with the concept that entities should always be valid. I think this poses some problems, but I’d love to see someone prove me wrong here.
I’m really glad that this discussion is taking place currently, and it is good to see it happening across several different people’s blogs. My thoughts are certainly nothing new, but I think that getting them written down will help me think through them a bit more. It has me itching a good bit to try and re-implement a few things that I have been working on to do validation in this manner.
Anyways, I hope you enjoyed the post, and please let me know if you think I have gone off the deep end!