19 ms·
It sounds like we've had similar experiences. I converted a handful of ad hoc "state machines" in a telephony system to FA. The original code was loaded with ex
by bstpierre 14y ago
It sounds like we've had similar experiences. I converted a handful of ad hoc "state machines" in a telephony system to FA. The original code was loaded with exceptions and special cases (and bugs). Converting to FA required detailed analysis of the existing system to extract the distinct events and states. I used a tool I wrote [1] to generate C state tables and an event loop from a description of the states+events.
While the state machines that came out of the analysis were a big improvement, they still weren't perfect. We came across a few bugs later on. Using a strict representation of the state machines was a huge advantage in debugging and maintenance. When everything is moving through the same event loop, it's easy to add logging in the form "[timestamp] state A: event X -> state B". Adding a new state or event to the machine (to fix a bug or add a new feature) is much easier when everything is in one place.
In a couple of cases, the state machine started to become large and unwieldy. Usually the cause was that there would be a couple of "meta" states: we'd have states A, B, and C, but then we'd need to represent "states B and C when X is true; states A and B when Y is true". Pulling X and Y into a separate machine simplified the parent state machine -- every X and Y moved into the child divides the number of states in the parent by as much as half. Then the parent can inject events into the child, and the child can fire events back to the parent.
[1] http://bstpierre.org/Projects/smc/ http://bstpierre.org/Projects/smc/
- rubyrescue 14y agoThis was one of the reasons Erlang was invented - big state machine + telephony.
- jacquesm 14y agoIndeed, it really sounds like a very similar experience, up to and including the code generation. One more thing I ended up adding (that isn't on your list above) is a true string type to the 'C' language (backwards compatible, works with pre-defined strings as well), including garbage collection. I found that in order to get the right level of abstraction the C string type was simply inadequate, it kept forcing things into the foreground that should not even be visible at that level. The one thing still missing is copy-on-write for string duplication, but that's a pretty tricky thing to implement in a thread safe and portable way. This would give a huge performance boost, but at the moment that would be just another case of premature optimization.