Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The biggest source of resistance that I've run into is not with the concept of state machines but with common implementations. Two examples:

* A quarter-century ago I implemented a cluster membership protocol and coordination system as a state machine. This provided great benefits in terms of verifiability, extensibility, etc. but some developers complained while the current state was explicit the history of how we got there was not. Adding a history mechanism helped, but frankly it still wasn't as good as the stack traces we'd had before. While the benefits far outweighed the drawbacks, this drawback was quite real.

* On my current project, a critical component (not dissimilar to the the one in the previous example) was implemented by someone else as a state machine. Besides the fact that the semantics of that state machine are unusual and undocumented, and that this state machine also lacks a history mechanism, developers over the years have been wildly inconsistent about which actions occur on which state transitions and how other information is saved/restored "off to the side" between transitions. The result is worse than spaghetti. It's like a chunky goulash that nobody can digest, which is why we're rewriting that component from scratch.

Based on these experiences, I suggest a few rules for implementing a successful state machine.

* Make sure the state machine is properly documented - what the states mean, what the events mean, how a transition is selected when multiple might apply, etc.

* Make the control flow discoverable by providing a history mechanism.

* Make the data discoverable by capturing all relevant flags and secondary state in a structure that's passed to the code implementing transitions.

* Verify the heck out of your state machine every time it changes. Make sure that every path terminates, using timeout events as needed, and that termination includes proper resource cleanup. If appropriate, verify that multiple concurrent invocations can't race with one another and violate the invariants you've checked within each. This verification is much easier to do with state machines than with other approaches, and you should take advantage of that.




I find the biggest resistance is the obvious fact that implementing a state machine requires planning: mapping out the goals, identify which are your formal states, map out the transitions, evaluate the overall logic requirement and then design the state machine's data structure and classes... All the "planning" is the opposite of what most "code slinging macho programmer personalities" want to do; they want to jump into coding an just wing it. That is the real issue here: Undisciplined development.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: