Our programs often use State Machines even though we might not even realise it.
How often do we have something called State and associated rules how states can change? Well there we most likely have a State Machine.
Jira Ticket example
Let’s take a Ticket in issue tracking tool Jira as an example of a State Machine. Each Ticket can have multiple states and states can change only following a set of rules according to Default workflow diagram.
Ticket can transition states following these rules:
- Open ticket cannot be Reopened.
- In Progress ticket cannot be Closed without first being Resolved.
- Resolved ticket cannot be put In Progress without first being Reopened.
- and so on…
Instead of writing all conditions here, it can be better expressed using the following diagram:
Image taken from Jira: Working with workflows
Show me the code
There are existing libraries for State Machine implementation in Swift, some of them very sophisticated and advanced. But often a simple solution is just enough…
A state machine is defined using
StateMachine protocol. Let’s have a closer look…
This is a type representing a State of a state machine. This will most likely be an
enum. It is
Hashable so it can be stored in
Set of allowed state transitions.
Accessor to current state of a state machine. Every state machine must have a state at all times.
This is the main magic behind our state machine: its state transition table. For each possible state, it defines what are the next states the state machine is allowed to transition to. It is basically code definition of the state diagram above.
Determines whether the transition to next state candidate is allowed from current state.
Performs the transition of a state machine to next state. It is marked as
mutating because it mutates the state.
Extension with default implementation
The extension provides default implementation of
canTransition(to:). By default does the expected: state transition is allowed when
stateTransitions allows it.
The example implementation is pretty straightforward.
enum Staterepresents all possible states of a ticket.
stateTransitionsis defined with all possible transitions.
transition(to:)performs the state transition.
- It changes value of a private variable.
- There is a
preconditionto check if the transition is valid. This implementation considers invalid state transition being a programmer’s error.
canTransition(to:)should always be consulted first before changing the state.
Ticket can transition states when mutable (defined as
mutating, it cannot be called on immutable ticket defined using
Like the article, got a comment or found an issue? Get in touch via Twitter .
Subscribe via RSS