A simple on-off state machine

I’ll tell you my story, maybe is yours too …

So it’s a great day at my workplace and I start coding an app that seems pretty simple.

Time passes, I get some tasks done and, at some point, the application starts getting messy.

I solve the problem by making some tricks because I’m quite smart and experienced developer 😉.

But, I start feeling dirty and sometimes astonished about how that simple idea, I had in my mind, is getting so complex and verbose to map to code. I think there is no one-to-one relationship between my mindmap and the code, it seems like a one-to-many relationship.

I’m the creator. I know how things work and this is not worrying me so much, because I do my best to write understandable and readable code.

After that, the app starts getting bigger and now I have to work with a colleague to speed things up.

Right now my colleague has many questions because he doesn’t know how the f*ck the app works! and what’s the idea behind it. I care about his health and I take the time to explain him the code. I’m a kind person I don’t want to make him waste that time 😅.

Sometime later I’m assigned to other app and, right now, I can understand the pain it was to my dear colleague to understand my code because I have to figure out how the cr*p this new UI code works.

Some months ago I’m reassigned to the first app for solving a bug, and you know, I should figure out how was my thinking these days.

I always thought that there is something I’m missing, some solution that doesn’t come with extended and outdated UI specification documents. Something that makes me and others catch the idea faster and spend less time understanding the code. And yep, I was right, finally, I found it.

Introducing Statecharts

These problems happen to almost all people involved in any kind of reactive systems development such as UI development and, some people are too used to struggle with it, that it seems unavoidable and natural, but it is not.

The problem is a well known one, reactive systems are complex because of event orchestration complexity. And, solving this problem is a matter of getting things explicit from the beginning. So, your mental model should be coded in a way that you and others can easily reason about.

In simple terms, a Statechart is a pure function that contains all the logic related to the event-state orchestration in an explicit way. This way we can avoid the most common bugs and, if there are some, it’s easy to find them.

With statecharts, you have a simple and manageable way to organize this logic by using a graph and some constructions. This gives us the power to reason about complex UI flows, and at the same time, it prevents unexpected behavior to happen. Just FYI this formalism is used at NASA for the Mars Science Laboratory Mission.

Taken from the NASA gallery

Yep! Curiosity uses statecharts! 😮 😎

You give to the statechart the current state, the event that happened, and optionally some external data, and it gives you back the next state and the actions that should be performed. An Action is a pretty simple concept, you can understand it as commands or functions that should be executed in response to the event that happened.

You already have state machines in your code

So, you already have this logic in your code but, the problem is that it is implicit. Here I have to quote Reginald Braithwaite:

Any sufficiently complicated model class contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of a state machine. — Reginald Braithwaite in How I Learned to Stop Worrying and ❤️ the State Machine.

You already implement all kinds of flows in your UI code, and probably you do it by manually handling all the cases and figuring out the edge cases by doing some exploratory testing. This is known as the bottom-up approach and it is the most common approach to developing UIs these days. We attach event listeners to UI components and perform some kind of action inside it. For instance, in vanilla JS you can have:

But what about Redux? Well, in Redux-like architectures you split the event handlers in reducers, for state management, and effect handlers. This is a great practice and Redux solves the state management problem, but you still have to struggle with the event orchestration one (state transitions).

A matter of paradigms

The above approaches are known as the event-action paradigm. In this paradigm, when some event happens you fire an action in response to it. The problem with it is that, in order to coordinate the UI, you have to put a lot of conditions inside your event handlers and even worse you may have nested if-else conditionals, switch cases, and so on.

In Redux you split this up in the reducer and the effect handlers but you still have the same problem. This paradigm makes your code complex and bug-prone. You as a developer have to maintain all those cases in your mind and be careful to not forget something.

Statecharts use the event-state-action paradigm which is the nature of complex UIs. And you may say, what’s the difference between statecharts and state diagrams. Long story short: