From Blockchain to AWS to TVs – The New Stack
I’ve noticed that state machines are mentioned a bit more often than they are explained. Nevertheless, they represent a standard tool in the developer’s arsenal, albeit easier to understand conceptually than they are to actually implement in a neat and reusable way.
A state machine (sometimes finite state machine) is a model of states and transitions between those states.
Think about the seasons. If we wanted to convert a year into a state machine of seasons, we know that the name of the states would be “spring”, “summer”, “autumn/autumn” and “winter”, and the transition between them would normally be ” wait three months .”
If we were to put this into simple code, we would have to:
- Enumerate the seasons;
- Relate which season transitions to which season;
- Allow the seasons to pass on a method call;
- Decide on a season start.
Here is my overly simple C# code for this requirement:
The memorable thing here is the definition of the seasons using enumeration types, which turn what would otherwise be strings into first-class citizens of code:
public enum SeasonalState { Spring, Summer, Fall, Winter }
public enum Seasonal condition { Our, Summer, Autumn, Winter } |
Now this is easy because the seasons work in a cycle. So the transitions are the same: You just jump to the next season. In fact, senior developers may refuse to recognize this as a state machine at all, due to how limited it is. However, it achieves its mission. While the names of the methods and variables are written to reflect the domain (seasons) for ease of reading, note that if we invented a new season, only two lines would need to be changed. We will return to the implementation later.
We recognize that most things in the real world do not have definitive states that they enter and exit cleanly. On the other hand, things like can modeled in this way, should be.
The Blockchain Use Case
Is a blockchain a state machine? After all, this is where many people have first seen the term used lately. We know what a block represents: ownership of cryptocurrency and transfer between parties. It is a (rather inefficient) state machine with an infinite number of states, even if they are equal. It has a current state and it can only continue after a transaction is properly resolved. Ethereum seems to describe itself as a state machine, adding the user content as part of the state to make it a “smart chain.”
Speaking of user content in a state, there’s a small tweak we can make to the simple state machine code to make it a bit more useful overall. This change allows a simple observer to subscribe to an event:
So now when we run the code, we see the seasons from the statements of a totally unrealistic farmer:
Spring is here. Spread the fertilizer! Summer is here. Cut the hay! Autumn is here. Harvest time! Winter is here. Feed the cows! Spring is here. Spread the fertilizer! Summer is here. Cut the hay!
Our is here. Spread the fertilizer! Summer is here. Cut the high! Autumn is here. Harvest time! Winter is here. Feed the cows! Our is here. Spread the fertilizer! Summer is here. Cut the high! |
AWS and step functions
The other notable modern use of state machines is within AWS. Called Step Functions, they can be used for orchestration in the serverless world. This means that other Lambda functions can be triggered by the arrival of spring. What is interesting is the way they are represented in JSON:
{ “Comment”: “A Hello World example of Amazon State Language”, “StartAt”: “HelloWorld”, “States”: { “HelloWorld”: { “Type”: “Pass”, “Result”: “Hello World ” !”, “End”: true } } }
{ “Comment”: “A Hello World Example of Amazon State Language”, “Start at”: “Hello World”, “States”: { “Hello World”: { “Type”: “Send”, “Result”: “Hello World!”, “End”: genuine } } } |
There is only one state here, which appears to be both the initial state and self-terminating.
A typical state machine: television
Let’s look at another decent but much more typical state machine: a very basic TV.
Now, this isn’t a TV you have or want, but you know how it works. A large button on the front switches the TV on (to standby) and off again. When in standby, you can switch between channels with the remote control. We will ignore all the other things a TV must also have.
If we stay in C#, we now need two enumeration types: one for the commands and one for the states.
public enum TVStates {OFF, STANDBY, CHANNEL1, CHANNEL2} public enum TVCommands {TURN_ON, TURN_OFF, SWITCH_TO_1, SWITCH_TO_2, SWITCH_OFF}
public enum TV States {OF, WAIT, CHANNEL 1, CHANNEL2} public enum TV commands {TURN ON, TURN OFF, SWITCH_TO_1, SWITCH_TO_2, TURN OFF} |
We can already see that we need to focus on the transitions, not the states themselves.
Unlike the seasonal cycle, not all commands are valid from a given state. We can’t turn on the TV twice in a row from the big button on the front. If I’m already on CHANNEL1, switching to CHANNEL1 won’t do anything. So while configuring, we need to add eight “when in this state, let this command move to that state” lines:
You can add observers or “side effects”, as I did in the previous example. You can imagine that a timer could be started when a channel changes, so that if the viewer falls asleep in front of a Japanese monster rampage or a cowboy showdown, the TV will turn off; in short, the TV’s API may need to subscribe to some state transitions.
When running, you can see that the disallowed transitions are politely ignored:
TURN_ON: Now STANDBY SWITCH_TO_CHANNEL1: Now CHANNEL1 SWITCH_TO_CHANNEL2: Now CHANNEL2 SWITCH_OFF: Now STANDBY
TURN ON: Now WAIT SWITCH_TO_CHANNEL1: Now CHANNEL 1 SWITCH_TO_CHANNEL2: Now CHANNEL2 TURN OFF: Now WAIT |
Conclusion
After you’ve written a few state machines, you’ll be in a better position to use existing library versions – and you no doubt will. These need to be totally generalized, so it might look a bit strict if you haven’t rolled some of your own and nailed this important design pattern.
Feature image via Shutterstock.