Sophie Alpert

Everyone is wrong about that Slack flowchart

October 30, 2024

Building software is hard. Oftentimes things that seem like they should be simple end up being way more complicated when you get into the details. (OK, maybe this isn’t specific to software.)

As evidence of this, people love to point to this flowchart that Slack’s engineering team published in March 2017 summarizing the logic Slack uses to determine whether to send a given user a notification for a message (author Johnny Rodgers’s additional commentary here):

Slack's flowchart titled 'Should we send a notification'. It has a few dozen boxes and arrows in different colors, and the lines are intertwined and even circular in some places. Multiple parts of the chart are partially duplicative with other parts.

You’ll hear no argument from me that this flowchart is incredibly complicated! It’s hard to understand the nuances of the logic from glancing quickly at this diagram. There are literally cycles in the graph! However I think it overcomplicates the situation a lot.

The most obvious cause of extra boxes in the diagram is completely splitting the “channel notification preferences” from “global notification preferences” questions, despite the fact that the options are almost perfectly analogous. Another issue is unnecessarily repeated checks for threads and highlight words that each appear a half dozen different times.

If you “refactor” the diagram, you end up with something that looks more like this version I drew:

My rendition of the same flowchart. It has only 6 boxes. We check the notification preference in only a single place and the chart overall is nearly linear, with each other check shunting a Yes or No answer towards the final 'Send Notification' or 'Don't Notify' outcome, rather than having many parallel paths that the common case goes down.

To me this is way easier to understand.

I know this is not 100% bug-for-bug compatible with the original flowchart. Honestly, that’s a little intentional: for example, if @channel mentions are suppressed then the original says that we’ll never notify for a @channel message, but it seems that if the message contains a user mention or highlight word, we should still notify in that case. Other minor differences too seem as likely to be errors in the original diagram versus mine.

Since the logic is simpler to understand at a glance in my version, I expect it is also easier to verify the correctness of and find bugs in my diagram if someone were to want to.

My diagram combines several things that are split out in the original version. In addition to the mergers I mentioned above, my use of && and || typically corresponds to different boxes in the original. Similarly, my Nothing (incl. muted) arrow is actually two checks masquerading as one.

Am I unfairly cheating by smooshing these together? I’d argue no. Each box or each arrow might correspond to a few lines of code (or may need to load data from multiple sources), but here we combine things that are conceptually part of the same check into one place, which makes it easier to understand the intent. I also focus on trying to have a single clear path through the chart with offramps, versus the original that has a dozen different “valid” paths. The goal of the chart, at least to me, is to make it easy to understand the high-level story of the decision tree, while still staying accurate to small details. In code, each complex check might be defined as its own function that can be reviewed and tested independently.

I don’t mean to claim that Slack’s notifications logic is simple. Indeed, former Slack employees tell me that it’s one of the most complex pieces of their codebase. I’m sure there is even a fair amount of complexity that is not captured in either diagram. For example, in what cases should a message sender be shown the choice to override do-not-disturb and “Notify anyway”? If a push notification is sent to my phone but then I view it on desktop or the message is deleted, should the notification be rescinded? This is all tricky business.

The point I want to make here is that the way we think about and talk about our systems has a huge impact on how understandable they are. It’s easy to make a complex solution to a complex problem; what’s hard is making a simple solution to a complex problem. With careful attention we can find the right lens to look through so that a tricky problem falls into place and our understanding of it looks more like the second diagram than the first.

Thanks to Scott Sandler for helping me understand the original diagram and reviewing mine.