Validation and DDD

By Vladimir Khorikov

Validation and DDD can be a tricky combination. How to perform validation in a way that doesn’t lead to domain knowledge leakage?

Validation and DDD

Recently, I came across an interesting discussion on the Jimmy Bogard’s blog. The post itself is quite old but the subject is still relevant. The discussion was about where to implement validation: in aggregates or in application services. It has resonated with me and I’d like to write where I personally stand on this matter.

If you look closely at situations where you need to validate something, most of them will fall into two categories: task-based validations and CRUD-y validations. Let’s start with the task-based one.

Suppose you have an Order class which looks like this:

public class Order

{

    public OrderStatus Status { get; private set; } = OrderStatus.InProgress;

    public string DeliveryAddress { get; private set; }

    public DateTime DeliveryTime { get; private set; }

}

 

public enum OrderStatus

{

    InProgress,

    Delivering,

    Closed

}

Let’s say that you need to implement a delivery feature. There are two business rules that are attached to that feature: all orders must have a non-empty delivery address and the day of delivery cannot be Sunday.

There are several common ways of enforcing these business rules.

Solution 1: IsValid method

The first method would be to assign an address and time to an order and make it validate itself. The validation method should then return any errors it encountered back to the caller. The Order class would look like this:

public class Order

{

    public OrderStatus Status { get; private set; } = OrderStatus.InProgress;

    public string DeliveryAddress { get; set; }

    public DateTime DeliveryTime { get; set; }

 

    public IReadOnlyList<string> ValidateForDelivery()

    {

        var errors = new List<string>();

 

        if (string.IsNullOrWhiteSpace(DeliveryAddress))

            errors.Add(Must specify delivery address);

 

        if (DeliveryTime.DayOfWeek == DayOfWeek.Sunday)

            errors.Add(Cannot deliver on Sundays);

 

        return errors;

    }

 

    public void Deliver()

    {

        Status = OrderStatus.Delivering;

    }

}

And here’s the code from an app service that uses it:

public class OrderController

{

    public ActionResult Deliver(DeliveryViewModel model)

    {

        Order order = GetFromDatabase(model.OrderId);

        order.DeliveryAddress = model.Address;

        order.DeliveryTime = model.Time;

 

        IReadOnlyList<string> errors = order.ValidateForDelivery();

        if (errors.Any())

        {

            ModelState.AddModelError(“”, string.Join(“, “, errors));

            return View();

        }

 

        order.Deliver();

        // Save the order and redirect to a success page

    }

}

The benefit of this approach is that it allows you to concentrate the relevant domain logic within the aggregate thus preventing its leakage. The knowledge regarding what it means to be ready for delivery should clearly belong to the Order class itself as that knowledge fully depends on the data that resides inside that class.

There’s a drawback to this implementation too, and it’s quite substantial. In order to validate itself, the entity must enter an invalid state first. And that means the aggregate no longer maintains its consistency boundary. Its invariants are held loosely and can be broken at any time.

This drawback is a deal-breaker. Invariants that lie within an aggregate should be kept by that aggregate at all times. Their violation leads to many nasty situations, potential data corruption is one of them.

Solution 2: checking validity in the application services layer

Another way to implement this task is to check the incoming request in the application service and send the data to the entity only if it passes the validation. You can do that either manually or with some automatic tool, such as ASP.NET model binder or FluentValidator.

Here’s the code:

public class Order

{

    public OrderStatus Status { get; private set; } = OrderStatus.InProgress;

    public string DeliveryAddress { get; private set; }

    public DateTime DeliveryTime { get; private set; }

 

    public void Deliver(string address, DateTime time)

    {

        DeliveryAddress = address;

        DeliveryTime = time;

        Status = OrderStatus.Delivering;

    }

}

 

public class OrderController

{

    public ActionResult Deliver(DeliveryViewModel model)

    {

        Order order = GetFromDatabase(model.OrderId);

 

        // ModelState uses rules defined by FluentValidator

        // (or similar tool) to validate DeliveryViewModel

        if (!ModelState.IsValid)

        {

            return View();

        }

 

        order.Deliver(model.Address, model.Time);

        // Save the order and redirect to a success page

    }

}

What makes this approach so appealing is the declarative nature of the validation rules and the ability to attach them to ASP.NET’s execution pipeline. Here they are defined using FluentValidator:

public class DeliveryViewModelValidator : AbstractValidator<DeliveryViewModel>

{

    public DeliveryViewModelValidator()

    {

        RuleFor(x => x.Address).NotEmpty().WithMessage(“Must specify delivery address”);

        RuleFor(x => x.Time).Must(NotBeSunday).WithMessage(“Cannot deliver on Sundays”);

    }

 

