State pattern using C#. Part 02.

In the previous post we saw how we can implement the state pattern (I know, I didn’t show you the purist way of using the State pattern …) and include in the state execution the flow logic.

This technique is fine but … it requires a lot of effort in the implementation and requires a lot of maintenance, plus it has the GAP of forcing us to re-run the CanExecute delegate every time we want to execute a specific action.

On the web I have found some solutions that personally didn’t satisfy me at all. I personally believe that the best way of designing a state machine workflow is to use a workflow engine and NET Framework provides with NET 4 an amazing state engine. Anyway let’s see what the web offers instead of using WF 4.

Stateless Open source project

Stateless is an Open source project hosted on Google code and available here: http://code.google.com/p/stateless/; it is a C# implementation of a stateless workflow using the BOO language.

We have the same domain exposed in the previous post but in this case we modified a little bit the Order object and we do not use anymore the Command pattern.

OrderObjectStateless

The class Order has 5 different methods that can modify its state in the following way:

Create an Order
  1. public void Create()
  2. {
  3.     this.State = OrderState.Created;
  4. }

They do not verify anymore if the action can or cannot be execute, we just know that the Create method, for example, modifies the state of the Order to “Created”.

Now it is time to wrap this code in a separated class that we will call OrderService and that is identified in DDD as a Domain Service object, a service used in the domain space to wrap business logic and keep it outside the Entity object. The final result should like this one:

statelessdiagram

The trick with http://code.google.com/p/stateless/ is to split the service in two parts, the first one is used to Bootstrap the stateless framework in the following way:

Stateless boostrapping
  1. public sealed class OrderService
  2. {
  3.     private StateMachine<OrderState, OrderActions> workflow;
  4.  
  5.     public OrderService()
  6.     {
  7.         workflow = new StateMachine<OrderState, OrderActions>(OrderState.Undefined);
  8.         workflow
  9.             .Configure(OrderState.Undefined)
  10.             .Permit(OrderActions.Create, OrderState.Created);
  11.         workflow
  12.             .Configure(OrderState.Created)
  13.             .Permit(OrderActions.Cancel, OrderState.Cancelled)
  14.             .Permit(OrderActions.Modify, OrderState.Modified)
  15.             .Permit(OrderActions.Approve, OrderState.Approved);
  16.  
  17.     }

And then we add a method in the service that will be used to Fire a specific state change, like this one:

Command pattern
  1. public void Fire(Order order, OrderActions action)
  2. {
  3.     workflow.Fire(action);
  4.     order.State = workflow.State;
  5. }
  6.  
  7. public bool CanFire(Order order, OrderActions action)
  8. {
  9.     return workflow.CanFire(action);
  10. }

Now, by default, Stateless raises an error (Exception) if the operation can’t be executed. The following test demonstrates the exception raised by stateless:

TDD
  1. [Test]
  2. public void CannotApproveAnOrderBeforeCreatingIt()
  3. {
  4.     var order = new Order();
  5.     var service = new OrderService();
  6.     Assert.Throws<InvalidOperationException>(() =>
  7.         service.Fire(order, OrderActions.Approve));
  8.     Assert.That(order.State, Is.EqualTo(OrderState.Undefined));
  9. }

The exception is of type InvalidOperationException.

Conclusion

Stateless is a good state machine framework, open source, easy to learn and it has a good and clear DSL language. Unfortunately the project is very young, the active developer is only one and it still has a huge list of ToDo and Bugs to be fixed.

It can be used to replace custom If and Switch in the Domain language but if you need to do some custom and more complicated evaluations, Stateless can result very verbose because it doesn’t have a UI so you have to prepare all the If and Switch using the Configure syntax.