20

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.

Jeff M
  • 375
  • 2
  • 8
  • An example: https://github.com/szjani/predaddy-issuetracker-sample/blob/master/src/hu/szjani/domain/issue/Issue.php – inf3rno Jun 26 '14 at 02:24
  • Imho they should not impact SRP. You can do a validation before setting a domain object property, for example in the commands if you use CQRS, so you will be sure, that they are valid... You can annotate your domain objects and use that data for validation. – inf3rno Jun 26 '14 at 02:34

2 Answers2

42

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.

public string Name { get; private set; }

public Employee(string name)
{
    Name = name;
}

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:

public string Name
{
    get
    {
        return name;
    }
    private set
    {
        if (String.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentOutOfRangeException("value", "Employee name cannot be an empty value");
        }

        name = value;
    }
}

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 an IsValid() 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:

public static bool IsValidName(string name)
{
    return (String.IsNullOrWhiteSpace(value))
}

Our property would now change somewhat:

public string Name
{
    get
    {
        return name;
    }
    private set
    {
        if (!Employee.IsValidName(value))
        {
            throw new ArgumentOutOfRangeException("value", "Employee name cannot be an empty value");
        }

        name = value;
    }
}

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!

public PersonName : IEquatable<PersonName>
{
    public string Name
    {
        get
        {
            return name;
        }
        private set
        {
            if (!PersonName.IsValid(value))
            {
                throw new ArgumentOutOfRangeException("value", "Person name cannot be an empty value");
            }

            name = value;
        }
    }

    private PersonName(string name)
    {
        Name = name;
    }

    public static PersonName From(string name)
    {
        return new PersonName(name);
    }

    public static bool IsValid(string name)
    {
        return !String.IsNullOrWhiteSpace(value);
    }

    // Don't forget to override .Equals
}

Now our Employee entity can be simplified (I have excluded a null reference check):

public Employee
{
    public PersonName Name { get; private set; }

    public Employee(PersonName name)
    {
        Name = name;
    }
}

Our client code can now look something like this:

if(PersonName.IsValid(name))
{
    employee = new Employee(PersonName.From(name));
}
else
{
    // Send a validation message to the user or something
}

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 simplified Employee.

Dave New
  • 38,496
  • 59
  • 215
  • 394
  • 4
    +1 This is possibly the best example of how to encapsulate most of my validation needs that I've ever read. – Adrian Thompson Phillips Jun 26 '14 at 10:08
  • 3
    +1 it's nice to see an answer from someone who truly understands DDD, this is something of a rarity on StackOverflow!! – MattDavey Jun 26 '14 at 10:08
  • @AdrianThompsonPhillips if you like these ideas, also take a look at [this video from NDC](http://vimeo.com/97507575) – MattDavey Jun 26 '14 at 10:11
  • @MattDavey cheers, I'm a massive defensive programming and value object fan. The addition of the 2 static methods and how they've been used is what I'm loving the most. It combines testing before setting, but has the fallback of throwing an exception. Perfect. – Adrian Thompson Phillips Jun 26 '14 at 10:17
  • Thanks for all the material... I am use to the example of using value objects where it make sense, and providing validation logic for them; i like the use of the static logic. I was also looking at this way, an alternative and would love some feedback on this method of implementation. [link](http://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/) – Jeff M Jun 26 '14 at 16:58
  • 2
    This is quite simple (simplistic?!) example. It gets harder with validation rules requiring check in the DB - eg. unique name or email. Then internal validations or static methods are not helping as much as here or they get bloated so separation of concern (eg. separate validation class) would be required. Let's not forget on context dependent validation when an Employee has name validation rules (eg. middle name required or not) based on where is he from (country) or what system is he/she for (eg. System A or from remote System B). – Tomas Dermisek Jun 29 '14 at 23:22
  • I've always understood that regarding ".... with validation rules requiring check in the DB..." these should be done in the application layer/service and that the domain model should only contain isolated invariant checks. – Jeff M Jul 01 '14 at 23:09
  • 1
    Not to nitpick, but this is not a valid "real-world" assumption: "We also know that an employee's name cannot change." Of course an employee's name can change. It happens frequently when people get married. Any system worth its salt should be able to accommodate that. – Louise Eggleton Dec 15 '14 at 16:02
  • 1
    @LouiseEggleton: You are 100% correct. The example is purely for illustrative purposes. – Dave New Feb 06 '15 at 14:23
  • @TomasDermisek This is why we in DDD distinguish between syntax rules, semantic rules and production rules. Unique name or e-mail address are regarded semantic rules, which checks whether the provided command makes sense given the current state of the system. On the other hand, a syntax rule validates that the provided data is coherent for the system. – Frederik Krautwald Sep 08 '20 at 13:39
-1

I built a library that can help you.

https://github.com/mersocarlin/ddd-validation

Hemerson Carlin
  • 7,354
  • 1
  • 27
  • 38