State Driven Development for User Interfaces (Part 2: Finite State Machines)
Tags: state, redux, react, sdd
Published: 2018-02-04 12:11:04

---
title: "State Driven Development for User Interfaces (Part 2: Finite State Machines)"
published: true
description: A short series outlining the practice of placing the most importance on your application's state
tags: #state #redux #react #sdd
---

_Note: This post assumes a basic familiarity with the way Redux works, although the core concept doesn't really lose anything without that understanding. Still, it might be worth checking out [Explain Redux like I'm five](https://dev.to/hemanth/explain-redux-like-im-five) if you are scratching your head in the second section. I'll also be using React, but the idea being presented here doesn't require React._

In order to implement the technique discussed in [my previous post](https://dev.to/dnimmo/state-driven-development-for-user-interfaces-part-1-an-introduction-27f1), it's especially helpful to be able to think about our applications in terms of a `Finite State Machine`.

For anyone unfamiliar with FSMs, as the name suggests, they can only have a finite number of possible states, but crucially can only be in _one_ of those states at any given time.

Consider for example, a door. How many states could it be in? It probably initially looks something like this:

```
LOCKED
UNLOCKED
OPENED
CLOSED
```

That's definitely a finite list of possible states our door can be in, but you may have noticed that we've made a mistake here. Do we really need a separate state for `CLOSED` _and_ `UNLOCKED`? Well, if we're looking to be able to say that our door can only be in _one_ of a finite number of states, then I'd say we probably don't. We can assume that `CLOSED` means `UNLOCKED`, since we know our door can't (meaningfully) be `LOCKED` and `OPENED` at the same time. So perhaps our states should look more like this:

```
LOCKED
CLOSED
OPENED
```

Now we've figured out our states, we'd probably like to know how our door will transition from one to another, right?

Here's a very simple state transition diagram for our door: 

![Diagram showing LOCKED -> Unlock -> CLOSED -> Open -> OPENED transitions](https://thepracticaldev.s3.amazonaws.com/i/msad1wt8juebhkb216ss.png)

In this case, the `initial state` doesn't matter so much (by which I mean any of these states would have been fine as the initial state), but let's say that the initial state of our door is going to be `CLOSED`.

And, you know what, we don't _really_ care about the transitions that just go back to their previous state either, do we? They're all just showing actions that aren't available in the current state, after all: 

 ![Diagram showing LOCKED -> Unlock -> CLOSED -> Open -> OPENED transitions](https://thepracticaldev.s3.amazonaws.com/i/avtto0irobpxjze3s6gs.png)

Now, we don't really spend a _lot_ of time at work building virtual doors, but let's say that we think we've identified a gap in the market, and we were looking to fill it by building our door into a web application.

We've already done the first step: figuring out our states and our transitions. Now it's time for a little bit of code. 

## Enter Redux

Saying "Redux isn't necessary for this" is, of course, redundant. But since it just happens to be perfect for what we're trying to achieve here, that's what we'll be doing. So, we can take our diagram, and use that to write our `store` file: 

```
export
const actionTypes = {
  OPEN: 'OPEN',
  CLOSE: 'CLOSE',
  LOCK: 'LOCK',
  UNLOCK: 'UNLOCK',
};

export
const stateTypes = {
  OPENED: { 
    name: 'OPENED', 
    availableActions: [actionTypes.CLOSE] 
  },
  CLOSED: { 
    name: 'CLOSED', 
    availableActions: [actionTypes.OPEN, actionTypes.LOCK] 
  },
  LOCKED: { 
    name: 'LOCKED', 
    availableActions: [actionTypes.UNLOCK] 
  },
};

const initialState = {
  _stateType: stateTypes.CLOSED,
};

export
const open = 
  () => ({ 
    type: actionTypes.OPEN,  
  });

export
const close =
  () => ({ 
    type: actionTypes.CLOSE,  
  });

export
const lock =
  () => ({ 
    type: actionTypes.LOCK,  
  });

export
const unlock =
  () => ({ 
    type: actionTypes.UNLOCK,  
  });

const door =
  (state = initialState, action) => {
    const actionIsAllowed =
      state._stateType.availableActions.includes(action.type);

    if(!actionIsAllowed) return state;

    switch(action.type) {
      case actionTypes.OPEN: 
        return { _stateType: stateTypes.OPENED };

      case actionTypes.CLOSE:
      case actionTypes.UNLOCK:
        return { _stateType: stateTypes.CLOSED };

      case actionTypes.LOCK:
        return { _stateType: stateTypes.LOCKED };

      default: 
        return state;
    }
  };
  

export default door;
```

Now we have our `reducer`, which is a coded version of our state transition diagram. Did you notice how easy it was to go from the diagram to the code here? Of course, the level of complexity in this example is _very_ low, but I'm hoping you can see why we're finding this so useful. 

The only thing that's in here that's "unusual" is the use of `_stateType`, which you can see also contains a list of available actions in a given state. The usefulness of this might be questionable, but I believe that it offers both an extra level of documentation for the reader of this code, as well as a potential safety net against errors when transitioning from one state to another.

## Implementation

Wiring this together into a container to hold our door, it looks like this:

```
import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

import { 
  stateTypes,
  close as closeFunction,
  open as openFunction,
  lock as lockFunction,
  unlock as unlockFunction, 
} from './path/to/store';

import OpenedDoor from './path/to/opened_door';
import ClosedDoor from './path/to/closed_door';
import LockedDoor from './path/to/locked_door';

const Door = 
  ({ 
    _stateType, 
    open,
    close,
    lock,
    unlock,
  }) => {
    switch(_stateType) {
      case stateTypes.OPENED:
        return (
          <OpenedDoor 
            close={close} 
          />);

      case stateTypes.CLOSED: 
        return (
          <ClosedDoor 
            open={open} 
            lock={lock}
          />);

      case stateTypes.LOCKED:
        return (
          <LockedDoor 
            unlock={unlock}
          />);

      default: 
        return null;
    }
  };

const mapStateToProps = 
  ({ door }) => ({
    _stateType: door._stateType,
  });

const mapDispatchToProps =
  dispatch => 
    bindActionCreators(
      {
        open: openFunction,
        close: closeFunction,
        lock: lockFunction,
        unlock: unlockFunction,
      }, dispatch);

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(Door);
```

Essentially, containers are rendered in exactly the same way as `actions` are processed in our `reducer`; a switch statement on the `stateType` returns the correct child component for a given state.

And from here, we'll have individual stateless components for each of our "door" types (open/closed/locked), which will be rendered to the user depending on the state the door is in, and will only allow for actions that are available based on our original state transition diagram (go and double check; they should match up nicely).

It's worth noting that the fact that the actual rendering of components almost feels like an afterthought isn't a coincidence (so much so that I didn't even feel that _showing_ the code for the components themselves would add any value to this post, but you can view them [on Github](https://github.com/dnimmo/state-machine-example/tree/part-1) if you feel otherwise). Thinking about state above all else lends itself to easy planning, to the point where actually putting it together is really simple. This methodology really is all about promoting more thought up-front; although the benefits are more obvious in a more complicated application than our door. 

In the next part we'll look at how to expand this to be more usable in a real application, by introducing [a methodology for dealing with parallel state machines](https://dev.to/dnimmo/state-driven-development-for-user-interfaces-part-3-parallel-state-machines-2oja).