Validation in DDD

iamprovidence
4 min readSep 30, 2022

--

Validation is something that performed across your entire system. Your input fields have some validation, then you validate your request, your domain model has its own set of rules, even your infrastructure like database will perform some validation, probably on uniqueness or something. Validation do not happen much.

When coming to DDD there are two common opinion about having domain model (not classes) in Always-valid state and Not-so-valid 😁 Today we will see a difference between those approach and decide which one is better.

However, before talking about validation, it is worth to mention Business invariants. You may have heard about it, but just to make sure we are on the same page, let’s remember:

Business invariant — is a condition that should be truthy for the entire lifecycle of domain model.

In human language, if your business requirement says it should not be possible for Order to have more than three item in it, than it should not be possible to assign more than three item to Order class in your code.

Long story short, business invariant and validation are the same thing. While validation is a more general term, business invariant is a validation rule related to your business model. Since we are talking about DDD, especially focusing on Domain, just think about those as they are equal.

Now, when everything clear, shall we begin?

Always-valid model

Adherents of Always-valid school claim that the domain model should always be in a valid state. Meaning, before performing any action, validation should occur. Notice, how in the example below, we throw an exception for invalid arguments or when invariant is violated.

That is not a new thing in programming and being overused, so often, that developers start confusing what terms you should use to describe it. Some refer it as if-then-throw pattern, other fail-fast principle and so on. Whatever you call, it’s still the same thing.

However, the simple use of exception, might not ensure that the object is in a valid state. Some complex business validation will require interaction with database. Which is expected. Domain rules can not be fully validated by single entity and most likely you still will need to came up with some service or another solution.

Not-always-valid model

Following this approach, we allow our entity to be invalid. Instead of always keeping it in valid state, we will perform validation of all invariants in a single Validate() method:

The Validate() method is usually called before persisting domain model, but can also be used before performing complex business logic:

The advantage here that we gather most of the validation in a single place. Why most? — you may wonder. Because, there are still some rules that just can not be validated on a final state, like the one we had in Cancel() method.

Secondly, it is also possible to accumulate validation messages in a single exception. With fail-first approach, you would need to send tons of request before you finally configure each property to be correct. On the other hand, this one will return all validation messages together.

Which one is better? 🤔

Now, when you have seen different validation approaches, we can decide which one to use. Even thought it is up to you, my suggestion would be to use Always-valid approach.

With not-always-valid approach, you simply can not be sure that you have a fully working model. Thus, there is always a need to investigate all references to make sure validation is not missed. That just tons of maintenance overhead.

Although, it may be useful to ignore the validation rule in some cases (when writing a unit test for example it always annoys me that I need to spend hours arranging correct data, for my test to work) I better catch an exception then store invalid data because I forget to call Validate().

On the other hand, always-valid approach decreases complexity of code support. It does not allow violating any business invariants. It does not allow providing wrong arguments, which lead to unstable state of your model. And you should not even do that. You should not have empty address and if something like that happens it is rather exceptional situation that should be reported right away and not in another function after other hundred line of code.

Choose Always-valid approach, and you will see how much easier it is to maintain your codebase.

📝 Let me know into the comments which one you prefer and why

☕️ Buy me a coffee if you want to support me

✅ Follow to get more articles about DDD

--

--

iamprovidence

👨🏼‍💻 Full Stack Dev writing about software architecture, patterns and other programming stuff https://www.buymeacoffee.com/iamprovidence