State machines must be taught equally as every other design pattern in programming. Interestingly, I started seeing state machines everywhere once I found this concept. Especially in the development of user interfaces where we have to manage a lot of states. But what is a state machine? The mathematical explanation is that the state machine is a model of computation. The non-mathematical (my description) is that the state machine is a box that keeps your state and changes it based on input and current value.
There are different types of state machines. The one that we are interested in is called a finite state machine. As the name suggests, it has a limited number of possible states. Think about a map of your app's conditions and strict lines between the different values.
To illustrate the concept, we will write software for an elevator. Our elevator is a simple one and can be in the following states: "idle", "moving", and "broken".
So, this is a finite number (3) of possible states. We can also define the transitions from one state to another:
idle --- move --> moving
moving --- stop --> idle
moving --- error --> broken
Here we can see one of the most significant benefits - if we implement the machine correctly, it will prevent wrong transitions. For example, we can't go from "idle" to a "stop" state or from "move" directly to "idle". Here is how this looks like in JavaScript:
function createEscalator() {
let currentState = 'idle';
const transitions = {
idle: {
move: () => {
currentState = 'moving';
}
},
moving: {
stop: () => {
currentState = 'idle';
},
error: () => {
currentState = 'broken';
}
},
broken: {}
}
return (action) => {
if (transitions[currentState][action]) {
transitions[currentState][action]();
} else {
console.warn(
`"${action}" is forbidden while in "${currentState}" state.`
)
}
}
}
The API of our machine is a single function that accepts an action. Internally the machine checks if the action makes sense in the context of the current state. If not, it does nothing and prints a warning message.
const escalator = createEscalator();
escalator('move'); // success
escalator('move'); // "move" is forbidden while in "moving" state.
escalator('stop'); // success
escalator('move'); // success
escalator('error'); // success
escalator('stop'); // "stop" is forbidden while in "broken" state.
Notice that we have no transitions if the machine falls into a "broken" state. We have to restart the machine, so it starts working again.