Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
DDD: The Specification Pattern

Continuing our series on Domain Driven Design, we now get to one of the more interesting patterns in DDD – the Specification.

A Specification is, in simple terms, a small piece of logic that sits on it’s own and gives an answer to a simple question … “does this match?”

With a Specification we split the logic of how a selection is made, away from the thing we are selecting.

We have a Customer, and we want to be able check if they are eligible for a discount on a Product.

If we were to put a method on the Customer entity, for example .IsEntitledToDiscountPrice(Product) we start to couple our entities tightly together, and as the number of questions we want to ask of our entity increases, the more polluted its interface becomes.

To avoid this we can use a Specification.

Some Code – A First for the Series

The basic implementation of Specification has a single method .IsSatisifiedBy, in our Discount example above we may have a EligibleForDiscountSpecification, the method would be .IsSatisifiedBy(Customer c)

The actual Specification is variable in how it is defined, but a very simple version for this scenario would be:

public interface ISpecification<T>
{
    bool IsSatisfiedBy(T sut);
}

public class EligibleForDiscountSpecification : ISpecification<Customer>
{
    private readonly Product _product;
    public EligibleForDiscountSpecification(Product product)
    {
        _product = product;
    }

    public bool IsSatisfiedBy(Customer customer)
    {
        return (_product.Price < 100 && customer.CreditRating >= _product.MinimumCreditRating);
    }
}

This now simplifies selection or matching, and the Customer and Product are no longer coupled – our Specification now knows how to decide if the Customer is eligible for a discount. Ignoring the fact that the following is a rotten unit test, we can use our Specification like this:

[Fact]
public void TestSpecification()
{
    var product = new Product() { MinimumCreditRating = 3, Price = 50 };
    var spec = new EligibleForDiscountSpecification(product);
    var goodCustomer = new Customer() { CreditRating = 3 };
    var badCustomer = new Customer() { CreditRating = 1 };

    Assert.True(spec.IsSatisfiedBy(goodCustomer));
    Assert.False(spec.IsSatisfiedBy(badCustomer));
}

Two things become very easy when using Specification – we can easily select from lists and we can pass dependencies without creating coupling.

To find all the Customers in a List<Customer> who are eligible for a discount, we can do (again ignoring the terrible unit test:

[Fact]
public void TestSpecificationCollection()
{
    var minCredit = 3;
    var product = new Product() { MinimumCreditRating = minCredit, Price = 50 };
    var spec = new EligibleForDiscountSpecification(product);

    var customers = new List<Customer>()
                        {
                            new Customer() {CreditRating = minCredit-2}, // bad credit
                            new Customer() {CreditRating = minCredit-1}, // bad credit
                            new Customer() {CreditRating = minCredit} // good credit
                        };
    IEnumerable<Customer> eligible = GetAllCustomersMatching(customers, spec);
    int count = 0;
    foreach (var eligibleCustomer in eligible)
    {
        Assert.True(eligibleCustomer.CreditRating >= minCredit);
        count++;
    }
    Assert.Equal(1, count);
}

public IEnumerable<Customer> GetAllCustomersMatching(IList<Customer> customers, 
ISpecification<Customer> specification) { foreach (var customer in customers) { if (specification.IsSatisfiedBy(customer)) yield return customer; } }

Removing the Dependencies

A scenario I had a while back required an Entity to only allow a method to proceed if a search against a Repository return no matches already there. This specific example turns out to be quite common, people seem to need access to Domain Services or Repositories on a frequent basis.

My first question would be, is the Entity doing too much? Is this an operation that should be in a Domain Service or perhaps a Specification?

Assuming you can legitimately answer “no” to that last question – let us assume that we want to have a Product with a ProductCode – but the ProductCode cannot be duplicated. Leaving aside the fact that this is a rather fake scenario, it means our Product now needs access to the ProductRepository, which is a bit back to front.

What Options Do We Have?

Generally in this scenario we have a few options:

  1. The Entity could call the Repository<Product>.GetByProductCode
  2. The Entity could call a Domain Service to check that it is a unique code
  3. A domain service could hold all the logic and coordinate the Entity  with the Repository.

Option (1) is not a good design – an Entity should not be aware of Repositories. It would probably require a Service Locator pattern to achieve, but becomes very messy very quickly. It could possibly be resolved with Double Dispatch, but is still a bit back to front (see 2 below).

Option (2) is a bit back to front – Entities logically sit behind Domain Services. This could work, as alluded to in a comment to a previous blog post on Domain Services, and if so will require Double Dispatch to be clean.

Option (3) is probably the best of all those options. Domain Services sit in front of Repositories, Entities, and other Domain Services.

The last option not on that list is to use Specification.

If we created a NoOtherMatchingProductCodeSpecification, we can cleanly use this to do the work.

public class NoMatchingProductCodeSpecification : ISpecification<Product>
{
    private readonly IRepository<Product> _repository;
    public NoMatchingProductCodeSpecification(IRepository<Product> repository)
    {
        _repository = repository;
    }

    public bool IsSatisfiedBy(Product product)
    {
        Product match = _repository.GetProductByProductCode(product.ProductCode);
        return match == null;
    }
}

Please bear in mind, this is a contrived scenario, I know this specific example has issues around ACID etc … it is here to prove a point, and Kyle Baley made me write this in a hurry!!!!

What Is Double Dispatch?

So far I have mentioned it more than a few times, and even used it in the title of this blog – so it must be important. You have probably used Double Dispatch many times, even if you didn’t know it had become a pattern with a proper name.

In simple terms, Double Dispatch means we pas in an object to a function, to let the function take an action or make a decision, based on the logic of the passed in object. This decouples our Entities from the actions they take.

Chaining Specifications

It also happens, another useful side effect of Specification is that they can be chained very easily, but I will leave that till a future post. A starting point if you are interested now is on Wikipedia

In Conclusion

I seem to have written more code in this post than I intended, and more than has been the style for the rest of the series. I again intend to blame Kyle for that :) Hopefully it has however given you a more concrete idea of where and how the Specification pattern can be of use.


Posted 03-02-2009 3:57 PM by Jak Charlton

[Advertisement]

Comments

Joel Holder wrote re: DDD: The Specification Pattern
on 03-02-2009 11:51 AM

This pattern looks a lot like DesignByContract (en.wikipedia.org/.../Design_by_contract).  It adds Ensure and Verify concepts to strengthen  the validity runtime operations.  The Spec can be enforced accordingly.

on 03-02-2009 12:06 PM

We got clobbered with over a foot of snow. ALT.NET There is some great coverage of ALT.NET Seattle 2009: Phil Haack : ALT.NET Seattle Day One ALT.NET Seattle Day Two ALT.NET Seattle Day Three Glenn Block Scott Hanselman - Experiencing ALT.NET Seattle

DotNetShoutout wrote DDD: The Specification Pattern - Casey Charlton - Insane World
on 03-02-2009 3:27 PM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Kyle Baley wrote re: DDD: The Specification Pattern
on 03-02-2009 5:11 PM

Whaddaya know, perfect timing! Thanks for clearing this up. And nice to know you will post on demand when required.

Bil Simser wrote re: DDD: The Specification Pattern
on 03-02-2009 5:29 PM

This is a great post to get introduced to the pattern. I wrote up a few blog entries on specification last year in response to turning a series of if statements from hell into something manageable. A few more resources:

Refactoring away crazy if statements:

weblogs.asp.net/.../refactoring-dumb-dumber-dumbest-away.aspx

JP Boodhoo on specification:

codebetter.com/.../bdd-specification-base-class.aspx

JP on refactoring to reveal intent:

codebetter.com/.../refactoring-to-reveal-intent.aspx

Matthew Podwysocki wrote re: DDD: The Specification Pattern
on 03-02-2009 5:47 PM

