Is Specification Pattern Pointless?
Asked Answered
T

4

15

I'm just wondering if Specification pattern is pointless, given following example:

Say you want to check if a Customer has enough balance in his/her account, you would create a specification something like:

new CustomerHasEnoughMoneyInTheirAccount().IsSatisfiedBy(customer)

However, what I'm wondering is I can achieve the same "benefits" of Specification pattern (such as only needing to change the business rules in on place) by using Property getter in the Customer class like this:

public class Customer
{

     public double Balance;

     public bool HasEnoughMoney
     {
          get { return this.Balance > 0; }
     }
}

From client code:

customer.HasEnoughMoney

So my question really is; what is the difference between using the property getter to wrap the business logic, and creating Specification class?

Thank you all in advance!

Torture answered 15/12, 2010 at 2:27 Comment(0)
E
10

Because with the specification class you can create new criterias without modification of the objects themselves.

Emmy answered 15/12, 2010 at 2:33 Comment(1)
objects? You mean class right? Isn't that the point of Object-Oriented to have high cohesion and tight coupling? If you have primary access to the Customer class, it should be a property. If it's linked to a code-first class, you can extend with a partial. In my experience the Specification Pattern is an Anti-Pattern.Universally
U
13

Yes, it is pointless.

The Wikipedia article criticises this pattern at length. But I see the biggest criticism being solely the Inner-Platform Effect. Why re-invent the AND operator? Please be sure to read the Wikipedia article for the complete picture.

Henry, you are correct to assume the Property Get is superior. Why eschew a simpler, well-understood OO concept, for an obscure "pattern" which in its conception doesn't answer your very question? It's an idea, but a bad one. It's an anti-pattern, a pattern that works against you, the coder.

You have asked what is the difference, but a more useful question is, when should a Specification Pattern be used?

Never use this pattern, is my general rule for this pattern.

First, you should realise this pattern isn't based on a scientific theory, it's only an arbitrary pattern someone imagined that uses a particular modeling of classes { Specification, AndSpecification, ...}. With the broader domain-driven theory in mind, you can abandon this pattern, and still have superior options that everyone is familiar with: for instance, well-named objects/methods/properties to model domain language and logic.

Jeffrey said:

a Specification object is just a predicate wrapped up in an object

That's true of domain-driven, but not the Specification Pattern specifically. Jeffrey, comprehensively describes a situation where one may want to dynamically build up an IQueryable expression, so it can efficiently execute on the data store (SQL Database). His final conclusion, is that you can't do that with the Specification Pattern as it's prescribed. Jeffrey's IQueryable expression trees are one alternative way to isolate logical rules and apply them in different composites. As you can see from his example code, it's verbose and very awkward to work with. I can't imagine any situation which would require such dynamic composites either. And if needed, there are many other techniques available which are simpler:-

We all know you should optimise performance last. Attempting here to achieve Bleeding edge with IQueryable expression trees, is a trap. Instead, start with the best tools, a simple and terse Property Getter first. Then test, evaluate and prioritise what work remains.

I am yet to experience a situation where this Specification Pattern is necessary/better. As I do come across supposed situations, I'll list them here and rebut them. If I come across a good situation, I'll revise this answer with a new section.

RE: zerkms answer

Because with the specification class you can create new criterias [sic] without modification of the objects themselves.

