views:

425

answers:

6

I have a little problem that involves modeling a state machine.

I have managed to do a little bit of knowledge engineering and 'reverse engineer' a set of primitive deterministic rules that determine state as well as state transitions.

I would like to know what the best practices are regarding:

  • How to rigorously test my states and state transitions to make sure that the system cannot end up in an undetermined state.

  • How to enforce state transition requirements (for example, it should be impossible to go directly from stateFoo to StateFooBar, i.e. to imbue each state with 'knowledge' about the states it can transition to.

Ideally, I would like to use clean, pattern based design, with templates wherever possible.

I do need somewhere to start though and I would be grateful for any pointers (no pun intended), that are sent my way.

A: 

Sounds like a pristine application for unit testing. There are many unit testing frameworks out there. I happen to like the Boost one.

Ben Collins
+1  A: 

Testing has little to do with patterns, templates, etc. I'd recommend a testing framework like CppUnit (part of the xUnit family) to capture all your test cases. The number will depend on the complexity of the state machine, of course.

Your question about enforcing state transitions goes to the heart of your class design for your state machine. I'd say that a state will have a collection of child states that it could transition to, along with the event that will trigger each one. If event Foo does not have a FooBar child, then there's no way to transition to it.

I'd Google "object-oriented finite state machines" to start getting some design ideas.

When I was thinking about problems like this, I thought that the Composite design pattern could be part of it, because a State might represent a more complex FSM. I'd have a State interface, with SimpleState and CompositeState as implementations. I'd have to start again and see if it could all work out.

duffymo
+2  A: 

Gosh, it isn’t as complicated as it seems. State machine code is very simple and short.

Store the state in a variable, let’s say myState.

You state machine will be a switch statement, branching on the value of the myState variable to exercise the code for each state.

The code will be full of lines like this:

myState = newState;

To enforce state transition requirements, you need to add a little method called instead, like this

void DoSafeStateTransition( int newState )
{
// check myState -. newState is not forbidden
// lots of ways to do this
// perhaps nested switch statement

switch( myState ) {

 …

case X:  switch( newState ) 
    case A: case B:  case Z: HorribleError( newState );
    break;

 ...

}

// check that newState is not undetermined

switch( newState ) {

// all the determined states
case A: case B: case C … case Z: myState = newState; break;
default: HorribleError( newState );
}
}
void HorribleError( int newState )
{  printf("Attempt to go from %d to %d - disallowed\n",
       myState, newState );
   exit(1);
}

I suggest that this simple and short enough that inspecting will do a better job than unit testing - it will certainly be lots faster!

The point, in my mind, of unit testing is that the test code be simpler than the code tested, so it can be more easily inspected for correctness, then used to test the complicated code. It is often easier to check the state machine code than state machine test code. There is not much point in reporting a 100% unit test pass, when you have little idea if the unit tests are correct.

Put it another way: coding a state machine is easy, designing the correct one is hard. Unit tests will only tell you if you correctly coded the design, not if the design was correct.

ravenspoint
+3  A: 

Be sure to take a look at the Boost Statechart Library.

gammelgul
+1  A: 

Using state machines is something that comes up from time to time. I usually do as ravenspoint suggested and simply make a switch statement. But, that only works if the states are not too large. This kinda sounds like your case. Taking that into consideration, I think the best thing is to start with a good architecture that will allow for some of the things you want to do. I took duffymo's suggestion and tried Google. This paper looked interesting - Object-Oriented State Machines. It might be overkill but I think it will give a framework that would be easy to test with something like CppUnit.

Some other good references from the Google search

A Finite State Machine Framework

Object-Oriented Finite State Machines

zooropa
A: 

If you're looking for the classic GOF Design Patterns State Machine Pattern, then look at wikipedia.

Take a look on this page (at the time of writing) at the Java example.

It has a StateContext class, which you can see from the example usage, has clients which know about the writeName method. The implementation is: this.myState.writeName(this, name); which means that it forwards the call to the current state, passing itself as the first argument.

Now look at interface State, it has a writeName method which matches the above usage. If you look at both StateA and StateB, they call back to the context setting a new state.

That's most of the State Pattern right there. The only thing to realise is that the StateContext class can hold all of the data involved in its operation, including a reference (it has to be a pointer in C++) to the current state. All the states collectively hold all of the behaviour, but no data, instead deferring the data (plus helper methods) in the context.

When I'm developing a state machine (I'm usually using TDD) I don't bother testing state transitions, just that the final behaviour is as I want.

quamrana