Modeling a Better Night’s Sleep: Building a White Noise Machine with State Machines

A presentation at Newcrafts in May 2024 in Paris, France by Laura Kalbag

Slide 1

Slide 1

Modelling a 
better night’s sleep

Building a white noise machine with state machines

Laura Kalbag - @LauraKalbag

Slide 2

Slide 2

Separation

I’ve been working in tech for 15 years with a variety of teams. I’ve worked in design, development, both managing projects and working for managers. And one of my biggest pet peeves is the separation created between our areas of expertise when there’s realistically so much overlap. So often we are doing bits of each others’ work; a designer makes decisions that impact engineering, engineers frequently make design decisions (including filling in missing details from mockups.) Project managers do the same! And we’re all constantly passing documents around with feedback and requirements.

Slide 3

Slide 3

And sure there’s better ways to communicate; processes we can employ, egos we can set aside. But sometimes we just need tools to help us get there faster. And because I’m all about uniting developers and designers, we’re going to talk about something that affects us all: managing your application logic.

Slide 4

Slide 4

Let’s start off with some issues we find around state management:

  • Complexity: the bigger the app, the harder it is to manage state. Even the smallest feature can introduce a lot of complexity.
  • Data flow: passing state between components can get complicated and hard to follow.
  • Concurrency: when different components are interacting with the same state simultaneously, you get into tricky situations.
  • Testing and debugging: the more states you have, the harder it is to isolate and reproduce state-specific issues. If you’ve used a lot of booleans for your state, you know what I mean!

Slide 5

Slide 5

Let’s be honest, a lot of the time, the sum of your app logic is essentially stored in the engineer’s head. (And it really isn’t easy to communicate the stuff that’s stored in your head!) (Especially if you’re out of office or get another job!)

Slide 6

Slide 6

So here’s my white noise machine app. I wanted to make a white noise machine after I got one to help soothe my dog’s anxiety during fireworks and thunderstorms And thinking about what my state situation might look like:

  • on/off
  • play audio/pause audio
  • white noise sounds: white noise! waves, fan
  • coloured lights: yellow, green, blue
  • volume up/volume down

This is already getting pretty complicated, so what tools am I going to recommend? (The clue is in the title of my talk!)

Slide 7

Slide 7

Finite state machine

Enter finite state machines. A finite state machine is a model that can only be in one state at a time. For example playing and paused are both states. And a state machine can change from one state to another in response to an input. A play event could be your event, or pause.

Slide 8

Slide 8

This icon (a circle with an arrow pointing away from it) is the initial state and it indicates which state the machine should start in. The arrow points to the initial state.

Slide 9

Slide 9

State machines are also an excellent visual representation of what your code should be doing. So I’m going to create a state machine for my white noise app!

Slide 10

Slide 10

State machines can be used anywhere in your stack.

Now despite the frontend-yness of my example, state machines can be used anywhere in your stack. And I’ll show you some more examples later.

Slide 11

Slide 11

Demo

Modelling the state machine. You can find my state machine link in the Resources section!

Slide 12

Slide 12

The actor model

Another concept that works really well with statecharts is the actor model where everything in the system is an actor. An actor can send and receive events and change its behaviour based on those events. So we can make our logic more modular and maintainable by breaking it into actors that communicate with each other.

Basically when each statechart is running, it is an actor.

Slide 13

Slide 13

Demo

Modelling the state machine. You can find my state machine link in the Resources section!

Slide 14

Slide 14

Statecharts can be used anywhere in your stack!

I said earlier that statecharts can be used anywhere in your stack. And now hopefully you can see the potential for state machines for your UI. And here’s some backend workflow statecharts.

Slide 15

Slide 15

Event-based actor

Here’s an event-based actor… It’s a common example of container environments where some of your services (aka actors) may not be exposed via a resource URI, and are accessible by submitting an event to the underlying container events manager.

This state machine represents a workflow for making a vet appointment. It starts in the “Idle” state, where it waits for a “MakeVetAppointment” event. When this event occurs, it transitions to the “MakeVetAppointmentState” state and triggers an action to make the appointment. Once the appointment is successfully made, it transitions back to the “Idle” state and stores the appointment information.