C# already caters for such situations:

  • Inheritance (in General), where you then extend the inherited class (this is good when you don't own the namespace/library from whence the class comes)
  • Method Overriding in Inheritence
  • Partial - great when you have data-model classes. You can add [NotStored] properties alongside, and enjoy all the bliss of accessing the information you need directly off the object. When you press '.' IntelliSense tells you what members are available.
  • Extension Methods are great when Inheritance is not practical ( architecture doesn't support it ), or if the parent class is sealed.

And these are globally taught ideas that most programmers will already naturally understand and use.

In projects I take over from, I do encounter anti-patterns like Specification Pattern, and more. They're often in a separate Project/Library (over-fragmentation of Projects is another terrible practice) and everyone is too scared to extend objects.

RE: Jeffery Hanton

see https://mcmap.net/q/762350/-is-specification-pattern-pointless [2023-01-23]

The use of Expression might be very suitable in many cases. I do still believe that simpler code will work just as well. There a chance it's a little messier, but I believe simplicity needs to come first. Don't confuse the new recruit, otherwise you lock the company needing to hire experts, which are normally in short supply for scaling.

This is his Specification Pattern example:

var spec = new All(new CustomerHasFunds(500.00m), new CustomerAccountAgeAtLeast(TimeSpan.FromDays(180)), new CustomerLocatedInState("NY"));

With plain code, it becomes

result = (CustomerSpec.HasFunds(500.0m) && CustomerSpec.AccountAgeAtLeast(TimeSpan.FromDays(180)) && CustomerSpec.LocatedInState);

If you ever need complexities, like multiple && and some () isolated ||. Then that's what you learn in Computer Science 101. It's also the same across all programming languages (except for syntax).

Universally answered 30/9, 2016 at 7:6 Comment(0)
P
11

In the general sense, a Specification object is just a predicate wrapped up in an object. If a predicate is very commonly used with a class, it might make sense to Move Method the predicate into the class it applies to.

This pattern really comes into its own when you're building up something more complicated like this:

var spec = new All(new CustomerHasFunds(500.00m),
                   new CustomerAccountAgeAtLeast(TimeSpan.FromDays(180)),
                   new CustomerLocatedInState("NY"));

and passing it around or serializing it; it can make even more sense when you're providing some sort of "specification builder" UI.

That said, C# provides more idiomatic ways to express these sorts of things, such as extension methods and LINQ:

var cutoffDate = DateTime.UtcNow - TimeSpan.FromDays(180); // captured
Expression<Func<Customer, bool>> filter =
    cust => (cust.AvailableFunds >= 500.00m &&
             cust.AccountOpenDateTime >= cutoffDate &&
             cust.Address.State == "NY");

I've been playing around with some experimental code that implements Specifications in terms of Expressions, with very simple static builder methods.

public partial class Customer
{
    public static partial class Specification
    {
        public static Expression<Func<Customer, bool>> HasFunds(decimal amount)
        {
            return c => c.AvailableFunds >= amount;
        }

        public static Expression<Func<Customer, bool>> AccountAgedAtLeast(TimeSpan age)
        {
            return c => c.AccountOpenDateTime <= DateTime.UtcNow - age;
        }


        public static Expression<Func<Customer, bool>> LocatedInState(string state)
        {
            return c => c.Address.State == state;
        }
    }
}

That said, this is a whole load of boilerplate that doesn't add value! These Expressions only look at public properties, so one could just as easily use a plain old lambda! Now, if one of these Specifications needs to access non-public state, we really do need a builder method with access to non-public state. I'll use lastCreditScore as an example here.

public partial class Customer
{
    private int lastCreditScore;

    public static partial class Specification
    { 
        public static Expression<Func<Customer, bool>> LastCreditScoreAtLeast(int score)
        {
            return c => c.lastCreditScore >= score;
        }
    }
}

We also need a way to make a composite of these Specifications - in this case, a composite that requires all children to be true:

public static partial class Specification
{
    public static Expression<Func<T, bool>> All<T>(params Expression<Func<T, bool>>[] tail)
    {
        if (tail == null || tail.Length == 0) return _0 => true;
        var param = Expression.Parameter(typeof(T), "_0");
        var body = tail.Reverse()
            .Skip(1)
            .Aggregate((Expression)Expression.Invoke(tail.Last(), param),
                       (current, item) =>
                           Expression.AndAlso(Expression.Invoke(item, param),
                                              current));

        return Expression.Lambda<Func<T, bool>>(body, param);
    }
}

I guess part of the downside to this is it can result in complicated Expression trees. For example, constructing this:

 var spec = Specification.All(Customer.Specification.HasFunds(500.00m),
                              Customer.Specification.AccountAgedAtLeast(TimeSpan.FromDays(180)),
                              Customer.Specification.LocatedInState("NY"),
                              Customer.Specification.LastCreditScoreAtLeast(667));

produces an Expression tree that looks like this. (These are slightly formatted versions of what ToString() returns when called on the Expression - note that you wouldn't be able to see the structure of the expression at all if you had only a simple delegate! A couple of notes: a DisplayClass is a compiler-generated class that holds local variables captured in a closure, to deal with the upwards funarg problem; and the dumped Expression uses a single = sign to represent equality comparison, rather than C#'s typical ==.)

_0 => (Invoke(c => (c.AvailableFunds >= value(ExpressionExperiment.Customer+Specification+<>c__DisplayClass0).amount),_0)
       && (Invoke(c => (c.AccountOpenDateTime <= (DateTime.UtcNow - value(ExpressionExperiment.Customer+Specification+<>c__DisplayClass2).age)),_0) 
           && (Invoke(c => (c.Address.State = value(ExpressionExperiment.Customer+Specification+<>c__DisplayClass4).state),_0)
               && Invoke(c => (c.lastCreditScore >= value(ExpressionExperiment.Customer+Specification+<>c__DisplayClass6).score),_0))))

Messy! Lots of invocation of immediate lambdas and retained references to the closures created in the builder methods. By substituting closure references with their captured values and β-reducing the nested lambdas (I also α-converted all parameter names to unique generated symbols as an intermediate step to simplify β-reduction), a much simpler Expression tree results:

_0 => ((_0.AvailableFunds >= 500.00)
       && ((_0.AccountOpenDateTime <= (DateTime.UtcNow - 180.00:00:00))
           && ((_0.Address.State = "NY")
               && (_0.lastCreditScore >= 667))))

These Expression trees can then be further combined, compiled into delegates, pretty-printed, edited, passed to LINQ interfaces that understand Expression trees (such as those provided by EF), or what have you.

On a side note, I built a silly little micro-benchmark and actually discovered that closure reference elimination had a remarkable performance impact on the speed of evaluation of the example Expression when compiled to a delegate - it cut the evaluation time nearly in half(!), from 134.1ns to 70.5ns per call on the machine I happen to be sitting in front of. On the other hand, β-reduction made no detectable difference, perhaps because compilation does that anyway. In any case, I doubt a conventional Specification class set could reach that kind of evaluation speed for a composite of four conditions; if such a conventional class set had to be built for other reasons such as the convenience of builder-UI code, I think it would be advisable to have the class set produce an Expression rather than directly evaluate, but first consider whether you need the pattern at all in C# - I've seen way too much Specification-overdosed code.

Praise answered 15/12, 2010 at 2:42 Comment(9)
From what you say, I'd say you can get the benefits of both approaches by creating extension methods for the Customer class that uses the specification classTetrapody
@Tetrapody Indeed. If you do that, though, I think the Expression loses some of its power -- if it only contains a MethodInfo naming the extension method rather than the actual condition, it can't be passed through an underlying IQueryable provider to perform remote-side filtering or index optimization.Praise
In which cases would one need to serialize such a specification? Why beat around the bush? var spec = Customer.HasFunds && Customer.AccountAgedAtLeast(TimeSpan.FromDays(180)) && Customer.LocatedInState("NY") If you need to serialize that, why not just serialize the parameters?Universally
@Todd, a typical ORM implementation of IQueryable is a dynamic SQL factory. Given an Expression free of method references (as in my answer) most are capable of translating the Expression into WHERE clause elements. On the other hand, mentioning any domain methods by name will typically result in those being omitted from WHERE and filtered client side because the method implementation is not part of the resulting Expression tree - only a MethodCallExpression node containing a MethodInfo describing the function to be called.Praise
@JeffreyHantin You are correct for ORM, but that wasn't mentioned by the OP. The Specification Pattern (which is the topic) is not designed for use with ORM. Having said that still can use Functions and Properties on an EF model class, you just need to do that on the following IEnumerable set, or in an iterator. var dbAsUsual = (from c in customers {filtering, grouping, ordering, select projection}); then var finalSet = (from c in dbAsUsual.AsEnumerable() where c.CustomerHasFunds && c.AccountAgeAtLeast(TimeSpan.FromDays(180)) && c.LocatedInState("NY"));Universally
@Todd, build the Specification pattern using factory methods returning Expression<Func<T, bool>>. This thins out the number of tiny Specification classes one must declare by hand, allows one to seamlessly throw in the occasional one-off lambda among predefined Specification constructions, doesn't break IQueryable push-through optimization, incorporates a Visitor pattern for analyzing its contents ... maybe I need to extend this answer to explain better.Praise
@JeffreyHantin Yes, I think some tweaks would help. CustomerHasFunds is a class typically in the Specification Pattern. I recommend CustomerHasFunds as a Property (and ignore the Specification Pattern). You don't have any cohesive CustomerHasFunds concept in your alternative, but it is possible. I will add it to your answer - feel free to remove/keep/edit.Universally
@Todd I'll probably have to edit - the key is maintaining the type of the specification as Expression<Func<T,bool>> without allowing it to decay to Func<T,bool>.Praise
@Todd I got to playing around with this approach. It's crazy fast in memory if you do some clean-up of the expression trees - I used Visitors to clean them up, but the actual code to do that clean-up is sort of beyond the scope of the answer, and this answer is already exceptionally long ...Praise
E
10

Because with the specification class you can create new criterias without modification of the objects themselves.

Emmy answered 15/12, 2010 at 2:33 Comment(1)
objects? You mean class right? Isn't that the point of Object-Oriented to have high cohesion and tight coupling? If you have primary access to the Customer class, it should be a property. If it's linked to a code-first class, you can extend with a partial. In my experience the Specification Pattern is an Anti-Pattern.Universally
M
3

See zerkms answer, plus: a specification can also work on abstract types like interfaces or as a generic making it applicable to a whole range of objects.

Or the check that needs to be done on customer might depend on the context. For example a customer object might not be valid for the pay role system yet, but valid for saving it in the database in the middle of a process for further processing when the user logs in again. With specifications you can build groups of related checks in a centralised location and switch out the entire set depending on context. In this situation you'd combine it with a factory pattern for example.

Macfadyn answered 15/12, 2010 at 2:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.