This is the first in a series of introductions to the AS3StateMachine, here we will look at the concept of a Finite State Machine (FSM) and what it actually does.
I will assume that you have a basic idea of what state is, and if you want an in depth definition of an FSM I suggest reading wikipedia’s entry, I’m not intending to get into anything too theoretical here.
The AS3StateMachine is basically a flat network of nodes (states) connected by unidirectional edges (transitions). The AS3StateMachine keeps track of the current state, manages the movement from one state to the next, and dispatches via your framework’s event-bus (which ever flavour it uses). Its job is to manage your application’s states – not to be confused with the State Pattern, or indeed Flash Builder’s view States.
I have been using a State Machine in my applications for many years now. Originally they defined only outlying processes, like boot-strapping, shut-down or complex in/out routines – all surrounding a big catch-all DISPLAYING state where the main part of the application business got done.
Recently, however, I have started using the FSM as the sole mapper of commands; an über-controller, filling in that catch-all DISPLAYING state.
For me, an FSM is a really good way of visualising the flow of processes in your application without all the nitty-gritty classes getting in the way. This is especially true when using an MVC(S) framework as they are specifically designed to decouple all your actors from each other.
The first thing I do before starting a project is to switch the computer off, get out my sketch book, an HB pencil and flee the office. I then proceed to sketch out state-diagrams, allocate responsibility, and keep reworking until I have the simplest structure I can. If it starts to look like spaghetti, I start splitting out processes into different modules with their own FSM.
These diagrams are very easily converted into the XML definition ready to be injected (remember to keep them up-to-date for you documentation).
I have also found working in this way very flexible, being able to rework transitions and add new states without the whole house falling down.
Let’s have a look at an example of an FSM – one that is immediately familiar and understandable.
Mapping out a Door as an FSM
A Door can be mapped into a series of states:
- LOCKED (pulled to, lock engaged)
- CLOSED (pulled to, lock disengaged)
- OPEN (ajar and lock disengaged)
Once we have defined the states, we can determine their relationship to each other by connecting them with transitions.
- to get to a CLOSED door from an OPEN one, you must first close it (lessen the angle of its hinges, so it lies flush in the doorway)
- to then get a LOCKED door, you must lock it (engage the lock)
- to then return to a CLOSED door you must then unlock it (disengage the lock)
The diagram below shows the States with all their transitions:
You can see from this example that one of the advantages of using an FSM is to create strict pathways of logic. A LOCKED door cannot transition directly to an OPENED door, it must enter the CLOSED state first. This ensures that the lock is disengaged first before attempting to open it. Attempting to open a LOCKED door will simply fail, as there is no open transition defined in the LOCKED state. This is generally also true of a Real-World Door, which is constrained by everyday physics. A Real-World Door can indeed go from a LOCKED state directly to an OPEN state, but it would require a brute force attack, and the breaking of the door.
Moreover this Virtual Door FSM improves on a Real-World Door in second way, by fixing a serious design-flaw. It does not allow an OPENED door to be LOCKED (there is no lock transition defined in the OPENED state). Engaging the lock of an OPENED door would break its close functionality.
Should you wish, you could also choose to see this as a “feature”, and create a forth state:
- LATCHED (ajar and lock engaged)
This Latchable Door exposes quite a serious security vulnerability which could easily be exploited, so we shall not consider this further.
Each state then has certain responsibilities: the LOCKED state is responsible for modifying the lock; the OPENED state ensures that the door is swung away from the door frame; the CLOSED state, that it is flush with it.
Note that the LOCKED state has no knowledge of the angle of the door – the CLOSED state ensures that conditions are correct for the lock to be engaged, yet it in turn, it has no knowledge of the lock.
Each state will manage certain procedures that will configure the application actors according to that state’s responsibilities.
On top of this, a state can also deny entrance or exit from a valid transition if the conditions required are not met.
Let’s imagine we encounter the Virtual Door at its initial state (the LOCKED one, as indicated by the arrow with the circle at the top of the diagram). We try to unlock it (by invoking the unlock transition), but the LOCKED state examines our key (our user-privileges, for example), finds them wanting, and cancels the transition. We are locked out, as our key does not fit the lock.
So, there we have it, I hope that has made it clear what – on a conceptual level, the AS3StateMachine is all about. Before digging into any actual code, though, I think that we need to take a look at what happens during a transition from one state to another – and that is precisely what we will be considering in the next introductory post.