Thoughts On Domain Validation – Part 1

Writing

I have been thinking a bit lately about validation within the Domain. To clarify, I have been looking at entity validation within an application’s domain model. So, what I wanted is a nice way to validate an entity (you may refer to it as a “business object”) to make sure that it is in a valid state. Currently I am focusing on single entity validation, and I have made some good headway thanks to the internets. Right now I have started off with a validation interface that looks like this:

public interface IValidatable
{
    bool IsPersistable();
    bool IsValid();
    IEnumerable<BrokenRuleData> GetBrokenBusinessRules();
    IEnumerable<BrokenRuleData> GetBrokenPersistenceRules();
    IEnumerable<BrokenRuleData> GetAllBrokenRules();
}

As you can see here, I am taking the approach that Jimmy Nilsson talked about in his book “Applying Domain-Driven Design And Patterns” where there is a two level approach to validation in the domain. At one level an entity may not be valid, but it can still be persistable (meaning that it can be saved to your persistence medium, whether that be a database, xml file, etc…). For example, what happens if someone is working on a screen and fills a bunch of data out, then they realize that they don’t have the data that they need. Well, in some cases, we want the user to be able to save their work and come back to it at a later point. If an entity has to be valid according to business rules, then a save to the database might not be possible.

Next I have an interface called IRule<T>. This interface is probably something that you have seen in an application before, it is nothing but the use of the command pattern for rule validation, with a bit of extra meta-data tacked on. I could have split this extra data off into its own interface, but I will only do so when I find a compelling reason. The IRule interface looks like this:

public interface IRule<T>
{
    string ErrorMessage { get; }
    IEnumerable<string> Properties { get; }
    bool Passes(T entity);
}

Here you can see that we have an interface with a single method called “Passes” which returns a boolean that says whether or not the particular entity passes the rule. Pretty simple, although I’m not happy with the name of the method, generally I like my boolean methods to start with “Is”, but we will just leave this for now. I have seen “IsSatisfiedBy”, but I just think that seems long and wordy. If you have any suggestions, let me know. It also has two properties, one that returns a default error message and another that holds the properties on the entities that are affected by the Rule. This could theoretically be empty, but most likely you will want to tie a rule to some property on an entity.

So, how do we implement these rules? Well, I looked around the net and I found a post by JP Boodhoo called “Validation in the Domain Layer“. In his post he actually uses predicate delegates as the means to defining rules, which is an excellent approach. This approach works even better now in C# 3.0 since we have lambdas to make the syntax a bit more terse. So I decided that I was going to define a similar style of rule, and it looks like this:

public class StaticRule<T>: Rule<T>
{
    private readonly Predicate<T> predicate;
    
    public StaticRule(Predicate<T> predicate, string errorMessage, 
        params string[] properties): base(errorMessage, properties)
    {
        this.predicate = predicate;
    }

    public override bool Passes(T entity)
    {
        return predicate(entity);
    }
}

Here you see that I have created a class called StaticRule that takes a predicate, error message, and list of properties. It then passes on the error message and properties to a base “Rule” class that I have defined. You’ll notice that my StaticRule class does not directly implement the IRule interface, it relies on the base Rule class to do this for us. The base Rule class looks like this:

public abstract class Rule<T>: IRule<T>
{
    private readonly string errorMessage;
    private readonly string[] properties;

    public Rule(string errorMessage, params string[] properties)
    {
        this.errorMessage = errorMessage;
        this.properties = properties;
    }        

    public IEnumerable<string> Properties
    {
        get { return properties; }
    }

    public string ErrorMessage
    {
        get { return errorMessage; }
    }

    public abstract bool Passes(T entity);        
}

The base rule class is merely a container for most of the metadata that we have surrounding our rules, it doesn’t implement any real functionality. It relies fully on the child classes to implement the logic needed to satisfy the IRule interface.

But the rules don’t do us any good unless we do something with them. The rules are going to be held inside of our entities because they are the ones that are controlling their own validation. Our entity base class will therefore have lists of business rules and persistence rules which it will use to validate itself. So, lets look at how we would statically add a new rule into a theoretical business entity:

this.PersistenceRules.Add(
        new StaticRule<BusinessEntity>(e => e.SomeValue > 5, 
        "SomeValue must be greater than 5.",
        "SomeValue"));

This may be a bit hard to read, but we have a list called “PersistenceRules” and we are adding a new “StaticRule<BusinessEntity>” to it. There are three parameters that we are passing to the StaticRule constructor, the first of which defines our rule, “e => e.SomeValue > 5”. This is a lambda that takes the entity as a parameter and then checks to make sure that the property “SomeValue” is greater than 5. This is passed into our StaticRule class as a “Predicate<BusinessEntity>” and will be called later on when the Rule is executed. You can see this above in the “StaticRule” class inside of our “Passes” method. These rules are executed on the entity when these methods in our base entity class are called:

public bool IsPersistable()
{
    return (PersistenceRules.Passes((T)this));
}

public bool IsValid()
{
    if (!PersistenceRules.Passes((T)this))
    {
        return false;
    }
    return BusinessRules.Passes((T)this);
}

The idea here is that in order for an object to persist, all of its persistence rules need to be valid, but in order for an object to be “valid” all of its persistence and business rules must pass. Here you see that I have created a “RuleList” class to make it easier to test all of the rules in a list. The “Passes” method that we are calling here is very simple, and just loops through each rule until it finds one that does not pass:

public bool Passes(T entity)
{
    foreach (IRule<T> rule in Rules)
    {
        if (!rule.Passes(entity))
        {
            return false;
        }

    }
    return true;
}

Very simple. So, all of this may seem pretty basic, nothing too special here. We have a pretty basic framework in place for defining static rules on our business entities, and so now we can validate an entity by simply calling “IsValid” or “IsPersistable”:

var businessEntity = new BusinessEntity();
businessEntity.SomeOtherValue = 1;
businessEntity.SomeValue = 1;
bool canPersist = businessEntity.IsPersistable();
bool isValid = businessEntity.IsValid();

Nice, but this is something that has been implemented over and over in many different applications. Maybe you haven’t implemented a system like this in your application, and if so, then you really should put some serious thought into it. A good validation strategy for your business objects is essential. Once you have determined whether or not your objects are valid, then you need to get the info out of them as to what is not valid. In this situation, I have put methods on the base Entity class to handle this:

public IEnumerable<BrokenRuleData> GetBrokenBusinessRules()
{
    return businessRules.GetFailedRules((T)this);
}

public IEnumerable<BrokenRuleData> GetBrokenPersistenceRules()
{
    return persistenceRules.GetFailedRules((T)this);
}

public IEnumerable<BrokenRuleData> GetAllBrokenRules()
{
    var result = new List<BrokenRuleData>();
    result.AddRange(GetBrokenPersistenceRules());
    result.AddRange(GetBrokenBusinessRules());
    return result;
}

Here you see that we are passing lists of BrokenRuleData classes back to the consumer of the class, so that they don’t need access to the actual Rule objects themselves. These BrokenRuleData classes are basically DTOs (Data Transfer Objects) that return back the error messages and properties of the failing Rules. This class looks like this:

public class BrokenRuleData
{
    public string Message { get; private set; }
    public IEnumerable<string> Properties { get; private set; }

    public BrokenRuleData(string message, IEnumerable<string> properties)
    {
        Message = message;
        Properties = properties;
    }
}

Overall I like this approach, but there are a few problems. One problem is that a business object could be valid or not based on the specific context where the business object is being used. This problem could be addressed by having different rule lists based on a set list of contexts or aspects of the business object. We may address this problem in the future, but for now, we are going to address a different problem.

The problem that we are going to address here is the changing of business rules within an application. In any sufficiently large business application it is often necessary that the rules governing the validity of business objects can (and will) change. The need for non-technical people to be able to update these rules is also often required. I have seen a few systems in my day that revolve around giant tables of regex or template driven rules, but I really like the flexibility that the rule system we already defined is capable of. We are able to define any rule that we can fit into a boolean expression. This is very powerful, but how can we approach this power with a rule system that has to store its rules externally in an easily updated fashion? This is the problem that I set out this weekend to try and solve, and in the next installment of this series I will outline the approach that I took.

I hope you enjoyed this point, and be on the lookout for the next installment!

More Insights

View All