Creating a dynamic state machine with C# and NHibernate, Part 2: Adding business rules.

This the second part of a series started in an earlier post; Creating a dynamic state machine with C# and NHibernate 

In my first post I showed you how to create a state machine, attach it to an entity and then save it using NHibernate. In this post we’ll extend the state machine with the capability of adding business rules that must be fulfilled to allow transitions. These rules will be dynamically added to each state and persisted to the database using NHibernate.

 

Extend the model with business rules using strategy pattern

The first step will be to use an implementation of the Strategy Pattern to ensure that our business rules engine is open for extension (thus following the open-closed principle). First we’ll define an interface to use for our business rules, listing 1 shows the definition;

 

public interface IRule
{
    bool IsMetBy(Template entity, State state);
}

listing 1, the IRule interface

The IsMetBy method accepts the entity that the state is attached to which we’ll be using as data for our rules later. Next we add a list of business rules to the state class;

 

public class State
{
    ...

    private IList<IRule> _transitionRules = new List<IRule>();
    public virtual IList<IRule> TransitionRules
    {
        get { return _transitionRules; }
        set { _transitionRules = value; }
    }

    public virtual bool HasAllTransitionRulesMetBy(Template entity)
    {
        var transitionIsAllowed = true;
        foreach (var rule in TransitionRules)
            transitionIsAllowed &= rule.IsMetBy(entity, this);

        return transitionIsAllowed;
    }
}

listing 2, list of rules on the state class

With this addition every state now holds a list of rules that need to be fulfilled before the state accept being changed into it. We’ve added a method that runs through all the business rules for the state and validate that all of them are met. This a call to HasAllTransitionRulesMetBy is added to the templates ChangeStateTo method;

public void ChangeStateTo(State newState)
{
    if (State.CanBeChangedTo(newState) && newState.HasAllTransitionRulesMetBy(this))
        State = newState;
    else
        throw new InvalidStateTransitionException();
}

listing 3, changes to the ChangeState method

At this point changing state will run through the list of allowed transitions, functionality we added in the first part, and the list of rules to make sure the transition is allowed. We honor the open – closed principle by allowing rules to be added in a simple fashion, thus not relying on a lot of refactoring when rules change or get’s added.

Implementing a rule

To make this state machine meaningful we need to start creating business rules. For convenience I’ve added a base class Rule that implements some properties needed later but in essence it’s the same as our interface. First rule will ensure that an entity from the template has a ScheduledHours property with a minimum of time. Listing 4 shows our first rule,

 

public class IsScheduledForAtLeast : Rule
{
    public virtual int ScheduledHours { get; set; }

    protected IsScheduledForAtLeast() {}

    public IsScheduledForAtLeast(int scheduledHours)
    {
        this.ScheduledHours = scheduledHours;
    }

    public override bool IsMetBy(Template entity, State state)
    {
       if ( entity.ScheduledHours >= ScheduledHours && state == "Closed" )
           return true;

        return false;
    }
}

listing 4, an example rule

In a typical scenario these rules might be a bit more complex and in part three of this series we’ll look into rules that need more then just the entity state to get it’s work done. Figure 1 displays the model we’ve built so far;

image

Figure 1, our model so far

A test to validate this looks something like listing 5;

public static class States
{
    public static State ClosedState = new State("Closed")
    { TransitionRules = new List<IRule>
    { new MinimumAttendanceRule(8), new IsScheduledForAtLeast(4)} };

    public static State OnGoingState = new State("OnGoing");

    public static State OpenState = new State("Open")
    { AllowedTransitions = new List<State> { "Paused", ClosedState } };
}

[Test]
public void It_will_not_allow_state_transition_from_closed_to_open()
{
    var entity = new Entity(States.ClosedState);

    Assert.Throws(typeof(InvalidStateTransitionException),
        () => entity.ChangeStateTo(States.OpenState));
}

 

Using NHibernate to persist a template with state and business rules.

So far we can build a state machine that is setup with transition rules and business rules for each state, but only in memory. For this to be meaningful we actually need to persist it as well. For our scenario we want to persist the template, it’s current state, all allowed state transitions and the rules added to each transition.

An example setup that we need to persist looks like listing 6;

[Test]
public void Save_a_state_with_transition_rules_added()
{
    var savedState = new State("Open")
                         {
                             TransitionRules =
                             new List<IRule> {
                                new MinimumAttendanceRule(8),
                                new IsScheduledForAtLeast(5)}
                         };

    stateRepository.Save(savedState);
    var fetchedState = validationRepository.Get(savedState.Id);

    Assert.That(fetchedState.TransitionRules.Count, Is.EqualTo(2));

   Assert.That(fetchedState.TransitionRules.FirstOrDefault(
    rule => rule is MinimumAttendanceRule), Is.Not.Null);

    Assert.That(fetchedState.TransitionRules.FirstOrDefault(
    rule => rule is IsScheduledForAtLeast), Is.Not.Null);
}

So how do you save something this dynamic to the database? There is no way of telling what rules will be added and certainly not a table structure that will fit. Can we do it? Yes we can. Using inheritance mapping in NHibernate this is very possible. For our scenario we’re using the inheritance type “Discriminator column” and a many-to-many relationship between state and rule. The database tables for this will look like figure 2;

imagefigure 2, Table structure 

