8

I have done a lot of reading recently about Always Valid domain entities. I have come to believe that in order to ensure the entities are always valid I need to:

1) Remove primitive obsession and put validation/domain rules in the value object constructors as explained here: https://enterprisecraftsmanship.com/2016/09/13/validation-and-ddd/. 2) Put validation/domain rules in the constuctor of entities or the property setters as explained here: http://gorodinski.com/blog/2012/05/19/validation-in-domain-driven-design-ddd/.

However, I then look at some Open Source projects such as this one: https://github.com/gregoryyoung/m-r. From what I understand the author of this project is an advocate of the always valid domain model and yet I look here at the InventoryItem class: https://github.com/gregoryyoung/m-r/blob/master/SimpleCQRS/Domain.cs. I notice that I am able to do this:

InventoryItem inventoryItem = new InventoryItem();

or this:

InventoryItem inventoryItem2 = new InventoryItem(Guid.Empty,null);

In my mind this means the entity is initialised in an invalid state. This seems to be the case in all of the other Open Source projects I have looked at recently as well e.g. this one: https://github.com/dcomartin/DDD-CQRS-ES-Example/blob/master/src/Domain/Customer.cs.

I realise there is Contextual validation in these open source project (https://martinfowler.com/bliki/ContextualValidation.html). I also realise that ORMs need a default empty constructor if mapped to the domain model.

Is a domain object in a valid state if it is initialised with default values using a zero arguement constructor/initialised with empty/null values?

  • 2
    You really can't generalise. It MIGHT be. It might be not. Does it matter? IMHO no, especially early DDD talks forgot to think that reality is different and for example, ORMs/languages/frameworks dictate some rules (and the price to circumvent them may be too high or not worthy). Ok, also project you listed don't seem to be best possible .NET code ever... – Adriano Repetti Jun 10 '18 at 18:51
  • @Adriano Repetti, do you know of any good cqrs open source projects? Do you put validation in your commands? – w0051977 Jun 10 '18 at 19:06
  • 2
    I'd distinguish parameters validation from domain validation (when applicable). For example a null parameter has nothing to do with the domain, it comes from an implementation detail (language you're using). The former I always do, no matters what and where. Domain validation is more tricky but if you really really worry about broken invariants then, IMO, you should consider immutable objects. They're (again just in my opinion) an, often, better tradeoff than a holy war against languages we really use (and that was a critique to many older DDD takes) – Adriano Repetti Jun 10 '18 at 21:58
7

Before I address the kinds of considerations that go into object creation, let's first address the motivation behind your question: the phrase "Always Valid Domain Entities". This phrase is, at best, misleading, and makes little sense in the context of DDD. This should be apparent for two related reasons:

The first is that it implicitly shifts your focus away from the behavior of the system, instead, asking you to consider validation only in terms of state. While superficially this may seem to make sense (of course validation is in terms of state!), you must remember that the fundamental principal of DDD is that a system is modeled according to behavior. The motivation for this is quite simply that the context, or the business process itself, is often an important consideration when determining whether or not some piece of state is valid. Modeling a system in this way can greatly reduce it's complexity.

This brings us to the second reason, which is in regard to the practical requirements such a system would entail. In order to create a system of "Always Valid Domain Entities", it would require one to model every single permutation of state according to the business processes in which the state is used. A simple example can illustrate the limitations of this:

Rules:

  • Customer must be over 18 to register
  • Customer must be under 25 to qualify for discount on registration
  • Customer must be over 25 to make reservation

The first thing you should notice is that all of these rules (like nearly all rules) apply to some business process. They don't exist in a vacuum. These rules would be validated on customer.Register() and customer.Reserve(). This results in a much more descriptive and declarative paradigm because it's clear where rules are executing.

If we wanted to model these rules such that it results in system of "Always Valid Domain Entities" we would need to partition our Customer into Registrar and Reserver entities. And while that might not seem so bad for this example, as rules become more complex and abundant you will end up with an explosion classes like this that represent state "within" some context or process. This is simply unnecessary and will inevitably create issues when two such objects are dependent on the same slice of state.

Additionally, something like Customer c = new Customer() is a bad place to throw an exception because it's unclear what business rules might apply. Which brings us to our final discussion.

I am just going to come out and go as far to say that there should be zero validation of business rules happening in constructors. Object construction has nothing at all to do with your business domain, and for that reason, in addition to the reasons above concerning context and coherence, all business rules should be enforced within an entity's method bodies (it's likely methods are named after business processes right?).

Furthermore, "newing" up an object is not the same thing as creating a new entity in your domain. Objects don't come out of nowhere. If there are business rules regarding how a new entity can come into your system, then it should be modeled in your domain. Here is some further discussion on the topic by a true master http://udidahan.com/2009/06/29/dont-create-aggregate-roots/

3

Is a domain object in a valid state if it is initialised with default values using a zero arguement constructor/initialised with empty/null values?

It can be.

There is nothing against the rules about creating a valid domain object using a default constructor.

There is nothing against the rules about creating a valid domain object with empty values.

There is nothing against the rules about creating a valid domain object that lacks optional elements.

There is nothing against the rules about creating a valid domain object using nulls.

Where problems occur: creating domain objects that don't obey their own semantic algebra.

The correct implementation depends on a correct interpretation of the semantics.

It's a normal thing to take a forgiving representation of a domain concept and by steps apply additional constraints. This is one of the areas where implementation languages that make it easy to add types (ex: F#) have advantages over clumsier languages like Java.

For example, if we have a domain that cares about numbers, and within that domain are some capabilities that are specific to prime numbers, or Mersenne primes, then a natural mechanism to use is to create three different types; making explicit the notion that there are different sets of constraints to be applied to the inputs in different parts of your solution.

Number n = new Number(...)
Optional<Prime> p = n.prime()
if (p.isPresent()) {
    Optional<MersennePrime> mp = p.mersennePrime()
    // ...
} 

In this sort of design, the "validation" that the number really is a Prime would exist within Prime constructor itself. In a context where we need the additional constraint that the parameter is a Mersenne prime, we use a Prime -> MersennePrime conversion, ensuring that the knowledge of the Mersenne constraint has one authority ("don't repeat yourself").

"Make the implicit, explicit"

  • Thanks. Could you explain what semantic algebra is with perhaps an example? Could you also explain how the code sample is relevant. +1 for "there is nothing against....". – w0051977 Jun 11 '18 at 14:34
  • Surely an entity without an empty ID is a bad thing? Unless there are scenarios where you initialise the domain class with default values and then build it incrementally? – w0051977 Jun 12 '18 at 8:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.