Could all Code ever written be improved by applying the State Machine Pattern?
I was working on a project that was a mass of horrendous awful, buggy, broken spaghetti code.
I copied Martin Fowler's example State Machine code from this blog and transformed the whole heap of crap into a series of statements.
Literally just a list of States, Events, Transitions and Commands.
I can't believe the transformation. The code is now clean, and works. Of course i was aware of State Machines before and have even implemented them
but in the Martin Fowler example the separation of model/configuration is amazing.
This makes me think that almost everything i've ever done could have benefitted in some way from this approach. I want this functionality in every language i use.
Maybe this should even be a language level feature.
Anyone think this is wrong?
Or anyone have a similar experience with a different pattern?
Finite state machines (FSM's) and more specifically domain specific languages (DSL's) make it easier to match a problem to one specific solution domain, by describing the solution in a specialised language.
The limitations of the State Machine pattern is that it itself constitutes a programming language, but one for which you have to write your own execution, testing and debugging tools; and one which any maintainer has to learn. You have moved the complexity of your code into a complex FSM configuration. Occasionally, this is useful, but certainly not universally.
And since any von Neumann computer is itself a FSM, then certainly any program can be recast in this fashion.
Spaghetti code is never the right answer. Patterns are good at cleaning up spaghetti code, but just having a well thought out design can achieve the same thing.
With respect to the state-machine question: I personally find them to be very useful. For a public facing app I created, I refactored to use a state-chart (which I think is the same thing as the state-machine) and noticed the benefits you mentioned. It is a really useful abstraction, because it allows you to separate the concern of handling events out into a separate component. With this, bugs go away because the state-chart implicitly knows what a user can do where, and since the events are only handled in the right place, you can't really perform an invalid action. Also, using the state-chart allowed me to simplify the code because I could pull all the event handling code out of where it was and put it where it in one place where it was supposed to be -- in other words, other components weren't complicated by also having event handlers on them.
A picture is worth a thousand works -- Here is the design I came up with:
With this, anyone who looks at it knows exactly how the app behaves at a high level. Its hard to break this, because like I said, you can't get to an invalid state because the event handlers control exactly where you can go; if you can get to an invalid state, its an implementation bug that is easily fixed. Also, the code cleansing benefits are enormous. For example, with the state chart, whenever I enter any paused state, I can do things like stop the clock, put a mask on the board, etc. Its a few lines of code in one place -- because when i enter a substate of paused the chart goes thru the parent state first. without the statechart, I would have to do that code everywhere an event was handled.
I don't know if it needs to be a language level feature, but having a well implemented framework is nice.