As figure 2 shows it is now possible to store every state with it’s transitions, their rules and any configured value needed (we serialize all values into one column at the moment). We need to update our NHibernate mapping to include the list of rules and all implemented rule types. Listing 7 shows the mapping files for this scenario;

 

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="State" table="States">    

     ...

    <bag name="TransitionRules" cascade="all" table="TransitionRules">
      <key column="StateId" />
      <many-to-many column="RuleId"  class="Rule" />
    </bag>
  </class>
</hibernate-mapping>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Rule" table="Rules" abstract="true">
    <id name="Id" type="int">
      <generator class="native" />
    </id>
    <discriminator column="Name" />

    <subclass discriminator-value="IsScheduledForAtLeast"
                     name="IsScheduledForAtLeast">
      <property name="ScheduledHours" column="Value" />
    </subclass>
  </class>
</hibernate-mapping>

listing 7, NHibernate mapping

 

 

Summary

With the usage of interfaces and the open-closed principle, we get a flexible way to add rules to our state machine. These rules can easily be added in a user interface and several templates with different sets of states and business rules. Using some powerful mapping techniques in NHibernate this is persisted easily as well.

This was part 2 of a three part series. In the last part we’ll be using dependency injection in our rules to enable more advanced scenarios. I’ll also provide you with a complete end-to-end sample solution.

Creating a dynamic state machine with C# and NHibernate

In my last post (An architecture dilemma: Workflow Foundation or a hand rolled state machine?) I talked about the discussion around an architectural choice. The conclusion of that discussion was to hand-roll a dynamic state machine. This post is the first part of 3 explaining the solution we used. In this part we’ll focus on the state machine, in the following two parts we’ll be adding business rules to each state and utilizing a couple of tricks from NHibernate to make those rules rich.

If you are uncertain what the state machine pattern looks like, there is some information here: http://msdn.microsoft.com/en-us/magazine/cc301852.aspx . For the rest of this post I will assume that you got a basic understanding of it.

The requirements for our state machine was that users should be able to add their own states and tight them into the state machine. They should also be able to define the flow, designing the structure of which states can transition to each other.

The basic state machine looks something like this:

Classic State Machine

Since we need to be more dynamic then this our model turned out more like this instead:

image

In this model we are using composition instead of inheritance to build our state machine. The list “AllowedTransitions” contains a list of states that is allowed to transition to from the current one.

The method “CanBeChangedInto” takes a state object and compares it to the list of states and decides if the transition is allowed. For our scenario this comparison is done by implementing IEquatable and overriding the appropriate operators (==, !=).

This is defined on a template kind of entity, there will be “instances” made out of this template where all attributes are copied onto the instance.

The implementation of the ChangeStateTo method on the template is fairly simple:

Template:
public void ChangeStateTo(State newState)
{
    if (State.CanBeChangedInTo(newState))
        State = newState;
    else
        throw new InvalidStateTransitionException();
}

State:
public bool CanBeChangedInTo(State state)
{
    return AllowedTransitions.Contains(state);
}

Simple but yet very powerful and allows for the kind of dynamic state transitions our scenario requires.

Adding state transitions is easy as well, since the AllowedTransitions list holds

Our project uses NHibernate as a persistence engine and to persist our dynamic state we use a many to many bag mapped in xml:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="" namespace="">
  <class name="State" table="States">
    <id name="Id" type="int">
      <generator class="native" />
    </id>

    <property name="Name" length="255" not-null="true" />

    <bag name="AllowedTransitions" table="AllowedStateTransitions">
      <key column="FromState_Id" />
      <many-to-many column="ToState_Id"  class="State" />
    </bag>
  </class>
</hibernate-mapping>

Between NHibernate many-to-many mapping and the design of the state transition list it’s easy to start building an application upon this. We are not done yet though. Every state needs more transition rules then just “AllowedTransitions”. The next post will tackle that requirement.

An architecture dilemma: Workflow Foundation or a hand rolled state machine?

Workflow Foundation is an interesting piece of technology, in a recent architectural decision for a project I had time to examine the pro’s and con’s of WF for a particular challenge.

This sprint a story came up that will give super-users of a system the ability to define new states in a state machine and attach business rules for state transition dynamically through a user interface. These custom states are then attached to entities in the system.

Workflow foundation is an excellent engine for this kind of flexibility, pop a couple of custom activities and just create new state machines for each time you need changes. Well, that’s what it says on the box, but is it really that simple?

On the execution side of things, WF is an excellent choice. Good engine with a lot of built in functionality. But what about the end user side? Allowing users to easily define new states, attach rules to each state and attach them to entity templates?

One thing that WF isn’t is User Friendly. So what would it take to make WF user friendly? A custom designer, that emits xoml, some training in the WF designer and process orientation and a container to run the state machine in. This is a lot of work.

WF is powerful, but when the user are involved. It’s weaknesses quickly become expensive.

A simple solution, not as powerful on the execution side, is to handcraft a state machine and store the state in a simple table or two. Utilizing the state machine pattern with a touch of strategy pattern and you can come a long long way.

So since the user experience was the top priority for our scenario and we really only needed the state machine functionality, no work to be done . The first iteration was handcrafted, utilizing NHibernate to store some state in a database.

So, WF does solve a lot of things. But it comes with a cost and increased complexity. If you aren’t using WF’s full potential, chances are it’s to expensive for you.

My next post on this subject will present the solution in code.