Why Developers Sometimes Use Finite State Machines

Posted On: 2021-05-24

By Mark

While doing some supporting research for an (unrelated) blog post, I stumbled across an article with a rather click-bait-y title that made some pretty strong claims about the use of finite state machines in programming. While at first glance it reads a bit like a straw man argument, I thought looking a bit closer - to see which parts are straw and which are not - could illuminate some interesting details about the topic.

What is a Finite State Machine?

Before digging into the argument itself, a bit of background on Finite State Machines (aka. FSM) is useful. A FSM is an abstraction that represents multiple mutually exclusive states along with a set of rules for when an object in one state should transition into another. As an example: a door may have two states, open or closed, and it will transition between the two states based on the direction of force applied to it. Thus, if a closed door is "push to open", and you push it, then it will be in the "open" state (and pulling it when in the "open" state will make it be in the "closed" state). Of course, most doors actually have more than two states (for example, doors with locks can also be locked/unlocked) - so this model of a two-state door is rather naive compared to actual real-world doors.

One important detail about FSMs is that they are often used for planning. When used in that way, the FSM typically describes the expected states and transitions, while omitting states and transitions that are not an intended part of the design. Consider, for example, a lock on a door. The two states (locked/unlocked) and the rules for changing those (ie. when the key is turned clockwise, an unlocked door moves to the locked state) would make sense to include in the design. The FSM would likely not include transitions that are defined by the material properties of the object - such as the lock* giving way to forced entry.

What About the Article?

The article in question asserts that developers generally don't use a single FSM to represent the control structure of an entire system*. The bulk of the article is spent arguing that attempting to do so is a bad idea: systems are generally pretty complicated, and a complicated FSM is difficult to maintain. It also enumerates known limitations of FSMs, such as only being able to represent a finite possiblity space and being a poor fit for designs that call for being in multiple states simultaneously.

Contrary to the title of the article, developers do, in fact, use FSMs. FSMs can be useful for many tasks, such as managing simple, deterministic AI (such as "walk until you hit a ledge, then turn around") or representing a small set of agent states and their relevant capabilities (such as "being in the knockback state prevents walking"). Importantly, developers (generally) don't attempt to use the FSM to manage every relevant detail - the FSM may call for an agent to walk, but the walk algorithm itself won't be implemented as a FSM. To put it succinctly, a FSM is just one tool available to developers, and for many problems (including system architecture) there are other, better tools available.

Why Did This Happen?

While the article literally reads as a straw man argument asserting one should never use a particular tool, a more charitable explanation is that it's an article aimed at people who primarily engage with only one rung of their domain's Ladder of Abstraction. Many organizations are carved up such that any particular individual only has responsibilities at a particular level of abstraction: workers only see their tasks, managers only see the workers' performance, directors only see the "big picture", etc. If someone is coming from such a background, they could very possibly see a tool that works at their abstraction level (such using a flowchart as a FSM for managing workers), and assume it works for all levels (or, more likely, simply not think about any other level.)

Software developers, by contrast, generally can't stick to one layer of abstraction*. Devs need to both be "in the weeds" to make the code work, and also high enough up the ladder to make sure the various pieces are working together harmoniously. Even in larger teams, when systems are carved up into multiple isolated parts, any work that is completed without consideration for how the disparate systems will fit together will likely need to be reworked**.

Conclusion

Hopefully you've enjoyed this exploration of FSMs: what they are, why they are (sometimes) useful, and how thinking they're the only tool available can lead to some problematic designs. As always, if you have any thoughts or feedback, please let me know.