fuzzelogic Solutions

February 16, 2010

Specification pattern revisited

Filed under: BDD, OO, Programming, c#, design — Tags: , — admin @ 7:09 pm

Hi!

I’ve spoken about the specification pattern before. The first thing to note is that article is on the older 1.1 stuff, so no generics.  However,in c# 3.5, we can crunch the specification pattern considerably. Here’s one idea..
First off the interface :-) [ Here's the code ]  = [ignore this 8JKPNVRYP3CT ]

public interface Ispecification<T>{
        bool is_satisfied_by(T this_item);
    }

Next the implemenation. Its not too different from the original

public class specification<T>: Ispecification<T>{
        private readonly Predicate<T> specification_predicate_test;

        public specification(Predicate<T>specification_predicate_test){
            this.specification_predicate_test = specification_predicate_test;
        }

        public bool is_satisfied_by(T this_item){
            return specification_predicate_test(this_item);
        }
    }

First off.. attach the interface. Then in the constructor give it the Predicate<T> (that’s the built in dot net predicate). In the “is_satisfied_by” method pass the item to the stored predicate and let it do the job.
That’s the specification done. Now to attend to the composite part.. the AND, OR combiniations…
Well, again, built in dot net to the rescue - extension methods..

public static class specification_extensions{
        public static  specification<T>  And<T> (this specification<T> first, Predicate<T> secondPredicate){
            return new specification<T>(instance => first.is_satisfied_by(instance) &amp;&amp; new specification<T>(secondPredicate).is_satisfied_by(instance));
        }
        public static specification<T> OR<T>(this specification<T> first, Predicate<T> secondPredicate){
            return new specification<T>(instance => first.is_satisfied_by(instance) || new specification<T>(secondPredicate).is_satisfied_by(instance));
        }
        public static specification<T> Negate<T>(this specification<T> first){
            return new specification<T>(instance => !first.is_satisfied_by(instance) );
        }
    }

Thats ok.. so how do we use it.. well. First define what specification. (our sample usage is bad invoices - pretty original :-) )

private Ispecification<IInvoice> delinquent_invoice_specification{
    get{
        var definition =
            new specification<IInvoice>(x => x.due_date.CompareTo(DateTime.Now) > 0)
                                    .And(x => x.total_amount > 1000)
                                    .And(x => x.months_over_due > 3)
                                    .OR(x => x.has_had_last_chance);
        return definition;
    }
}

And the sample usage. We have a bunch of invoices that we want to check..

public void sample_usage(){

    var all_invoices_in_our_company = new List<IInvoice>();

    all_invoices_in_our_company.Add(a_bad_invoice);
    all_invoices_in_our_company.Add(a_bad_invoice);
    all_invoices_in_our_company.Add(a_good_invoice);
    all_invoices_in_our_company.Add(a_good_invoice);
    all_invoices_in_our_company.Add(a_good_invoice);
    all_invoices_in_our_company.Add(a_good_invoice);
    all_invoices_in_our_company.Add(a_bad_invoice);

    foreach (var invoice in all_invoices_in_our_company){
        if (delinquent_invoice_specification.is_satisfied_by(invoice))
            send(invoice).to_legal_department();
    }

}

private IInvoice a_bad_invoice { get { return new Invoice(DateTime.Now.AddMonths(-10), 5000, 8, true); } }
private IInvoice a_good_invoice { get { return new Invoice(DateTime.Now.AddMonths(1), 1205, 0, false); } }

