Specifications versus validators
Joe posed a great question on my recent entity validation post:
I question the term Validator in relation to DDD. Since the operation of the Validator seems to be a simple predicate based on business rule shouldn’t the term Specification [Evans Pg227] be used instead?
On the surface, it would seem that validation does similar actions as specifications, namely that it performs a set of boolean operations to determine if an object matches or not.
For those unfamiliar with the Specification pattern, it provides a succinct yet powerful mechanism to match an object against a simple rule. For example, let’s look at an expanded version of the original Order class on that post:
public class Order { public int Id { get; set; } public string Customer { get; set; } public decimal Total { get; set; } }
A Specification class is fairly simple, it only has one method that takes the entity as an argument:
public interface ISpecification<T> { bool IsSatisfiedBy(T entity); }
I can then create specific specifications based on user needs. Let’s say the business wants to find orders greater than a certain total, but the total can change. Here’s specification for that:
public class OrderTotalSpec : ISpecification<Order> { private readonly decimal _minTotal;<span class="kwrd">public</span> OrderTotalSpec(<span class="kwrd">decimal</span> minTotal) { _minTotal = minTotal; } <span class="kwrd">public</span> <span class="kwrd">bool</span> IsSatisfiedBy(Order entity) { <span class="kwrd">return</span> entity.Total >= _minTotal; }}
Specs by themselves aren’t that useful, but combined with the Composite pattern, their usefulness really shines:
public class AndSpec<T> : ISpecification<T> { private readonly List<ISpecification<T>> _augends = new List<ISpecification<T>>();<span class="kwrd">public</span> AndSpec(ISpecification<T> augend1, ISpecification<T> augend2) { _augends.Add(augend1); _augends.Add(augend2); } <span class="kwrd">public</span> AndSpec(IEnumerable<ISpecification<T>> augends) { _augends.AddRange(augends); } <span class="kwrd">public</span> <span class="kwrd">void</span> Add(T augend) { _augends.Add(augend); } <span class="kwrd">public</span> <span class="kwrd">bool</span> IsSatisfiedBy(T entity) { <span class="kwrd">bool</span> isSatisfied = <span class="kwrd">true</span>; <span class="kwrd">foreach</span> (var augend <span class="kwrd">in</span> _augends) { isSatisfied &= augend.IsSatisfiedBy(entity); } <span class="kwrd">return</span> isSatisfied; }}
Adding an “OrSpec” and a “NotSpec” allows me to compose some arbitrarily complex specifications, which would otherwise clutter up my repository if I had to make a single search method per combination:
OrderRepository repo = new OrderRepository(); var joesOrders = repo.FindBy( new AndSpec( new OrderTotalSpec(100.0m), new NameStartsWithSpec("Joe") ));
Given the Specification pattern (fleshed out into excruciating detail), why can’t I compose validation into a set of specifications? Let’s compare and contrast the two:
Specification
- Matches a single aspect on a single entity
- Performs positive matching (i.e., return true if it matches)
- Executed against a repository or a collection
- Can be composed into an arbitrarily complex search context, where a multitude of specifications compose one search context
-
“I’m looking for something”
-
-
Matches as many aspects as needed on a single entity
- Performs negative matching (i.e., returns false if it matches)
- Executed against a single entity
- Is intentionally not composable, a single validator object represents a single validation context
- “I’m validating this”
- Is intentionally not composable, a single validator object represents a single validation context
- Executed against a single entity
- Performs negative matching (i.e., returns false if it matches)
- Can be composed into an arbitrarily complex search context, where a multitude of specifications compose one search context
- Executed against a repository or a collection
- Performs positive matching (i.e., return true if it matches)
