Boost logo

Boost :

From: Jeff Garland (jeff_at_[hidden])
Date: 2005-02-27 11:17:48


On Sun, 27 Feb 2005 11:40:52 +0000 (UTC), Darryl Green wrote

> When the obvious increase in code complexity is smaller than the obvious
> decrease in code complexity?
>
> I really need to ask - an obvious increase in complexity over what?
> I have seen some truly complex code arise from *not* using an fsm
> framework in some form or another.

The context of my comment was with respect to the stop watch example. I think
we are all in agreement that the stop watch is too simple for the benefits of
increased complexity required to use fsm. And I'm thinking we might want to
say something about that in the docs -- I'm afraid alot of developers would be
scared away looking at the code. A bunch of us understand that once the state
machine gets a little more complicated the hand solutions tend to get ugly and
buggy, but

In particular I was thinking of some of the 'scary' code as:

  double ElapsedTime() const
  {
    return state_cast< const IElapsedTime & >().ElapsedTime();
  }
  //class running
    virtual double ElapsedTime() const
    {
      return context< Active >().ElapsedTime() +
        std::difftime( std::time( 0 ), startTime_ );
    }

One part of the increased code complexity is just getting to understand the
idioms to access other states. The other part is that that originally threw
me was the locations of the time calculation functions. It wasn't obvious to
me why I would code the addition to elapsed time was in the destructor of the
Running state versus somehow making it part of the running->stopped
transition. In this case I was thinking about how I would explain the rules
of thumb to a 'junior' developer that actaully had to write the behavioral code.

BTW, I think part of my trouble might have been that the code context< Active
> is introduced before it is explained in the tutorial. So I think I got
distracted trying to understand what that code meant...
 
> My attempt at a heuristic is that one should consider using the fsm
> libary when:
>
> 1) There are more than a handful of transitions per state
>
> 2) There are more than a handful of states
>
> 3) The state space is naturally hierarchical
>
> 4) There is substantial context associated with (groups of) states
>
> If you have only (1) or (2), it is likely that the problem doesn't warrant
> using boost fsm.
> If you have (1) and (2) it is worth at least thinking about using
> boost fsm, with substantial size or the presence of either of the
> other 2 features being enough to make it pretty much an immediate choice.

That's pretty good. I was thinking that probably more than few states and I
think point 4 is critical. Most states don't just have a single bit of
information with then. I'm thinking of telecom applications as an example.
For every state in a phone call there's alot of state.

As Andreas points out, one problem with handcrafted designs is there tends be
alot of code to manage the context associated with these states and it gets
lumped into one 'winnebago class' (a winnebago is a really large recreational
vehicle with everything thrown in) that does everything and becomes a hotspot
for change in the design.

> > So the other general design
> > question is -- when is it better to but the variables asoociated with the
> > machine in a state class versus pushing them up to the machine?
>
> Innermost (leaf) states are usually empty, outer states are really a
> sort of sub-machine and it is just a scoping issue - if the variable
> scope is clearly tied to the lifetime of the outer state/sub-machine,
> put it there. Transition functions then naturally are placed in the
> same state/context as the variables they manipulate.

Also good.

> > Again there
> > may be no answer here, but maybe someone that has implemented real code using
> > fsm would have a design heuristic...
>
> I have seen substantial reductions in code complexity arise out of
> using the fsm libary in a refactoring of some existing code. The
> result is also much easier to modify/maintain. This last point is
> particularly important if the fsm is not well specified to start
> with and/or may need to be modified in reaction to changes in
> requirements. Using boost fsm an iterative/exploratory design
> approach works fine. In many ways this is less painful than if there
> were a code generator. I'd actually prefer a diagram/documentation
> generator.

I was thinking that if you have XMI from a design tool it might be pretty easy
to initially generate code -- but I won't disagree with wanting to reverse the
transition table from the code. It's just that parsing C++ is probably harder
than the other way around, but perhaps it wouldn't be too bad.
 
Jeff


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk