Wednesday, February 26, 2014

Stateless State Machine

The other day I went to grab a snack in the vending machine at work. I swiped my RFID badge on the reader, waited a few seconds, it showed my balance, and while entering the number of the yummy snack I was ready to consume, the balance went back to zero, which then had the effect of me hitting enter and it displaying “not enough funds, please enter money”.

Knowing full well that a few seconds ago, it showed my balance as being more then plenty, I repeated this process, this time with vigilance in preparing the number ahead of time, so that the second it showed my balance, I could hit enter. Suffice to say, I enjoyed my snack. But this brought to my attention that this state machine didn’t have a path for stopping its pricing update when it had a balance. In other words, a broken state machine.


A state machine is defined as any device that stores the status of something at a given time and can operate on input to change the status and/or an action or output to take place for any given change. That is a great “what is” definition, but what is it really, and how can I make these awesome prone to buggy snippets of code?

Lets start with a basic state machine:
    public class BasicStateMachine
    {
        public string State { get; private set; }

        public void Transition(string state)
        {
            switch (state)
            {
                case "on":
                    State = "ON";
                    OnSwitchedOn();
                    break;
                default:
                    State = "OFF";
                    OnSwitchedOff();
                    break;
            }
        }

        private void OnSwitchedOn()
        {
            // Do something clever
        }

        private void OnSwitchedOff()
        {
            // Stop doing something clever
        }
    }


The above code is pretty straightforward. You have the ability to Transition to states, when the state is set to on, it sets the state to “ON” and fires the OnSwitchedOn method. Anything else attempting to transition will just switch it off.

Now that the “what is a state machine” is taken care of, lets check out a fluent API called Stateless by to do the same thing above, but “better”.

Stateless by Nicholas Blumhardt is a base for exploration of generic and functional programming to drive workflow in .Net. It allows you to create lightweight state machine based workflows directly in code.

On NuGet you will find two packages Stateless and Stateless-4.0. The latter is just a .Net 4.0 complication.

PM> Install-Package stateless-4.0

With Stateless our state machine looks something like this.


    public class StatelessStateMachine
    {
        private readonly StateMachine _stateMachine;

        public enum Trigger
        {
            TurnOn,
            TurnOff
        }

        public enum State
        {
            On,
            Off
        }

        public State Current { get { return _stateMachine.State; } }

        public StatelessStateMachine()
        {
            _stateMachine = new StateMachine(State.Off);
            _stateMachine.Configure(State.Off)
                .Permit(Trigger.TurnOn, State.On)
                .OnEntry(OnSwitchedOff);

            _stateMachine.Configure(State.On)
                .Permit(Trigger.TurnOff, State.Off)
                .OnEntry(OnSwitchedOn);
        }

        public bool Transition(Trigger trigger)
        {
            if (!_stateMachine.CanFire(trigger))
                return false;

            _stateMachine.Fire(trigger);

            return true;
        }
        private void OnSwitchedOn()
        {
            // Do something clever
        }

        private void OnSwitchedOff()
        {
            // Stop doing something clever
        }

    }


Now.. that is a ton more code it looks like, but this is a dynamic system that can grow with need. The State Machine object requires two objects, one for the “State” and one for the “Trigger” or as I like to reference it, the “Transition”.

Going over the Configure section, this is simply setting up that in the “Off” state we are allowed to transition to the “On” state with the “TurnOn” trigger, and finally when the state is entered, call the OnSwitchedOff. There is a point of confusion that can occur here, as with most Fluent API’s. The OnEntry is for the Configure, not the Permit. It might even be more useful later to move the OnEntry above the Permit just to clarify for other people using the code.

Stateless is a great bit of code, the source includes a ton of unit tests (nUnit) as well as a decent amount of samples. It is also really lightweight being 3 total classes (spread out over 13 files) and no external dependencies outside of the BCL. So simple in fact, on one recent project I worked with, I just included the source code, rather than referencing the library to keep down on my dependencies.

I highly recommend heading over to the Google Code Project and giving it a shot!

You can find the code used in this Blog Post on my GitHub Repository.

No comments: