States and State Machines
Using state machines to define behaviors and state transitions — explained with dating apps
What’s a state?
In information technology and computer science, a system is described as stateful if it is designed to remember preceding events or user interactions; the remembered information is called the state of the system.
A system’s states are often defined by the aggregation of behaviors its users do. States are important because it’s a more systematic way of verifying whether certain behaviors at certain states are valid or not.
States of a traffic light
Consider a traffic light as an example. If it’s been green, drivers and passengers expect to see yellow — not red — next. When it turns yellow, they’d expect red and not green. So the states here are simple:
Green -> Yellow -> Red
Follow the arrows (aka the allowed transitions of states) and your traffic light’s good to go.
States of the matches in dating apps
Now let’s take a dating app as a more complicated example, imagine that we’re building an app for people to “match” online. Let’s say we have the algorithms ready and we need to start writing the logics behind the matches that pop up on our users’ apps.
Let’s define an entity match first to represent the match between two people. There are several states for a match we should take into consideration if we were to design it.
We need the states so that people won’t see unexpected behaviors such as a random, not-matched person showing up on the screen saying hello.
My thought process:
- First of all, a match has to be created, meaning a certain set of algorithms has to select two people ready for a match. Of course the algorithms need to make sure beforehand that they’re both up for a match, fit each other’s preferences, not banned, etc.
- Then, this match could become either pending (waiting for another person’s swipe) or failed depending on the first user’s action. If the user swipes right (which means “I like you” in dating apps’ terms), the state jumps from created to pending. If the user swipes left (meaning “I don’t like you”), the state changes to failed.
- Then if both people like each other, it goes from pending to matched.
- Either of the person in a match could also “unmatch” a match, bringing the state to unmatched.
- I think I got all the changes of states covered. But are these all? Hmm… isn’t there’s a paid feature called “rewind” which allows you to go back and swipe again? What should we do with this?
How do we ensure that we’ve included all changes? If so how do we program it?
What’s a state machine?
A methodology for modeling the behavior of an entity with an established lifecycle
When building state-oriented systems, state machines are useful to help us better determine the complicated transitions and triggers.
Finite state machines (FSM)
It is an abstract machine that can be in exactly one of a finite number of states at any given time. The FSM can change from one state to another in response to some inputs; the change from one state to another is called a transition. An FSM is defined by a list of its states, its initial state, and the inputs that trigger each transition.
Let’s carry on with our dating app example. If we create a state diagram from the logics behind a match, it looks somewhat like this:
* Different methods can be taken by different users involved: either of the matched customers, or the dating app (platform builder / company).
It has a finite number of states, modeling all behaviors within a match’s lifecycle. To build a state machine, we just have to follow the lines and see how the entity responds to various behaviors.
Why should I use a state machine?
Okay now I know that the state diagram is really helpful, yet still why should I use a state machine when I’m writing my code?
From the same example, let’s take a look at some simplified code before and after a state machine’s involved.
Before using a state machine
You can spot a lot of
After using a state machine
ChangeState method take care of state transitions using
StateTransition type. All other methods can now focus on the logics of handling the match.
What more can I do?
Just to name a few:
- For now we assume that the “Rewind” methods are good enough for frontend interfaces to call. A more delicate way of dealing with methods should be to check if the match is recorded — and if so, is it liked or disliked — and then decide which command to use. Instead of letting the UI make the judgement (and risk it being wrong), it’s more suggested that we handle it in the
- If the state transitions get too complicated, try using a matrix with axis of current states and commands. The data in the matrix can be the updated states. This way the code becomes more readable.
So why use a state machine? Because considering the state-changing events (aka the important behaviors of an entity), it better models a system. Mostly everything else can be solved with basic CRUD methods. Also it makes your code more readable and maintainable.
When it comes to building APIs, don’t design them only based on the requests product managers make. Design APIs (at least minimum APIs) for your entity with the critical behaviors and transitions — states — in mind.
Richard Clayton - Use State Machines!
Finite State Machines (FSM, or in the context of this post, simply "State Machines") are a methodology for modeling the…
A finite-state machine ( FSM) or finite-state automaton ( FSA, plural: automata), finite automaton, or simply a state…