    private bool NotBeSunday(DateTime dateTime)

    {

        return dateTime.DayOfWeek != DayOfWeek.Sunday;

    }

}

The shortcoming of this approach is that it encourages business logic leakage. The Order entity is no longer accountable for holding the domain knowledge about its invariants. This responsibility is drifted away from the domain model to the application services layer.

Also, while we do check for validity of the entity prior to calling the Deliver method, there’s nothing preventing us from assigning the entity incorrect data. Unlike in the previous code sample, we don’t actively do that but this scenario remains possible. The aggregate in this implementation still doesn’t maintain its invariants.

This implementation is still better than the previous one, though, and it might be fine to use it in simple code bases. In complex projects, however, it’s important to keep the domain model invariants intact for maintainability reasons.

Solution 3: TryExecute pattern

The third way is to make the Deliver method do all the validations needed and either proceed with the delivery or return back any errors it encounters. Here’s how it can be done:

public class Order

{

    public OrderStatus Status { get; private set; } = OrderStatus.InProgress;

    public string DeliveryAddress { get; private set; }

    public DateTime DeliveryTime { get; private set; }

 

    public IReadOnlyList<string> Deliver(string address, DateTime time)

    {

        var errors = new List<string>();

 

        if (string.IsNullOrWhiteSpace(address))

            errors.Add(“Must specify delivery address”);

 

        if (time.DayOfWeek == DayOfWeek.Sunday)

            errors.Add(“Cannot deliver on Sundays”);

 

        if (errors.Any())

            return errors;

 

        DeliveryAddress = address;

        DeliveryTime = time;

        Status = OrderStatus.Delivering;

 

        return errors;

    }

}

 

public class OrderController

{

    public ActionResult Deliver(DeliveryViewModel model)

    {

        Order order = GetFromDatabase(model.OrderId);

 

        IReadOnlyList<string> errors = order.Deliver(model.Address, model.Time);

        if (errors.Any())

        {

            ModelState.AddModelError(“”, string.Join(“, “, errors));

            return View();

        }

 

        // Save the order and redirect to a success page

    }

}

This is essentially what int.TryParse(“5”, out val) does when you try to parse a value, hence the name TryExecute.

From the domain model purity standpoint, this approach is much better. The entity here both holds the domain knowledge and maintains its consistency. It’s impossible to transition it into an invalid state, the invariants are guaranteed to be preserved.

Solution 4: Execute / CanExecute pattern

The implementation above violates the CQS principle: it both mutates the entity’s state and returns a value. It’s not a big deal but it would be nice to eliminate this shortcoming.

To do that, you can separate the Deliver method in two: Deliver and CanDeliver:

public class Order

{

    public OrderStatus Status { get; private set; } = OrderStatus.InProgress;

    public string DeliveryAddress { get; private set; }

    public DateTime DeliveryTime { get; private set; }

 

    public IReadOnlyList<string> CanDeliver(string address, DateTime time)

    {

        var errors = new List<string>();

 

        if (string.IsNullOrWhiteSpace(address))

            errors.Add(“Must specify delivery address”);

 

        if (time.DayOfWeek == DayOfWeek.Sunday)

            errors.Add(“Cannot deliver on Sundays”);

 

        return errors;

    }

 

    public void Deliver(string address, DateTime time)

    {

        if (CanDeliver(address, time).Any())

            throw new InvalidOperationException();

 

        DeliveryAddress = address;

        DeliveryTime = time;

        Status = OrderStatus.Delivering;

    }

}

 

public class OrderController

{

    public ActionResult Deliver(DeliveryViewModel model)

    {

        Order order = GetFromDatabase(model.OrderId);

 

        IReadOnlyList<string> errors = order.CanDeliver(model.Address, model.Time);

        if (errors.Any())

        {

            ModelState.AddModelError(“”, string.Join(“, “, errors));

            return View();

        }

 

        order.Deliver(model.Address, model.Time);

        // Save the order and redirect to a success page

    }

}

This approach offers better separation of concerns due to adherence to CQS. Note that it’s still impossible to transition the entity into an invalid state. The Deliver method declares a precondition saying that CanDeliver must hold true prior to executing the delivery. (Here you can read more on the subject of validation vs invariants: code contracts vs input validation.)

CRUD-y validations

Solution 4 (Execute / CanExecute pattern) works best in task-based scenarios where the user just wants to execute a task and where it’s perfectly fine to return a generic error message if something goes wrong.

It’s not as good in CRUD scenarios where you need to map potential validation errors back to UI. For example, you might have Delivery Time and Delivery Address UI fields which should be highlighted in case values in them are incorrect.

In such situation, you have two choices. The first one is to take the 2nd approach and do the validation in the application services layer. Again, not too pleasant but quite easy to implement.

The second one is to adjust the 4th solution and make the CanDeliver method return not just plain strings but special Error instances which would contain information about the source of the problem (read: UI fields). You may create an enum listing all those possible sources and then implement a mapping mechanism to convert them into field names on the UI.

Unlike in task-based validation, here, the choice is not as clear. The complexity overhead you’d need to introduce for the solution with CanDeliver method makes it less appealing for CRUD-y validations. Overall, both approaches are clunky, so you need to carefully weigh their pros and cons before considering one over another.

Summary

There are 4 possible ways to implement validation.

  • IsValid method: transition an entity to a state (potentially invalid) and ask it to validate itself.
  • Validation in application services.
  • TryExecute pattern.
  • Execute / CanExecute pattern.

There are two major types of validation.

  • Task-based where you don’t need to map validation errors to UI elements.
  • CRUD-y where you do need to do that.

The Execute / TryExecute pattern works best for task-based scenarios. For CRUD scenarios, you need to choose between Execute / TryExecute and validation in application services. The choice comes down to purity versus ease of implementation.

Related articles

LinkedInRedditTumblrBufferPocketShare




  • Harry McIntyre

    You might be interested in my ‘Harden’ library, which can be used to do something along the lines of the `CanDoSomething` method:

    https://github.com/mcintyre321/Harden/blob/master/Harden.Tests/Validation/CanValidateMethodParameters.cs

    The idea was to wrap your domain objects with a dynamic proxy which automatically calls the `CanX` checks you mention above.

    I think it would be better to use compile time weaving with Fody as can be very tricky to proxy all your domain objects in a way that works nicely with an ORM.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Interesting idea!

  • Guillaume L

    I’m not sure option 3 conforms to the TryX() pattern like TryParse does, since as a convention in the .NET ecosystem, it should return true or false indicating whether the operation succeeded or not.

    In solution 4, CanX(), also as a convention, should return a boolean. I find “if (CanDeliver(address, time).Any())” a bit awkward since Can denotes an ability, not a potentiality for errors.

    Things like “all orders must have a non-empty delivery address and the day of delivery cannot be Sunday” look like invariants to me. I prefer to keep my entities always valid rather than having an out of band validation mechanism. I always try to constrain as much as I can on a type level. For instance, Deliver() could take in a WorkingDay value object that cannot be initialized to Sunday. Statically typed functional languages like F# can be a big help in that regard.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      I’m not sure option 3 conforms to the TryX() pattern like TryParse does, since as a convention in the .NET ecosystem, it should return true or false indicating whether the operation succeeded or not.

      The signatures differ of course, but I think TryParse and the 3rd option aim at essentially the same thing: validate some condition and if it holds true, execute an operation.

      I find “if (CanDeliver(address, time).Any())” a bit awkward since Can denotes an ability, not a potentiality for errors.

      I agree. However, I couldn’t find a naming that would both fit the act of returning a list of errors and tell the client that this is the method they should use prior to calling Deliver(). How would you name it?

      I also agree with the last paragraph. That’s basically the premise behind the concept of primitive obsession. I wouldn’t do that on simple code bases, though, as this practice is not as trivial to implement in C# as in F#.

  • Sergey Tachenov

    Isn’t it possible to merge the CanExecute and application services validation approaches together for CRUD-y validation? An application service could perform the validation, but delegate actual validation rules to the domain layer. The order then should have methods like IsDeliveryAddressValid() and IsDeliveryTimeValid(), and the application service would delegate to them. This would keep the actual logic within the domain layer, but will allow to validate each field separately.

    There are obvious drawbacks to this approach as well, though. If validity of the address depends on the time, for example, the IsDeliveryAddressValid() should accept two parameters: address and time. It can get very ugly if there is a lot of inter-dependencies between data fields being validated. It could be mitigated by packing the parameters into some sort of DTO, but this raises the question of who does the packing.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      In this example, it is, indeed. Even better, we could wrap these two concepts (Address and Time) into separate Value Objects as Guillaume proposed below and then map errors from them manually to UI controls. Something like this:


      Result<DeliveryAddress> address = DeliveryAddress.Create(model.Address);
      Result<DeliveryTime> time = DeliveryTime.Create(model.Time);

      if (address.IsFailure)
      ModelState.AddModelError(Address, address.Error);
      if (time.IsFailure)
      ModelState.AddModelError(Time, time.Error);

      In more complex scenarios (with lots of fields to validate and different kinds of validations) that would look quite awkward comparing to the approach with validations in app services layer. But still feasible, indeed.

  • Gajanan Kulkarni

    Recently I was working on Customer entity which had below Rules
    1) Credit Limit should be above threshold limit
    2) It should have valid first name and last name
    3) Age > 20

    So I modelled this validation in Entity object with IsValid() function and called this method in constructor. If validation rules failed, my entity constructor would throw exception saying which all rules are not followed…

    So my entity wont be created if it is not valid. So is it bad way of doing it.

    • Naeem Sarfraz

      Personally that doesn’t seem a bad solution at all. Question is, do you need to report back which rule was violated? I’m guessing your IsValid method returns a bool and so you wouldn’t know which rule was violated.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      You do protect the entity’s invariants here, so that part is covered. However, as Naeem mentioned, in most cases you need to return a result of your validation to the client code. And, as this is a constructor and not some other method on the entity, you won’t be able to do that. I’d recommend adding a factory that returns Result.

  • pbujok

    Once you have written about wrapping result in class like Result. What do you think about using this approach to resolve this issue?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      An approach with Result would essentially be the same as the 3rd and the 4th ones from the article. I would indeed prefer to use Result in place of plain strings. With Result, you’d have the same challenges as with strings, though: you’ll need to come up with a mechanism for mapping the errors to the UI fields. Probably by introducing a hierarchy of types of errors.

  • Patrick Tully

    I guess this is more of an opinion, but I prefer solution 3 to 4. It might violate CQS, but I don’t buy that that’s necessarily a bad thing. I would still consider throwing an exception a form of a return value, it’s just hidden from the function signature. It might be nice to still have the CanExecute function as well though in case you don’t want to actually take action.

  • Joseph Ferris

    Nice write-up. Very similar to the solution that I have in place right now, too. One change I’ve been wanting to make to my own implementation is to add a couple of methods to my AggregateRoot base class that would look something like the following pseudo-code:

    protected void Enforce(Command command)
    {
    var results = Validate(command);

    if (results.Any())
    {
    throw new CommandValidationException(results);
    }
    }

    protected IEnumerable Validate(Command command)
    {
    var results = ((dynamic)this).Validate(command);
    return results;
    }

    Approach is pretty similar to how several people have written on applying Events to an AggregateRoot for playback in an ES system. Basically, you would have the Command Handler replay the Aggregate Root to get it to current state, and then would push the derived Command instance to the Aggregate Root. Through the dynamic, it would dispatch to the private method of the same name that matches the signature. Then, the actual method that you wanted to call on the Aggregate Root would simply do an Enforce() and throw the exception.

    Caveats, of course, would be that you would want to add something additional to handle (in both the Validate() and Enforce() methods on the base class) when those implementations cannot be invoked – such as when a derived Command is passed in that does not have an explicitly declared private method with the same handler.

    Keep wanting to throw a sample together and put it up on my (poor neglected) blog.

  • http://consciousprogrammer.com Marco Willemart

    This is indeed an interesting topic and one that is, in my opinion, not extensively covered in the various DDD books.

    Personally I like to keep validation out of my domain model. Of course the domain model should enforce business rules and the like by means of invariants, pre and post conditions, etc. However validation is another concern that should be tackle elsewhere. I’ve found that adding validation to the domain model adds a lot of complexity into the code which quickly becomes hard to read/maintain. One could also argue that this violates the Single Responsibility Principle.

    Also there are many kinds of validation, on the top of my head:
    – domain and range of values
    – identities that must reference existing aggregates
    – constraints over several aggregates
    – …

    Some can easily be checked without accessing the persistence state, but some are not. So I like the validation to be performed in one place where I’m able to check all the validation rules at once.

    So we’ve implemented the following solution in our current project:

    Commands are sent to application services, however before being handled they are automatically intercepted by an aspect which applies the appropriate validator class. The validator performs all the necessary validations by means of a few queries against the query model (we’re using a CQRS architecture here). Then if the validation passes the application service handles the command which is expected to be executed with success (the defensive checks in the domain model should not fail). On the other hand, if the validation fails, an exception is thrown with the corresponding error message and error code (so the problem can either be displayed to the end user or be handled programmatically (i18n, HTTP codes, particular formatting, etc).

    This way the system can be used by any client (UI, REST, etc) and it reacts appropriately. Now there’s the concern of mapping validation to UI fields. Because a particular UI is just one client among others, I don’t think application services (or the domain model) should know about particular fields, etc. This would couple tightly the client to the core (application services + domain model) of the bounded context.

    So in this case we just duplicate whatever validation needs to be performed “on the fly” by the UI on specific fields (which may change from one client to the other). So far, the benefits of going this way clearly outweigh the cost of duplication. At first this may seem useless, but when the system changes and evolves, this is quite easy to handle.

    Here was my 2 cents on this topic. I don’t think our solution is perfect, but so far it has been proven to be useful and effective. Time will tell if we’re right :-)

  • jorgeser

    Hi Vladimir,

    I think you did a little mistake on your code.

    Where you put:
    !string.IsNullOrWhiteSpace

    I think that it should be:
    string.IsNullOrWhiteSpace

    I hope that helps if someone test your code samples.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Indeed! Fixed it, thanks.

      • https://j0rgeserran0.github.io/ Jorge Serrano Pérez

        You are welcome! :)

  • jorgeser

    Other comnents about these samples:

    In natural language, this code instruction are not clear:

    if (CanDeliver(address, time).Any())

    Normally it should be:

    if (!CanDeliver(xxx))

    Because that you are telling here is that you CanDeliver and throws an Exception, and it has not a correct meaning.
    In other case, you could change the name of the method by:

    CanNotDeliver and the natural language could be correct in this case.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      How would CanNotDeliver be different here? Could you give an example?

      I agree that

      if (CanDeliver(address, time).Any())

      doesn’t seem natural. I couldn’t find a naming that both fits the act of returning a list of errors and tells the client that this is the method they should use prior to calling Deliver(). So appreciate any suggestions.

      • https://j0rgeserran0.github.io/ Jorge Serrano Pérez

        Hi Vladimir.

        We are talking about little details of the code.
        In this case, only about the naming.
        But when we are writing code for the programmers (not only for us but also for ALL), is important keep all details and the quality of the code.

        For me, when I read “CanDeliver” is an affirmative question, isn’t it?
        So, to cover all possibilities, I suggested CanNotDeliver because here we would like to call this method to check if we can deliver or not checking the validations, and “CanNoDeliver” is the opposite of “CanDeliver”.
        However, it is possible that the name I suggested be a bad idea.

        A better choice here could be an abstract name to perform the same call always in all classes. Not only in the Order class.
        Create an interface, and implementing this interface in our classes is other solution too to use the same name always.

        The name of this method could be the standard name: IsValidate

        You could see the calls as Order.IsValidate.
        .IsValidate()

        However, “IsValidate” is a method that seems as is waiting a true/false value.

        So, again, we should think another alternative.
        .Validate()

        This is the general call to validate the entity, and all programmers know the meaning of Validate().

        So, if you call to .Validate(), you know that you are validating the entity sure without some doubt.

        This is my opinion. :)

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          Ah, I see your point now. Interesting suggestion, thanks :)

      • Michael G.

        How I have handled it thus far is by returning a Result object with an error collection of List. Then it is as simple as:

        Result deliveryCheck = CanDeliver(address, time);
        if (deliveryCheck.Failed)

        Alternatively an implicit operator on the Result class could be used to convert it to a boolean for logical checks:

        Result canDeliver = CanDeliver(address, time);
        if(!canDeliver)

        I am not a fan of the latter, but it can have its uses.

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          Heh, indeed, it’s much more readable!

  • https://j0rgeserran0.github.io/ Jorge Serrano Pérez

    I don’t want to divert the attention of this post, but I find necessary to talk about exceptions and validations.

    I am talking about the last sample code (Solution 4).
    (I don’t know if you did a mistake here but…)

    When the validation is incorrect, is it a good practice to throw an Exception?

    There is a “mantra” that said that you should never use exceptions as part of your logical coding.
    Sometimes the difference between to know if the validations are inside of the logical coding or not is very thin.
    In other cases to use exceptions here is an advantage, but normally, to throw exceptions in the validation actions is not a good idea.

    In fact, the name exception marks the meaning of it.
    Exeption-al.
    So an exception should be thrown in exceptional cases only, and an incorrect validation (not as a mantra) is not an exceptional case normally.

    What do you think about it?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      I agree, validations should not be handled by exceptions. In the 4th solution, however, the exception is there not to be handled by any external code (that’s why it’s just a InvalidOperationException btw, and not some custom exception type), it’s there to protect the entity’s invariants. If thrown, this exception signalizes there’s a bug in the software: the application service haven’t done its part correctly and called the Deliver() method using incorrect parameters.

      Here I wrote in more detail about the differences between validation and invariants: http://enterprisecraftsmanship.com/2015/02/14/code-contracts-vs-input-validation/

      • https://j0rgeserran0.github.io/ Jorge Serrano Pérez

        Great!

        I’m sorry, I didn’t read that post.
        Exactly that!!!

        Good post!!! :)