fuzzelogic Solutions

February 14, 2010

Rules everywhere

Filed under: OO, Programming, c#, design — Tags: , , , — admin @ 5:55 pm

Hi!

During the last Dev group meeting, we’ve had a brief discussion about rules. Often the business rules are duplicated and in a layered application, are across multiple layers.
Here’s a simple implementation that will allow you to validate at either the domain layer or externalized. This will allow us to validate a set of rules against a domain object.

First off : Here’s the interface

 public interface IRule<T>{
        bool is_broken_by(T item);
        string error_message { get; }
    }
 

This will allow us to validate an item against a requirement, and get back a message. Simple enough.
Here’s a simlpe implementation of the IRule interface.

 public class BreakableRule :  IRule<T>{
        protected readonly Predicate<T> predicate;
        protected readonly string broken_rule_message;

        public BreakableRule(Predicate<T> predicate, string broken_rule_message ){
            this.predicate = predicate;
            this.broken_rule_message = broken_rule_message;
        }

        public bool is_broken_by(T item){
            error_message = string.Empty;
            var is_broken = predicate.Invoke(item);
            if ( is_broken ) error_message = broken_rule_message;
            return is_broken;
        }

        public string error_message { get; protected set; }
    }
 

Next of we create a ruleset. This will be where we collect the rules and iterate through them to validate against the domain. This will give us an emuerable list of error messages.

public interface IRuleset<T> {
        IEnumerable<string> validate(T item);
        bool is_valid();        
    }
 

I’ve implemented this as an abstract class that will be used as a base class for the ruleset implementation

 public abstract class rule_set <T> : IRuleset <T> {
        protected IList <IRule<T> > all_rules;
        protected Report report;
        protected bool isBroken;
        protected rule_set() : this(new  List <IRule<T> > ()) {}

        protected rule_set(  IList <IRule<T> >  allRules){
            all_rules = allRules;
            configure_rules();
        }
        protected void add_a_rule(IRule<T> this_rule){
            all_rules.Add(this_rule);
        }
        public virtual bool is_valid(){
            return !isBroken;
        }

        public virtual IEnumerable <string> validate(T item){
            var report = new Report();   // Nothing more than an object that collects the error messages
            isBroken = false;
            foreach (var rule in all_rules){
                if (rule.is_broken_by(item)){
                    isBroken = true;
                    report.add_validation_messages(rule.error_message);
                }
            }
            return report.final_result;
        }

        ///  This will be be overridden by the implementation
        protected abstract void configure_rules();
       
    }
 

When the validate method is called it iterates through all the rules passing in the object to validate and calls the is broken method on each. This in turn evaluates the predicate and handles the error messaging.
The idea being that each ruleset will be implemented using the above base class. Its usage is simple(ish). When you
implement a rule set, override the configure_rules(), and add the new breakable rule, eg.

…  protected override void configure_rules(){
            add_a_rule(new BreakableRule<IPerson>(x => x.FirstName.is_null_or_empty(), "First name cannot be blank"));
    }
           

So lets create a domain to play with all this.

 public interface IPerson{
        string FirstName { get; set; }
        string LastName { get; set; }
        int Age { get; set; }
    }

    public class Person : IPerson{
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
    }

 

The above objects are not self-validating. The rule set will validate them. So the rule set that will be used for validating the person object specifies the person must have a First and last name that is not null or empty
and the person must be greater than 21 years.

public class Person_rule_set: rule_set<IPerson>{
       
protected override void configure_rules(){
    add_a_rule(new BreakableRule<IPerson>(x => x.FirstName.is_null_or_empty(), "First name cannot be blank"));
    add_a_rule(new BreakableRule<IPerson>(x => x.LastName.is_null_or_empty(), "Last name cannot be blank"));
    add_a_rule(new BreakableRule<IPerson>(x => x.Age < 21, "Person must be older than 21"));
    add_a_rule(new BreakableRule<IPerson>(some_complex_rule,"No person with Q in your firstname"));
}

private bool some_complex_rule(IPerson person){
    return person.FirstName.is_null_or_empty() ||  person.FirstName.Contains("Q");
}
    }
 

To use this to validate an instance of a person object we do the following..

    var ruleset_for_a_person = new Person_rule_set();
    var error_report = ruleset_for_a_person.validate(some_person_instance);
    // you can test the vaildation
        if ( ! ruleset_for_a_person.is_valid() ) show_the (error_report );
 

Now if we extend this to domain objects that need to validate themselves create an interface IValidatable

    public interface IValidatable<T>    {
        IEnumerable<string> validate_using(IRuleset<T> this_rule_set);
        bool is_valid();
    }
 

Implementing this on an object will allow the object to “validate” itself - well actually using the visitor pattern we can add validation to the object.
This will allow you to pass the ruleset in (stratergy pattern),

public class ValidatablePerson : IPerson,IValidatable<IPerson>{
       
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }

         // STORE THE RULESET
        private IRuleset<IPerson> ruleset;
        public IEnumerable<string> validate_using(IRuleset<IPerson> this_rule_set){
            ruleset= this_rule_set;
            return ruleset.validate(this);  /// ** Here’s where  we ask the ruleset to validate this object **
        }
        public bool is_valid(){
            return ruleset.is_valid();  /// ?? should we call the validate_using ???
        }
    }
 

Here’s how we validate the object

var ruleset_for_a_person = new Person_rule_set();  // Use the same rule set
    var error_report = person_instance.validate_using ( ruleset_for_a_person);
    // you can test the vaildation
        if ( ! person_instance.is_valid() ) show_the (error_report );
 

So thats about it.. although we can make it a little neater to combine the rulesets to make up new rules. This ability to combine rules we tip into the fluent interface made popular by the specification pattern and an abstract class
I call “a chainer” (I’m sure there’s a better name for it ) - we’ll also wrap the fluentness into an extension class. so here goes…

 public abstract class Combined_ruleset<T> : rule_set<T>
    {
        protected readonly IRuleset<T> first;
        protected readonly IRuleset<T> second;

        public Combined_ruleset(IRuleset<T> first, IRuleset<T> second) {
            this.first = first;
            this.second = second;
        }
        public override IEnumerable<string> validate(T item){
            return first.validate(item).Union(second.validate(item));
        }

        protected override void configure_rules(){
        }      
    }
   
    // The AND chainer..
     public class AND_ruleset<T> : Combined_ruleset<T>    {
        public AND_ruleset(IRuleset<T> first, IRuleset<T> second) : base(first, second) { }
        public override bool is_valid()        {
            return first.is_valid() && second.is_valid();
        }
    }
    // The OR chainer..
     public class OR_ruleset<T> : Combined_ruleset<T>    {
        public OR_ruleset(IRuleset<T> first, IRuleset<T> second) : base(first, second) { }
        public override bool is_valid()        {
            return first.is_valid() || second.is_valid();
        }
    }
   
   

The extension class to bring in the fluentness

 public static class RulesetExtensions    {
        public static IRuleset<T> and<T>(this IRuleset<T> fist_specification, IRuleset<T> the_other){
            return new AND_ruleset<T>(fist_specification, the_other);
        }
        public static IRuleset<T> or<T>(this IRuleset<T> fist_specification, IRuleset<T> the_other){
            return new OR_ruleset<T>(fist_specification, the_other);
        }
    }
 

We can then use this to AND or OR together different rulesets that can be use in the validation eg.

    var casino_entry_rule = new adults_only_rule().and(new must_have_name_rule());
    report = some_person.validate_using (casino_entry_rule );
 

So now we validate an object based on a combination of rulesets. We can now vary the validated state of a object based on an externalized set of rules.
Hope that helps!
.. download the code here

Thanks
Zak

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