
Why Developers Never Use State Machines (2011) - severine
https://www.skorks.com/2011/09/why-developers-never-use-state-machines/
======
s4vi0r
Traditional programming languages and imperative thinking don't lend
themselves to writing state machines, so its not really that surprising that
they're under utilized.

Its kind of frustrating constantly reading posts where people shit on
functional programm(ers|ing) for being too ivory tower-y or whatever, when its
kind of hard not to be when a lot of the older FP guys have spent the last
like 20-30 years going "yo this is dope you guys should really be doing this"
and getting largely ignored. State machines are super commonly used in
languages where you can (easily) construct ADTs and pattern match on them.

~~~
simonh
>the older FP guys have spent the last like 20-30 years going "yo this is dope
you guys should really be doing this" and getting largely ignored

I've not been ignoring them. I tried at least three different Haskell
tutorials and articles explaining how cool it is. The problem was the author
would show some code sand say 'see how easy it is to do this, and this, and
this!', but I'd look at the code and have no idea whatever what it was doing
or how it was doing it, and the guide/tutorial wouldn't tell me. After a few
tries, I just gave up.

Maybe there's a canonical newbie's tutorial that takes you through the shift
from imperative/procedural thinking?

~~~
oblio
Heh, very often their problem domain is also an issue.

"We're going to write a compiler in our shiny FP language".

"We're going to implement a Fourier transform".

Nah, thanks, could you show me instead how I can get the Employee record from
an XML file, stick it in a PostgreSQL database and also send it down the wire
through a REST API as JSON?

~~~
PeterisP
Haskell code for _that_ looks quite nice as well - however, it's less about a
language per se but rather about availability of libraries and how mature /
well-built their API is.

For quite a few FP languages the ecosystem is there and you can do all these
problem domains nicely, they just tend to be skipped in tutorials as they rely
on non-core third party libraries (sometimes with multiple nice but very
different alternatives). Perhaps a "batteries-included" stance of Ruby(+Rails)
and Python would simplify that, but it's more of a political issue.

~~~
oblio
> It's less about a language per se but rather about availability of libraries
> and how mature / well-built their API is.

In the real world, those matter just as much as the language. They usually
matter even more :)

Look at what Rust is doing - I think at least half of their effort is spent
towards building up a large collection of high quality, well maintained (i.e.
feature requests implemented, bugs fixed quickly) and well documented
libraries.

~~~
vbezhenar
I agree. For me what matters most is language implementation (compiler/VM
quality, GC quality, etc) and important libraries (and whether they are good).
Language itself is not very important. I can write boilerplate, but I can't
write GC implementation. So while I don't like Go language, for example, its
implementation is very good and I can live with it.

------
userbinator
_I would hazard a guess that there are decent state machine libraries for most
languages that you can use_

I think this is already part of the problem of complexity --- when I think
"state machine", what comes to mind is a loop and a switch with some gotos in
the cases. Definitely _not_ a library. If you think "I need to use a state
machine" and your next thought is "I need to find a library for that", then
IMHO you're definitely doing it wrong.

~~~
JoachimS
Agreed. When I worked on last years Advent of Code problems (amazingly good
problems btw) I ended up writing many solutions as small FSMs.

Typically you read a token, moved to a new position and then acted based on
the current state and the token, position. You don't need a library since the
code is just a few switch statements.