And there we have it.. crunched composite specification. [ Here's the code ]
Hope that helps
Zak

May 2, 2009

BDD : a change in thinking

Filed under: BDD, OO, design — Tags: , , , — admin @ 5:47 pm

For everyone doing TDD (test first … test driven design) bdd is not going to sound like a lot of new stuff. BDD, at its core represents a change in thinking. It drives us down the path of writing out “specifications” so that its readable to everyone involoved in the software project. It steers developers into thinking about the behaviour in a given context, and what the “user experience” is going to be like.

It brings programmers close to the business…. that’s important enough to say it again. it brings programmers close to the business.

Additionally, BDD trys to get the words changed so that we stop communicating in terms of testing. We start talking about the behaviour of a system. Its worth mentioning, there’s a couple flavours in the BDD world. The Dan North “Given , When , Then” and then there’s Scott Bellware’s “Context specification” and of course mine (pretty much context specification based on sceanrios - each scenario is an If).

Using an example of a Login specification, let check each one.

Dans style : Given incorrect credentials when the user logs in then the user should be shown a failed to login message.

Scotts’s style: When the user logs in in [in the context of having incorrect details] then the user should be shown a failed login message

Mine: If the login credentials are incorrect when the user logs in, then the user should be shown a failed login message.

How this actually looks in code depends on the underlying framework used. For me, I’ve written up my own basic one, which relys on a few simple classes (I’ll post them at a later date)

// This is quick look at the layout of the test.
// The implemenation is left out for simplicity

public class Login_Specification
{
     [Story]
public abstract class when_the_user_logs_in: Story_for<ILoginController>  {}
// This is a scenario
public class if_the_credentials_supplied_are_incorrect : when_the_user_logs_in{}
// This is another scenario
public class if_the_credentials_supplied_are_correct :when_the_user_logs_in{}
}

April 16, 2009

Open closed principle

Filed under: OO, design — Tags: , , , — admin @ 5:17 pm

O.C.P : Open closed principle….
       an object is open for extension but closed for modification.

So to understand what this means, lets consider the following scenario - (There’s a bunch of code).

We have a product entity, and we can get lists of these back from our repository.
The Requirement for Today: we’re asked to create a filtered list of products that match a certain color, so we create the following product filter class, who’s job it is to filter the list.
     

public class ProductFilter{
               public IEnumberable<IProduct> GetItemsMatchingTheColor( IEnumerable<IProduct> fullList, Color color) {
                   foreach ( var item in fullList )
                       if ( item.ItsColor == color);
                            yield return item;
               }
           }

That’s fine, and it gets us what we want… but as we know, change is always around the corner….

Requirement a little in the future: we’re asked to get list filtered by Product size.

      
           public class ProductFilter{
              public IEnumberable<IProduct> GetItemsMatchingTheColor( IEnumerable<IProduct> fullList, Color color) {
                   foreach ( var item in fullList )
                       if ( item.ItsColor == color);
                            yield return item;
               }
               // Added this new method…
               public IEnumberable<IProduct> GetItemsMatchingSomeSize( IEnumerable<IProduct> fullList, ProductSize size) {
                   foreach ( var item in fullList )
                       if ( item.Size == size);
                            yield return item;
               }
           }

so what did we do here??? well we cracked open the filter object added the new behavior and rebuilt it.

Requirement a little further in the future: we’re asked to get list filtered by Product size AND Color.

public class ProductFilter{
public IEnumberable<IProduct> GetItemsMatchingTheColor( IEnumerable<IProduct> fullList, Color color) {
                   foreach ( var item in fullList )
                       if ( item.ItsColor == color);
                            yield return item;
               }

public IEnumberable<IProduct> GetItemsMatchingSomeSize( IEnumerable<IProduct> fullList, ProductSize size) {
                   foreach ( var item in fullList )
                       if ( item.Size == size);
                            yield return item;
               }
               // Added this new method…
               public IEnumberable<IProduct> GetItemsMatchingSomeSize( IEnumerable<IProduct> fullList, ProductSize size, Color color) {
                   foreach ( var item in fullList )
                       if ( item.Size == size &amp;&amp; item.ItsColor==color);
                            yield return item;
               }
           }

so what did we do here??? well AGAIN we cracked open the filter object added the new behavior and rebuilt it. Although we managed to extend the behavior of the object we violated the OCP. What are the benefits of OCP? Well by following the principle we have 2 benefits:
               1. Objects are extensible which will satisfiy changing requirements
               2. Objects are maintainable and stable, because they didn’t change, there’s less chance of introducing bugs.

So how do we do this, how do extend something without cracking it open?(one way)….

If if we consider a few design principles… encapsulate what varies: in this case the filter specification. (I’ll also sneek in the specification pattern here)

    /// <summary>
    /// Interface to be implemented by objects that act as specifications
    /// </summary>
    /// <typeparam name=”T”></typeparam>
    public interface ISpecification<T>
    {
        bool IsSatisfiedBy(T item);
    }

    /// <summary>
    /// Interface to be implemented by objects that support filtering
    /// </summary>
    /// <typeparam name=”TypeToFilter”></typeparam>
    public interface IFilter<TypeToFilter>
    {
        IEnumerable<TypeToFilter> Filter(IEnumerable<TypeToFilter> completelist, ISpecification<TypeToFilter> specification);
    }

// For completeness of the sample….

    /// <summary>
    /// The Product interface.
    /// </summary>
    public interface IProduct
    {
        string Name { get; set; }
        Color ItsColor { get; set; }
        ProductSize Size { get; set; }
    }

    /// <summary>
    /// Enum defining the sizes
    /// </summary>
    public enum ProductSize
    {
        Small, Medium, Large, ReallyBig
    }

Now the refactored Filter object.

    /// <summary>
    /// The Filter class
    /// </summary>
    public class ProductFilter : IFilter<IProduct>
    {   �
        public IEnumerable<IProduct> Filter(IEnumerable<IProduct> completelist, ISpecification<IProduct> specification)
        {
             foreach (var product in completelist )
                 if ( specification.IsSatisfiedBy ( product ))
                     yield return product;
        }
    }

Now we have a Product filter object that accepts a complete list of products and specification that we can filter on. All we need to do now is provide the filtering specifications.

    #region -[ Specifications ]-

    /// <summary>
    /// Individual specification for a color filter
    /// </summary>
    public class ColorFilterSpecification : ISpecification<IProduct>
    {
        Color colorToMatch;

        public ColorFilterSpecification(Color colorToMatch)
        {
            this.colorToMatch = colorToMatch;
        }
        public bool IsSatisfiedBy(IProduct item)
        {
            return item.ItsColor == colorToMatch;
        }
    }
    /// <summary>
    /// Individual specification for a Size filter
    /// </summary>
    public class SizeFilterSpecification : ISpecification<IProduct>
    {
        ProductSize sizeToMatch;
        public SizeFilterSpecification(ProductSize sizeToMatch)
        {
            this.sizeToMatch = sizeToMatch;
        }
        public bool IsSatisfiedBy(IProduct item)
        {
            return item.Size == sizeToMatch;
        }

    }

    /// <summary>
    /// Without exploding this into a full blow specification pattern
    /// where you can “chain” specifications together in .. AND, OR..etc
    /// a very basic “And” specification
    /// </summary>
    public class AndSpecification<T> : ISpecification<T>
    {
        ISpecification<T> first;
        ISpecification<T> second;

        public AndSpecification(ISpecification<T> first, ISpecification<T> second)
        {
            this.first = first;
            this.second = second;
        }
        public bool IsSatisfiedBy(T item)
        {
            return ( first.IsSatisfiedBy(item) &amp;&amp; second.IsSatisfiedBy(item));
        }
    }

    /// <summary>
    /// Without exploding this into a full blow specification pattern
    /// where you can “chain” specifications together in .. AND, OR..etc
    /// a very basic “OR” specification
    /// </summary>
    public class ORSpecification<T> : ISpecification<T>
    {
        ISpecification<T> first;
        ISpecification<T> second;

        public ORSpecification(ISpecification<T> first, ISpecification<T> second)
        {
            this.first = first;
            this.second = second;
        }
        public bool IsSatisfiedBy(T item)
        {
            return (first.IsSatisfiedBy(item) || second.IsSatisfiedBy(item));
        }
    }

    #endregion

And to test all this actually works, here’s a very basic set of tests using MSTest built into the Visual studio

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
//using Reference to where your code lives.
using System.Drawing;

namespace _Tests_For_OOConcepts
{
    /// <summary>
    /// Summary description for FilterTests
    /// </summary>
    [TestClass]
    public class FilterTests
    {

        IEnumerable<IProduct> complete_list;
        IEnumerable<IProduct> results;
        IFilter<IProduct> System_under_test;
            �
        [TestInitialize]
        public void startup()
        {
            complete_list = Fake_list_of_products();
            System_under_test = new ProductFilter();
        }

        [TestMethod]
        public void List_only_contains_items_of_a_specified_COLOR()
        {
            results = Action_the_system_under_test_with(new ColorFilterSpecification(Color.Orange));

            foreach (var item in results)
                Assert.IsTrue(item.ItsColor == Color.Orange);
        }
    �
        [TestMethod]
        public void List_only_contains_items_of_a_specified_SIZE()
        {
            results = Action_the_system_under_test_with( new SizeFilterSpecification(ProductSize.Small) );
            foreach (var item in results)
                Assert.IsTrue(item.Size == ProductSize.Small);
        }
    �
        [TestMethod]
        public void List_only_contains_items_of_a_specified_SIZE_AND_COLOR()
        {
            var the_matching_criteria = new AndSpecification<IProduct>(new ColorFilterSpecification(Color.AliceBlue),
                                                                        new SizeFilterSpecification(ProductSize.Small));
                   �
            results = Action_the_system_under_test_with(the_matching_criteria);
            foreach (var item in results)
            {
                Assert.IsTrue(item.Size == ProductSize.Small);
                Assert.IsTrue(item.ItsColor == Color.AliceBlue);
            }
        }

        public IEnumerable<IProduct> Action_the_system_under_test_with(ISpecification<IProduct> the_filter_specification_to_use)
        {
            return System_under_test.Filter(complete_list, the_filter_specification_to_use);
        }
        public IEnumerable<IProduct> Fake_list_of_products()
        {

            yield return new FakeProduct(”apple”, Color.Red, ProductSize.Large);
            yield return new FakeProduct(”apple2″, Color.Red, ProductSize.Medium);
            yield return new FakeProduct(”orange”, Color.Orange, ProductSize.Medium);
            yield return new FakeProduct(”orange2″, Color.Orange, ProductSize.Large);
            yield return new FakeProduct(”bananna”, Color.Yellow, ProductSize.Small);
            yield return new FakeProduct(”bananna2″, Color.Yellow, ProductSize.ReallyBig);
            yield return new FakeProduct(”stuffed bear”, Color.AliceBlue, ProductSize.ReallyBig);
            yield return new FakeProduct(”stuffed bear2″, Color.Orange, ProductSize.Small);
        }

    }

    public class FakeProduct : IProduct
    {

        public FakeProduct(string name, Color theColor, ProductSize itsSize)
        {
            this.Name = name;
            this.ItsColor = theColor;
            this.Size = itsSize;
        }
    �
        public string Name {get;set;}
        public Color ItsColor {get;set;}
        public ProductSize Size { get; set; }
    }

}

So now we can vary the filter specification, add new specifications and extend the filtering object without actually modifying the source code of the Filter object.

Hope this helps
Zak

Powered by WordPress