Slide 16

Slide 16

Patient onboarding

Here’s patient onboarding, where we might want to invoke three services (actors) simultaneously.

This state machine represents a patient onboarding process in a hospital or clinic. It helps guide the steps needed to onboard a new patient. The machine has different states that represent different stages of the onboarding process. The initial state is “Idle”, where the machine waits for a “NewPatientEvent” to be triggered. When the event is received, the machine moves to the “Onboard” state and stores the patient’s information. In the “Onboard” state, there are three sub-states: “StorePatient”, “AssignDoctor”, and “ScheduleAppt”. Each sub-state represents a specific task in the onboarding process. The “StorePatient” sub-state invokes a service called “StoreNewPatientInfo” to store the patient’s information. If the service is successful, the machine moves to the “AssignDoctor” sub-state. If there is an error, the machine goes to the “End” state. The “AssignDoctor” sub-state invokes a service called “AssignDoctor” to assign a doctor to the patient. If the service is successful, the machine moves to the “ScheduleAppt” sub-state. If there is an error, the machine goes to the “End” state. The “ScheduleAppt” sub-state invokes a service called “ScheduleAppt” to schedule an appointment for the patient. If the service is successful, the machine moves to the “Done” sub-state. If there is an error, the machine goes to the “End” state. Finally, when the onboarding process is completed, the machine moves to the “End” state, which represents the end of the process.

Slide 17

Slide 17

Credit check

And here is a serverless workflow where you need to integrate with an external microservice to perform a credit check.

This state machine represents a simple workflow for a credit checking application process. It shows the different states and events involved in the process. The states are represented by blue color, the “happy” path events are in green, alternative paths are in yellow, and “failure” events and states are in red. The workflow starts with the “CheckCredit” state, where a credit check microservice is invoked. After a delay of 15 minutes, if the credit check is not completed, the workflow moves to the “Timeout” state. If the credit check is completed successfully, the workflow moves to the “EvaluateDecision” state. Here, based on the credit score, the workflow either transitions to the “StartApplication” state if the score is above a certain threshold, or to the “RejectApplication” state if the score is below the threshold. In the “StartApplication” state, an application workflow is started, and in the “RejectApplication” state, a rejection email is sent. Finally, the workflow ends in the “End” state. This state machine demonstrates concepts like delays, invocations, guarded transitions, and different states and events in a credit checking application process.

Slide 18

Slide 18

Diagrams are great!

Through this demo you might start thinking “wow, this is easy to understand”, “Laura doesn’t even have to explain much”, “even Jim would understand this…” It’s because diagrams are great! There’s visual representation of code and clear communication, so it’s also easy to collaborate and easy to spot errors, which is great for documentation, and all this helps with better planning and organisation.

Slide 19

Slide 19

The benefits of statecharts

Statecharts provide all the benefits of diagrams but as executable code. Having your application logic be both visual and executable makes for living documentation and a logical source of truth. Everybody understands it, and it can be kept up to date.

Going back to the problems we have in software and development:

  • The modular and hierarchical structures in statecharts handle complexity better.
  • The explictness and clarity make complexity easier to understand.
  • The visual representation is great for internal documentation.
  • And we have a clear structure for testing and debugging.

Slide 20

Slide 20

Demo

Implementing the state machine. You can find my demo code link in the Resources section!

Slide 21

Slide 21

Do you always need a state machine?

Do you always need a state machine? No, especially if you have simple and linear logic or small and isolated components.

Slide 22

Slide 22

When do you need a state machine or statechart?

When do you need a state machine or statechart? The rest of the time… 😁 Complex systems, when you want make it easier to document, debug, and test, when you need to be able to communicate your app logic and share one source of truth with your team…

Slide 23

Slide 23

Everyone gets a better night’s sleep with state machines

Everyone gets a better night’s sleep with state machines.

Slide 24

Slide 24

Thank you!