A Newborn Baby as a Finite State Machine, Part 3

In the previous post we created a grid of states, triggers, and transitions. This is a great format to transcribe to a computer, such as your automated test suite. However, it is not easy for humans to reason about or to onboard someone on how a newborn baby works. Fortunately we can easily translate this into a Finite State Machine diagram using a tool like Draw.io.

As you can see, even with our simplifications a newborn baby is quite a complex state machine. I would imagine, if using TDD in isolation, we are all but guaranteed to miss some transitions. But despite the complexity we are able to easily account for all scenarios through this exercise. As a bonus we can also manually trace through any flow with this diagram, allowing us to perform sanity checks.

Another potential benefit beyond performing TDD in isolation is that we don’t need an overabundance of integration or end to end tests for the different flows, or series of transitions. Using a structured approach of triggers, transitions, and states mathematically guarantees that any combination of flows can work, assuming each transition has been unit tested.

One thing we did not cover was side effects. For example the baby may smile when you touch her but it does not affect her overall state. Side effects are useful to annotate and know about but are not necessary to effectively model the program.

I hope this demonstrates how we can tackle complex programs by modeling them as finite state machines.

A Newborn Baby as a Finite State Machine, Part 2

In the previous post I introduced why modeling software as a Finite State Machine can be useful and used a newborn baby as an example. This post will fill in the transitions for the baby.

I realize I missed two key triggers, hopefully this does not reflect on my real-life parenting ability. Feeding the baby and changing the diaper should have an impact on the state of a newborn, so let’s include those. That gives us the following grid of states and triggers:

Quiet Alert Active Alert Crying Drowsiness Quiet Sleep Active Sleep
Hunger
Dirty Diaper
Lack of comfort
30 min interval
Sudden light/noise
Physical Touch
Feed
Change Diaper

Let’s fill in more of the obvious transitions:

Quiet Alert Active Alert Crying Drowsiness Quiet Sleep Active Sleep
Hunger Crying Crying Crying Crying Crying Crying
Dirty Diaper Crying Crying Crying Crying Crying Crying
Lack of comfort Crying Crying Crying Crying Crying Crying
Time passes Active Alert Drowsiness Drowsiness if was asleep, Quiet Sleep; else Active Alert Drowsiness Quiet Sleep
Sudden light/noise
Physical Touch
Feed
Change Diaper

For simplicity’s sake let’s assume that a baby will always immediately cry when an unhappy event occurs. This is a human being and we cannot expect a program to fully represent the nuances of even a newborn, so this is good enough for now. It is common to need to simplify things for the sake of understanding the program, in any case. It is valuable to simplify the unimportant details for the sake of the important ones.

Next let’s look at what happens as time passes:

Quiet Alert Active Alert Crying Drowsiness Quiet Sleep Active Sleep
Hunger Crying Crying Crying Crying Crying Crying
Dirty Diaper Crying Crying Crying Crying Crying Crying
Lack of comfort Crying Crying Crying Crying Crying Crying
Time passes Active Alert Drowsiness Drowsiness if was asleep, Quiet Alert
else Quiet Sleep
Active Sleep Quiet Sleep
Sudden light/noise
Physical Touch
Feed
Change Diaper

We are saying that a baby will start quiet, become quite active, and then tire herself out into drowsiness until falling asleep, again a simplification. The final simplification we have here is that a baby will get tired if she cries enough without any intervention (not recommended in real life). Note that we put our first conditional transition, when the baby is Drowsy. The baby can be drowsy waking up or falling asleep so we need to know in which “direction” the baby is going to make a decision. Too many conditional transitions can indicate that we need to refactor our States to be clearer. In this case we are fine for now.

Next, let’s cover what I would categorize as the “crying solving” triggers. Most parents are familiar with this checklist of things to check when a baby is crying:

Quiet Alert Active Alert Crying Drowsiness Quiet Sleep Active Sleep
Hunger Crying Crying Crying Crying Crying Crying
Dirty Diaper Crying Crying Crying Crying Crying Crying
Lack of comfort Crying Crying Crying Crying Crying Crying
Time passes Active Alert Drowsiness Drowsiness if was asleep, Quiet Alert
else Quiet Sleep
Active Sleep Quiet Sleep
Sudden light/noise
Physical Touch Quiet Alert Active Alert if discomfort, Quiet Alert
else Crying
Drowsiness Quiet Sleep Active Sleep
Feed Quiet Alert Active Alert if hungry, Quiet Alert
else Crying
Drowsiness Drowsiness Drowsiness
Change Diaper Quiet Alert Active Alert if dirty diaper, Quiet Alert
else Crying
Drowsiness Drowsiness Drowsiness

