Designing Behavior

Learn to model a system from multiple perspectives and introduce logic and decision making.

In this article, we’ll specify the behavior of a mechanical egg timer and we’ll have to consider two distinct perspectives:

  • That of the user, who interacts with the egg timer by turning the dial forward or backward
  • That of the timer’s mechanical logic, which must keep track of time and, somehow, decide when to “ding”

Meet the egg timer

Lets start with the “happy path” flow for a mechanical egg timer:

  • User turns the dial forward to set a time
  • Timer begins ticking
  • User waits for time to elapse
  • Timer dings and stops ticking

A first pass might look like this:

The wind forward event is caused by the user, and the states (Stopped and Ticking) belong to the timer.

The time elapsed event is rather mysterious, though. How does the egg timer know that the time set by the user has elapsed?

The spec needs to sufficiently explain the behavior so that our collaborators can implement it. Assuming a magic time elapsed event doesn’t seem much more helpful than saying “build something that works”.

Lets try clarifying the spec so it explains how timer knows that the time has elapsed.

An explosion of states

We can specify the timer’s behavior in more detail by modeling the remaining time using states:

Here we’ve modeled the system in more detail: Instead of thinking of the user winding the timer forward an arbitrary amount, we consider each incremental turn as a separate wind forward one second event. And we’ve replaced the “timer magically knows when the time has elapsed” event with a more specific tick event that occurs every second (and is, presumably, easier for the mechanical engineers to implement).

While this model unambiguously defines the behavior we want, it isn’t great at concisely capturing that behavior. Specifying that the user should be able to wind the dial backward takes quite a bit of typing:

What’s worse, this verbose explosion of states does a poor job of communicating the essential behavior (which is the entire point of specification!)

Good luck convincing an engineer or other busy stakeholder at Egg Timers Incorporated to stay awake while you walk through every state of this spec.

The reason it’s boring is because the essential behavior of all the N Seconds Left states is identical: The timer is ticking and the user can move the dial forward or backward.

Having so many nearly identical states distracts from the states where the behavior truly is different (that is, the Stopped state, where the timer is silent and the user cannot turn the dial backward).

So how else can we precisely — but concisely — describe the egg timer’s behavior?

Simulating logic

A useful trick we can use here is to introduce a transient state. Unlike a regular state (where our system actually spends time), a transient state is purely notational — it lets us define our system’s internal logic, but without the hassle of dropping all the way down into code. (Think of it like a flowchart.)

We can capture the essence of the egg timer’s behavior by adding a single transient state, Done?:

By convention, transient states and the pseudo-events that lead out of them end with a question mark.

We can read this spec as: “If the user moves the dial forward or backward, or if the timer emits a tick event, the timer should move to either the Ticking or Stopped state based on whether or not there is time remaining”.

It’s worth nothing that the timer is never in the Done? state — it is always either Stopped or Ticking. But when you simulate the behavior by clicking on the diagram, it will end up waiting in the Done? transient state for you to choose one of the paths out.

That said, if your system does spend some time waiting for logic to run, you might want to model that explicitly with a regular state. A good example is when you send input to a remote server:

There’s a transient state that models the local validation (Okay To Send?) and a regular state (Loading) where the system waits for a response.

Whose events?

All interesting systems consist of multiple actors — people, machines, acts of God, etc. — and the art of designing the whole system’s behavior is knowing how to model these actors and their interactions with states, events, and transitions.

From the perspective of someone using the egg timer, there are only two things they can do: wind the timer forward or wind it backward. But there is a third event in our spec, tick, which is emitted by a mechanism within the timer itself.

Furthermore, there are two “pseudo-events”: time remaining? and no time remaining?, that correspond to instantaneous decisions made by the timer’s mechanical mechanism.

As you interactively sketch and model systems with, you’ll need to jump between perspectives. Sometimes you’ll wear the hat of the user, emitting events by interacting with a prototype UI. But other times you’ll need to emit events via the diagram, pretending to be a mechanical timer emitting tick events or a database backend accepting or rejecting inputs.

Further exercises

  • A mechanical engineer informs you that the egg timer’s internal mechanism needs the user turn the dial past the 10 second mark so that it has enough energy to begin ticking. Fork the egg timer spec and model this new change.