[https://adventofcode.com/2017](https://adventofcode.com/2017)

~~~
AstralStorm
And then everything ends up in Error state with no history. At least function
stack has stack traces...

~~~
zaarn
FSM's usually don't have error states, you tend to crash them first.

Though that is preventable, mostly because the code you run is inbetween
transitions and that will return very nice stack traces.

Otherwise, you don't need a trace of a state machine, the state you're in and
the current transition should tell you exactly where it's breaking.

If it doesn't, chances are you're breaking state machine definitions by
storing wildly complex state outside the machine.

------
IamNotAtWork
I really don't like state machines because if you need to add a new event,
each of the states need to be updated to handle that event. If you add a new
state, you have to figure out how to handle each of the transitions from other
states. So as your states grow, the maintenance on the developer's side grows
faster than linear.

Additionally, I find that I cannot understand how the program works without
actually drawing out the state machine diagram if I come across it the first
time, so there is a bit of a learning curve. It's also a nightmare to test
because of all of the states that need to be tested.

So in summary, not a fan. Like recursion... if it feels natural then use it,
but I don't go and try and turn stuff that isn't a SM into one or turn
something that can be done as loops into recursive function for fun.

~~~
taeric
For the life of me, I can't read your complaints as actual complaints, but
endorsements of the idea.

I haven't done it, yet, but I am tempted to make everyone I work with draft
out the state machine of everything we are working with in our systems. I'm
half convinced the worst bugs we have, are when folks didn't realize that the
change they were doing required modifications because of how far reaching they
were in the state of the system.

I take a simple vending machine as a good thought exercise. If you are just
changing the system that recognizes coins, you can easily localize your
changes. If you are changing the system that accepts coins...

~~~
candiodari
This.

How much of the anti-formalism attitude is about real difficulties of the
method, and how much is about "I don't know this method, so it must be bad".

Code, regardless of what it does, is a state machine. That does not change
whether you do it intentionally or not. And if you don't use state machine
design tools to design them ... then your state machine becomes a huge mess
with transitions going from everywhere to everywhere and very surprising
connections in many places (and most/all of those will be bugs, bugs that no
unit test ever is going to find).

Which seems to be acceptable for a lot of people.

------
RobLach
If you've ever do any game programming you'll be drowning in state machines.

~~~
signa11
network protocol as well, hell, any non-toy network application ends up
containing a state machine either implicitly or explicitly

~~~
escapecharacter
Gesture detection/interaction here. All state machines all the time.

~~~
eeks
Life cycle management, process synchronization, lockfree data structure, user-
space networking... I can't remember the last time I _didn 't_ use a state
machine.

------
niftich
State machines are not a first-class concept in most currently popular high-
level programming languages, so when you implement one, you're merely adhering
to a design pattern.

While a design pattern is a perfectly legitimate strategy to organize code,
it's a manual exercise with no help from the compiler: it's a workaround for
the language of choice not being high-level enough for the concepts you're
coding.

This is why frameworks useful: they intentionally constrain the problem space,
so one can focus on just unique behavior. When one reaches for a framework,
they're often using someone else's state machine. Game loops, GUI event loops,
or network protocol states are applications of this same pattern.

In some greenfield development, frameworks have a poor reputation for removing
developer control. This stems from a misunderstanding: that having a large
amount of choices in organizing code is a desirable goal. It very rarely is.

~~~
vinceguidry
In between design patterns and frameworks are the perfectly legitimate
solution of libraries, which is the most common approach I've seen.

------
aplorbust
"Why Developers Should Be Force-Fed State Machines"

[https://shopifyengineering.myshopify.com/blogs/engineering/1...](https://shopifyengineering.myshopify.com/blogs/engineering/17488160-why-
developers-should-be-force-fed-state-machines)

I always thought all computer science students had to take a compilers course,
or some course on theory of computation that required some level of competency
in lexing/scanning/tokenizing and parsing. This blog post appears to be
directed at "web application developers" who lack "awareness about state
machines".

~~~
mikekchar
Quite a lot of software developers were never CS students. In fact in some
industries engineers are very much desired as programmers. In others, math and
physics majors are desirable. And even when we exhaust all of those, I don't
think there is any need to look down our noses at those who took an
apprenticeship style approach to the industry. In fact, in my career I have
met many CS graduates who dismissed grammars and automata as irrelevant and
insisted on writing that parser for a context sensitive language using regular
expressions and about 400 global variables (and they still can't understand
why it doesn't always work). Besides some of us "web application developers"
actually _have_ CS degrees and have worked in half a dozen other industries
besides "web application development". Programming is programming and a
programmer is a programmer. There's a lot to learn and you have to stay humble
your whole career. Not everybody manages it easily.

~~~
noir_lord
Very nicely put.

I've worked with lots of programmers over the years and a CS degree has been a
very poor indicator of their ability to program in the large.

------
theatrus2
Developers use state machines a lot more than they would admit to. Often code
would be more readable if the state machine was succinctly defined.

~~~
nathanyo
There's a lot of truth to this statement in my experience. I just finished
rewriting my homework for my operating systems course and the first version
looks awful compared to when I rewrote a chunk of it as a state machine

------
notacoward
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.

~~~
bsenftner
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.

------
cbetti
One thing formal state machines make difficult is component reuse.

Let's say you have a music playback control component you wish to reuse across
a feature rich player, as well as a mini playback controller.

You COULD just use the full state machine to power the mini player, but most
of the transitions would be unused. It would be unclear to the next maintainer
which aspects were needed for each use case, thus making the state machine
brittle.

Instead, you can write an independent playback progress/state class, and reuse
it in both players via composition and proper layering of functionality.

By hiding the playback state from the rest of the player and exposing control
of it's state via an interface, you've gained functional reuse.

Reapply the same pattern for all components of your players and you'll find
that your product is safer to change and easier to understand than if you had
built a complicated formal state machine covering all possible music player
use cases.

~~~
bsenftner
Ah... your "independent playback progress/state class" is another state
machine, just better with an architecture that suits your use case. "Full
state machine" is a misnomer and common misunderstanding of the power of state
machines. Any state machine bordering on complexity that is hard to manage can
be broken into multiple smaller, easier to grasp and manage state machines.
And state machines transparently integrate with functional programming, so any
ideas contrary to that is yet another misunderstanding of them.

~~~
cbetti
I wouldn't consider this class a state machine in the sense described in the
paper.

Any class managing state exclusively is an implicit state machine, no?

------
dwarman
I'll echo the observation: datacomms protocol parsing and generation are
nothing but state machines.I started in that domain back in 1973 or so, and
some configurations - statistical multiplexors for example - may be running
upwards of 34 FSM's concurrently and independently. And that with a mix of
multiple instances of one protocol. So I developed a cooperative multitasking
pattern that ran on a virtual OS scheduler. Indeed in some systems it was the
real OS. State variable is a function pointer to a function that returns its
own protoype function pointer. Arguments include event, plus data plus state
context. Supports submachines too. Still using it. No switching complex stack
contexts, runs fast.

------
sytse
There was a reference to a Shopify blog post that 404s, the new url is
[https://shopifyengineering.myshopify.com/blogs/engineering/1...](https://shopifyengineering.myshopify.com/blogs/engineering/17488160-why-
developers-should-be-force-fed-state-machines)

------
tanilama
State machine is useful when it is useful. I can see for certain string
matching problem, internal management of certain data structure, it is going
to be a handy improvement.

However, specifically in web development, it is discouraged because the nature
of the application itself. Think hard how states are managed in a typical
service, the real states live in a DB. Which makes state machine less useful
because the ground truth is stored elsewhere, and should be updated by DB's
own primitives. And in a distributed settings, failure is something you have
to put into consideration. Making your service stateful is a red herring that
brings all kinds of operational troubles. That is why the dominant approach
people seems to agree upon is to keep application stateless while delegate all
dirty work to DB.

So realistically I think state machine is useful to write certain helper
routines in a non-persistent, single-thread scenario, for the ease of
reasoning, but really should be limited within the lifecycle of a single API
call.

~~~
mixmastamyk
Would like to read more on this subject if anyone knows any resources.

------
cimmanom
Isn't one component of this that so many people develop for web now? And that
HTTP is inherently stateless.

That means we have to resort to hacks to store state (databases, cookies) -
and like most hacks, those are fragile (such as assuming a single instance of
state and then breaking when the user opens another copy of the site in a
tab).

With the rise of single page apps, there's a more coherent concept of state on
the front end, but that doesn't fix the fragility of the server side portions.

~~~
naasking
> That means we have to resort to hacks to store state (databases, cookies) -
> and like most hacks, those are fragile (such as assuming a single instance
> of state and then breaking when the user opens another copy of the site in a
> tab).

In principle, there's nothing fragile about the types of state you describe,
but most web frameworks don't impose enough restrictions to ensure this state
is used correctly [1].

[1] something like this would work, but it's not the only option:
[http://cs.brown.edu/~sk/Publications/Papers/Published/mk-
int...](http://cs.brown.edu/~sk/Publications/Papers/Published/mk-int-safe-
state-web/)

------
vortico
You could even go as far as saying that a class in some forms is a state
machine. Networking is a huge application of state machines. Microcontrollers
usually have a small state and step through a switch statement in an infinite
loop. OpenGL is a state machine. If you write a state machine, it's easier to
implement it "perfectly" than other methods, and other parts of your program
are able to interact with it in more straightforward ways.

------
ggambetta
I rarely (if ever) use state machines explicitly, but I do use them relatively
frequently to reason about the behaviour of a system. A paper tool rather than
the way I actually write the code. I use flow charts and sequence diagrams in
a similar way.

------
acrive
The state machine is very near at Design by contract pattern. There are
states, preconditions and other stuff. The question now will be "Why
developers never use design by contract pattern?" :)

[https://github.com/nhatminhle/cofoja](https://github.com/nhatminhle/cofoja)
for example

~~~
AstralStorm
Design by contact is a lot more general. You can have preconditions and
postconditions in stateless code. And statelessness is the best way to handle
concurrency. When stateful and concurrent, you get to handle outdated requests
intelligently and with as little blocking as possible.

------
housel
One of my go-to interview questions is "Can you tell me about a time when
you've used an explicitly-modeled state machine in your programming?" Our
work, heavy in embedded devices, network protocols, and parsing, is so full of
state machines that I wouldn't want to hire someone who wasn't comfortable
using them.

~~~
dominotw
Is it pretty hard to pick it up for an average programmer?

~~~
Sylos
Nah, not at all.

It basically just means that you define states for your program to be in and
you define from what state to what other state your program can go to under
what conditions.

For example, let's say you have a program that takes user input and once
everything is entered correctly, then you move on to the next thing.

That would mean you have a state "user_input" (or whatever you want to call
it). Then you'd have a event "User clicks OK-button", with which you'd do a
state transition. And then there's two possible state transitions, one which
loops back onto user_input, for when the user enters something that's not
correct, and one that points to the state of that next thing, with a condition
of the user input being correct.

You could also directly specify here what "correct" user input looks like.
That's your choice. It's a design tool, use it to whatever depth you need it.

There's a relatively intuitive notation standard, which you'll want to learn,
as writing it all down is what gets you to actually think through all the
states, events and conditions that there are.

Implementation-wise, you'll usually have a variable that holds your state and
then methods to do state transitions. You can also implement a check into
those methods to ensure you're in a state that's allowed to transition to the
state that this method transitions to.

------
grzm
Discussed at the time (over 90 comments):

[https://news.ycombinator.com/item?id=2949543](https://news.ycombinator.com/item?id=2949543)

------
aj7
Of course developers whose last experience with state machines was in a
college course won’t use them. Just read some of the comments below the
article on storks.com. Labview developers use state machines extensively,
because the implementation is graphical, beautiful, and prevents loose ends.

~~~
planteen
I used to do VHDL for FPGAs, where you basically have to use state machines.
LabView is that way too, being a dataflow language. But I don't know how much
LabView I've seen that I would call beautiful. Maybe if one considers
spaghetti beautiful. ;)

------
sfilargi
Erlang OTP’s gen_fsm and gen_statem are great for implementing state machines.

Mind you however, the immutable nature of variables really helps.

------
dis-sys
Try consensus libraries widely used in modern distributed systems, whether it
is paxos or raft based, just pick your favourite one, both are heavily based
on the concept of state machine.

------
liveoneggs
[http://erlang.org/doc/man/gen_statem.html](http://erlang.org/doc/man/gen_statem.html)

------
rxhernandez
> I am the only kind of developer there is and so therefore I will speak with
> authority as to what all developers do.

I use state machines regularly when producing performance statistics where I
need to individually isolate many history dependent outcomes in a large sample
space. I tried doing it without them and ended up with unreadable and thus
unmaintainable buggy code. Never again.

------
ncmncm
I use state machines all the damn time. Am I, then, no developer?

Maybe you meant to say that only competent developers use state machines. But
that would place you outside their august company, leaving us little reason to
credit your observation. In that world, the absence of state machines in one's
code would reliably indicate incompetence.

But in fact, by definition, there is no computer program on God's green Earth
that is not a state machine. Programming languages were created specifically
to make the state machines they compile down to look more intuitive and less
like, you know, state machines.

So the observation is really that our programs usually look the way they were
intended to look, except when we abuse our language in pursuit of performance,
elegance, or other consensual delusion.

------
moscovium
We tend to use state machines for massively asynchronous operations like order
management (with days between updates), as well as a home-built library for
handling the task. It's incredibly fault tolerant and offers really easy
abstraction and automation.

------
danmaz74
Using (explicit) state machines in Rails is so easy, thanks to the gem of the
same name(1), that we use them very often, with good results. I think that
ease of setting them up and integrating them in whatever framework/language
you use is a very important factor in their adoption.

1 current version:
[https://github.com/pluginaweek/state_machine](https://github.com/pluginaweek/state_machine)

1a original unmaintained version:
[https://github.com/pluginaweek/state_machine](https://github.com/pluginaweek/state_machine)

~~~
jrimbault
[https://github.com/state-machines/state_machines](https://github.com/state-
machines/state_machines)

~~~
danmaz74
Thanks for the correction, I pasted the same link twice - can't edit :(

~~~
jrimbault
I put the link when I saw the one hour mark ;)

 _I spent too much time on HN today_

------
lupin3
One of the most refreshing experience I have had recently is to map Websockets
to some finite state machine implemented on an actor model (namely Akka FSM):
straightforward and fitting together naturally.

------
thinkloop
Fast forward 8 years and everyone on the front end is using state machines
with the rise of react/redux et al.

~~~
ricardobeat
A reducer store is not a state machine since both the transitions and states
are loosely defined. That said, at this point I think it's actually better for
UI, despite the verbosity and lack of formal correctness.

~~~
acemarke
It's also worth noting that you can absolutely _use_ state machines to
implement your reducer logic :)

------
lph
Saying that developers "don't use" state machines just because code isn't
littered with things like instantiations of machine and state classes is an
interesting point, but kind of glib. I use state machines all the time as an
abstraction to reason about programs.

------
nwatson
State machines are essential for a lot of programming tasks -- I wish they
were more explicit more often, because there always is an implicit state
machine lurking in there somewhere, and code would be cleaner with the state
machine made explicit.

For example ...

I was brought on to work at a startup a few years ago by an old-time
acquaintance that was CEO of a startup ... the company's proposed product
sounded interesting, and I believed in her skills and background and had
decent rapport with her. I was wary of the VP Engineering and a few others,
but it was to be my first post-move-out-of-SF-Bay-Area remote startup job and
I thought I could make it work.

I show up in Santa Clara, CA to make sure I really want to do this ... and
after joining we spend the next few days going over architecture,
implementation-so-far, etc. Part of the product's job is to discover and
categorize servers and networking devices, the basic software deployed on
them, etc. Apparently this aspect has been in design/implementation for
several months, but it's not working very well, and the problem and approach
aren't articulated very well. I have a chance to look at the code a bit.

I eat lunch with the CEO and she asks me how I'd approach the problem, and I
advocate breaking everything down into state machines with well-defined
transitions ... both for interacting with the environment, and for storing
info in the back end -- there's ample opportunity for things to go wrong, to
require retries, etc., and tracking these interactions with state machines
makes it much easier to efficiently and quickly deal with the environment and
back end in asynchronous fashion, and to separate different levels of
discovery (network / IP; finding credentials that work; OS determination;
software inventory; storage inventory; etc.) much easier.

In the next day's architecture discussion I then hear the VP Engineering use a
few of my words and draw a few poorly formulated diagrams that don't do the
task much justice ... it's apparent the CEO has discussed the problem with him
and urged a new look. I had to start work on my piece so I didn't follow their
developments much, but I heard later they actually purchased and licensed for
significant money a "finite state machine package" of some kind. All they
needed were ENUMs, (preferably async-result) functions to try something out,
and then transitions between enums based on the results. That discovery code
was always buggy, never did work right.

That was one of many fiascos. There were so many other fiascos, and they all
cost me lots of sleep, some of my sanity, and some self-respect. I lasted
almost three years there (some early players were pushed out but the product
never really got better). I would have been happier quitting the first week,
or better yet never joining.

------
greenleafjacob
Erlang stands out for me as having a state machine library in the standard
library (gen_fsm).

~~~
liveoneggs
now gen_statem

------
AstralStorm
A major problem with any state machine is that they tend to fall apart or
become major bottlenecks if concurrency is required...

It is still shared state, a thing to minimize. Usually message passing
(current buzzword: reactive) approaches work much better.

~~~
dragonwriter
> A major problem with any state machine is that they tend to fall apart or
> become major bottlenecks if concurrency is required...

One of the classic ways of architectural a concurrent system is as a
collection of sequential processes implementing message processing loops as
state machines.

If you mean that state machines can't deal with internal concurrency, that's
not true either. Leaving out concerns about unmanaged state (mutable data not
reflected in the state of the machine), a state machine provides a clear
framework for managing concurrency:

(1) an unlimited number of events that produce self-transitions can be
processed simultaneously;

(2) an event that would be processed the same in the start and end states of
all currently running events and whose end state would not alter the
processing of any currently running event can be processed concurrently,

(3) an event that would not be valid in the end state of any currently running
event is invalid,

(4) any other event cannot be run concurrently, blocks new events entering
processing, and must be evaluated for validity after each running event
completes (it may become either runnable or invalid).

The last is a kind of bottleneck, but it's usually not introduced by the state
machine so much as a feature of the domain.

------
kabes
But most developers do write regular expressions, which are also finite state
machines.

------
ssoft
may be some of developers don't know this technique and more evident that they
never tried to work with end state machines. I am using state machine long
time and made my own script player for SM, unlike to others SM i am using it
in different implementation from web till equipment automation.
[https://github.com/series6147/ProcessPlayer-state-
machine](https://github.com/series6147/ProcessPlayer-state-machine)

------
PSeitz
I use a state machine for text

[https://github.com/BurntSushi/fst](https://github.com/BurntSushi/fst)

------
s_m_t
I don't think I've ever programmed anything more than a hundred lines
_without_ a state machine...

------
CarVac
I use state machines in UI.

------
nailer
Can't read the article as site is down but: fear of the unknown, along with
some of the unnecessarily complex language around the topic.

I got over both of these and now use state machines in production where they
make sense as a model.

~~~
jwilk
Archived copy: [https://archive.is/3v9Gm](https://archive.is/3v9Gm)

------
tonylinn80
lol, interesting read. I used to work on a graphics project with a state
machine at its core, and user actions are defined to trigger state transitions

------
mmilano
Ads that auto pay audio on a developer blog, really?

~~~
forgotmypw
Disable JavaScript, problem solved.

Bonus: Pages written by developers who don't know/care about graceful
degradation appear blank, so you don't have to waste time reading them.