We added more conditional transitions as the baby could be crying for different reasons. Note that physical touch does not normally wake the baby, but feeding and changing does. We may not have known this when we first took her home, but after being around her we now know how she will respond. This goes back to ensuring you gain the domain knowledge to answer these questions. If you don’t know up front, that is fine. The willingness and ability to find answers or to make assumptions and move on is one thing that separates efficiencers from average software developers.

Finally let’s fill in that last trigger:

Quiet Alert Active Alert Crying Drowsiness Quiet Sleep Active Sleep
Hunger Crying Crying Crying Crying Crying Crying
Dirty Diaper Crying Crying Crying Crying Crying Crying
Lack of comfort Crying Crying Crying Crying Crying Crying
Time passes Active Alert Drowsiness Drowsiness if was asleep, Quiet Alert
else Quiet Sleep
Active Sleep Quiet Sleep
Sudden light/noise Active Alert Active Alert Crying Active Alert Drowsiness Drowsiness
Physical Touch Quiet Alert Active Alert if discomfort, Quiet Alert
else Crying
Drowsiness Quiet Sleep Active Sleep
Feed Quiet Alert Active Alert if hungry, Quiet Alert
else Crying
Drowsiness Drowsiness Drowsiness
Change Diaper Quiet Alert Active Alert if dirty diaper, Quiet Alert
else Crying
Drowsiness Drowsiness Drowsiness

We can see from observing the baby for a while that any sudden noise or light will “jump start” the baby into an active alert state in most cases, unless she is crying or asleep.

This is a great format to transcribe to a computer, such as your automated test suite. However, it is not easy for humans to reason about or to onboard someone how a newborn baby works. In the next post we will see the resulting diagram that we can use to help us and our coworkers reason about newborns.

A Newborn Baby as a Finite State Machine, Part 1

TDD is great but sometimes I need an extra oomph into my design to help model a non-trivial problem. I find that modeling things as finite state machines help me to achieve this.

A finite state machine is a system where a set of inputs, called triggers, can cause the system to transition from one state of being to another state of being.

Why is this a useful way to model behavior?

  • It constrains me to think in terms of a limited set of abstractions: triggers, states, transitions and side effects.
  • It exposes edge cases I  may not have thought of through pure TDD.
  • It frees from me from thinking about things as sequential series of events, which other models such as Flowcharts can sometimes trap us into doing.

Before I model the state machine I ensure I understand the domain well enough to know the potential states and triggers. A state can be one value (like an enum) or a combination of values. A trigger can be any event, user action, or time passing. Here are the steps I usually take:

  1. I start by making a grid out of these states and triggers, then filling in the transitions (destination State) and any side effects.
  2. Then I diagram the state machine visually using Draw.io or similar tool so that my pair partner or other devs can easily understand the solution being developed. I try not to underestimate the cost of knowledge transfer on a team.
  3. Finally, I test-drive out the functionality in the code itself. Even though I modeled the scenarios ahead of time, this let’s me flesh out those nitty-gritty details, like what the triggers look like, the surface area of the state machine, how it needs to fit into the codebase, etc.

Let’s take an example. I just had a beautiful baby girl, so let’s use a newborn baby as a state machine. A book I am reading, The New Father, says that there are 6 states to a newborn baby: Quiet Alert, Active Alert, Crying, Drowsiness, Quiet Sleep, Active Sleep.

Transitions are a bit trickier and require us to infer a bit, as it will be with most problems we are solving for a customer. Crying is a (well known) state and all parents likely know that babies cry due to a few things: they are hungry, they have a dirty diaper, and they need comfort. The latter covers  range of comfort needs, like temperature change and parental affection but I lumped them together for simplicity. From the book we know that Quiet Sleep and Active Sleep switch every 30 minutes so time passing is another trigger. Other triggers may include sudden light or noise and physical contact. Also note that transitions can be both conditional (only happens some of the time based on trigger context) and unconditional (will always happen when the trigger occurs).

So now we have a grid we can setup:

Quiet Alert Active Alert Crying Drowsiness Quiet Sleep Active Sleep
Hunger
Dirty Diaper
Lack of comfort
30 min interval
Sudden light/noise
Physical Touch

In the next post in the series we will fill in the transitions and diagram the machine.