Instead, we could rewrite your test to use LINQ and a more functional style to get your code to read easier such as this:

[Fact]

public void TestSpecificationCollection()

{

   var minCredit = 3;

   var product = new Product() { MinimumCreditRating = minCredit, Price = 50 };

   var spec = new EligibleForDiscountSpecification(product);

   var customers = new List<Customer>()

                       {

                           new Customer() {CreditRating = minCredit-2}, // bad credit

                           new Customer() {CreditRating = minCredit-1}, // bad credit

                           new Customer() {CreditRating = minCredit} // good credit

                       };

   var eligible = from customer in customers

                  where spec.IsSatisfiedBy(customer)

                  select customer;

   Assert.True(eligible.All(c => c.CreditRating >= minCredit));

   Assert.Equal(1, eligible.Count());

}

Make sense?

Matt

Jak Charlton wrote re: DDD: The Specification Pattern
on 03-03-2009 2:23 AM

Indeed it does Matt ... much cleaner .. was going to cover a bit of something like that later on

Out of interest ... anyone know if Matt's Linq statement will work against Linq toSQL or Linq to NH???  

Reflective Perspective - Chris Alcock » The Morning Brew #298 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #298
on 03-03-2009 3:37 AM

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #298

Specs and the Repository wrote re: DDD: The Specification Pattern
on 03-03-2009 10:44 AM

Casey,

Nick Blumhardt, creator of the IoC container Autofac, has written an excellent article on how we might use LINQ to make the specification pattern and repository pattern work together:

ubik.com.au/.../implementing_the_specification_pattern_with_linq

Jak Charlton wrote re: DDD: The Specification Pattern
on 03-03-2009 11:57 AM

Very nice link Chris ... Tuna is going to have a hit at NH version too

Nicholas Blumhardt wrote re: DDD: The Specification Pattern
on 03-03-2009 12:44 PM

Jonathan beat me to the Linq/Specifications link :)

There's a project on Google Code run by Steve Burman that implements a Linq-based Specifications framework. This one came out of a real-world project so it is probably an interesting place to start exploring:

www.mostlyclean.com/.../Linq-Specifications-The-Project.aspx

Jak Charlton wrote re: DDD: The Specification Pattern
on 03-03-2009 4:29 PM

Nicholas/Jonathon

Excellent links ... thanks a lot ...

redgreenrefactor wrote re: DDD: The Specification Pattern
on 03-04-2009 3:56 PM

For another nice example of the double dispatch:

junit.sourceforge.net/.../testing.htm

Specification Pattern and LINQ to NHibernate « Andy Hitchman’s Blog wrote Specification Pattern and LINQ to NHibernate &laquo; Andy Hitchman&#8217;s Blog
on 03-13-2009 6:56 AM

Pingback from  Specification Pattern and LINQ to NHibernate &laquo; Andy Hitchman&#8217;s Blog

T-Man tipser om Specification pattern wrote T-Man tipser om Specification pattern
on 03-20-2009 9:34 AM

Pingback from  T-Man tipser om Specification pattern

Tim Bond wrote re: DDD: The Specification Pattern
on 03-23-2009 2:40 PM

This solution treats customers and products asymmetrically.  What if i want to find all products that a customer would get a discount for.  I would have to instantiate a new object for each product and then test against the single customer.  Can specifications take two parameters?

Jak Charlton wrote re: DDD: The Specification Pattern
on 03-23-2009 3:01 PM

@Tim

Any number you like ... the point is the dependencies are setup in isolation from the thing that asks if there is a match ...

But in your example it is more likely it is a Specification<Product> that takes a Customer in the constructor ... then it is a simple select against the Product .IsSatisfiedBy

DotNetKicks.com wrote The Specification Pattern
on 09-02-2009 2:34 PM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Anonymous wrote re: DDD: The Specification Pattern
on 01-30-2010 8:58 AM

Why are the first 2 unit tests "rotten"?

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)