Threads in Slack, a long design journey
On August 19, 2014 at 11:46 AM, Stewart Butterfield, CEO of Slack, created a new channel called #feat-rxns and invited a few members of the Slack team to join the conversation. The purpose of this channel was to build two new features in Slack: Emoji Reactions and Threads. Looking back at this more than 3 years later, it might sound strange that both features were combined into one project, but at the time it did not sound like either of those would be big enough to justify more than one channel. They both revolved around the same idea: reacting to a message, with either words or emoji.
This is the story of designing Threads, and how much we underestimated its complexity. It’s also a deep dive into the design process at Slack.
What are threads, though?
Threads was one of our most requested features, but one thing that we realized quite early on is that “having threads in Slack” could mean a lot of different things. Most of the tools we use every day have threaded conversations at their core: Facebook, Twitter, Reddit, YouTube (and of course, emails). However, they each have a different way to handling this feature.
At the time, Facebook posts each had only one long thread of comments ordered by date. On Twitter, any tweet could have a multitude of direct replies, and those replies could also have replies, allowing an infinite amount of depth. Reddit, too, treated replies and their visibility slightly differently. So which was the right approach for us?
With all these different systems around, we wanted to first understand what people really mean when they ask for threads in Slack. At the time, Slack was not even one year old, and it would have made total sense to build something quickly and see how customers reacted to it. But Slack was working fairly well without threads, so we decided to take the time to figure out a model that would bring the most value to the way people use Slack.
Quick notes about the Slack design process
One thing that we are very proud of at Slack is that we drink our own wine — for every feature that we build, we try it out on ourselves before making it available to the public. Everyone is encouraged to provide feedback about a new feature, regardless of who you are in the company. Often, the most valuable feedback comes from people who have no idea what the feature is, as they will experience it in the most candid and genuine way possible. This system also provides the design team with a bit of leeway: if we’re not sure about something, we just give it our best shot and see how it goes.
This process was crucial for Threads, where it would have been impossible to validate any of our design decisions without seeing how real people used it. We shipped 6 major versions of Threads internally, and got valuable feedback every time. Each release was necessary in order to understand what wasn’t working and what was.
Exploration 1 — The Twitter model, inline.
We decided to start our first exploration of Threads based on the same model as Twitter, because it looked like the most flexible solution. The design adhered to the following rules:
You can reply to any message, including other replies
There is no limit to how many direct replies a message can have
All replies are posted in the channel
Here is an illustration of what we had in mind:
With this system, you could have multiple conversations happening simultaneously in the channel. We liked this first approach because conversations were kept in the channel, so replies lived by the same rules as normal messages: they would mark channels as unread, and mentions would trigger a badge on the channel. All we needed to do was to make sure that replies were clearly labeled so they wouldn’t degrade the normal reading experience.
The main problem with this first version was the “expanding” effect that you would experience when opening a thread. Because we were pushing messages up and down to display the thread inline, it was difficult not to lose your bearings when closing a thread, especially since you would always end up scrolling a little bit when reading the thread, and closing it would land you in a completely different position in the channel. This was so disruptive that it was impossible to judge the rest of the feature, so we turned the whole thing off, and explored other ways to open a thread.
Exploration 2 — Twitter model, overlay.
Instead of pushing content up and down, we next tried displaying threads in an overlay. We believed that by separating the thread into its own layer, it would be easier to navigate the channel’s content.
Sadly, this solution fixed one problem, but created many more. Having to constantly open and close the overlays proved to be very tedious, and it was a lot of extra work just to read a channel. Also, making every message clickable was very problematic, because people click a lot, and often for no reason.Overlays were constantly triggered by mistake (whether the user was trying to click out of a menu, a selection, or just randomly clicking while reading a message), which was very frustrating. Eventually, we decided not to persist with overlays, and to move threads to the right sidebar.
Exploration 3 — Twitter model, right sidebar.
Moving threads to the right sidebar was very good news for the engineering team. With a minimum amount of effort we had a new place to view threads, without shifting content or adding extra layers to the interface.
Because we were using a familiar element, the feedback we received started to shift from comments about the user interface to comments about the user experience. It wasn’t about how the feature looked, but how people felt when they experienced the feature. This was a good sign, because it meant that people were starting to use Threads, rather than just looking at them, but the amount of confusion people encountered was quite worrisome. Initially, we believed that if we spent enough time polishing the workflows, the design would eventually start to make sense. Unfortunately, after a few rounds, we realized that the feedback would not change, and we needed to continue to iterate.
As difficult as it was to admit, none of our initial solutions were successful. When a team hits a wall like this, the natural reaction is to question the very necessity of our work. Should we continue? Is this even a good idea? Are we adding complexity for no good reason? Should we just forget all about it and focus on the next big feature?
The design team had spent nine months trying to build Threads, but it was time to face a harsh reality: our model was just not working, no matter how visually polished the design was. We decided to start from scratch — but beforehand, we took some time to work on a couple of small features that were necessary to support threads and emoji reactions. We also decided to conduct some user testing to better understand why our model was failing.
Before trying our next approach, we added the ability to take action on a message, which fixed the problem of opening threads by mistake, and added an obvious place for threads to begin.
This benefited a few other projects that were happening at the same time, like the aforementioned Emoji Reactions project, as well as the Share Messagesproject, and Reminders. With inline actions in place, we were able to move on to user testing.
To better understand why our model was failing, we decided to conduct a small round of user testing. During those tests, people experienced the same confusion with Threads as the Slack team, but we were able to better identify the breaking points. The main problem was that the design was very complicated, and people didn’t understand it at all. For example, here is what a thread could look like:
Because you could reply to any message, including replies, Threads quickly became extremely complex. Once we realized this, we decided to restrict each thread to only one level of replies, hoping that this would be simple enough to start making sense.
Exploration 4 — One-Level Threads
Reducing each thread to only one level of replies was an instant success on all fronts. The design was simpler, it was easier to build, and of course, easier to understand and to use.
Although people were less confused with this approach, an unexpected problem started to appear: people were using Threads too much and it was making channels very difficult to understand, as multiple conversations wove into each other constantly.
Before Threads, if a user wanted to reply to an older message, they would have had to start a new message with some context, like, “about this topic, I think that…,” which was easy to read. But now that Threads were doing the heavy lifting of providing context, people didn’t bother doing this, making the channel incredibly hard to read without opening every thread in the channel.
We tried a few designs to fix this problem, like preambles before replies to provide better context, or notifications (e.g. “Hubert has replied”) that would be posted instead of replies in the channel.
Unfortunately, none of our solutions had any real positive impact. No matter how it was presented, Threads would make you read messages multiple times, as you would read a thread and then read the replies of that thread again in the channel. The feature that was supposed to help reading channels was doing the exact opposite. Once again, our model was failing. Since posting replies in the channel was never going to work, we decided to explore removing them altogether.
Exploration 5 — Sidebar Conversations
In our next iteration, replies were only posted in the sidebar, not in the channel. This was a major simplification of the feature, both in terms of visual design and engineering. But we were facing a new problem. On all our previous explorations, a new reply would mark the channel as unread, so the user would be alerted when their conversation was continuing. Now that replies were not in the channel anymore, we couldn’t rely on this system, but we still needed a way to let users know when new replies arrived. We decided to move thread notifications to the Activity panel on the top right.
Hiding replies from the channel content turned out to be the single most meaningful change we made while designing Threads. Channels were once again easy to read and focused. People weren’t confused about how to use Threads. Before this change, we would see people using Threads on the last message in the channel even though it would have been exactly the same to just send a new message to the channel. Now, there was a real difference between replying in the channel or in a thread.
Of course, things were still not perfect. We quickly realised that the Activity panel was not the right way to notify people about new replies. It was easy to miss, but distracting at the same time. The notification system was going to be our next challenge.
Exploration 6 — All Threads
For the first time, we didn’t have to turn our previous experiment off while building a central reply notification system (known as All Threads). Even though things were not perfect, they were good enough for our team to use in their normal workday. We took this as a very strong sign that we were on the right path.
All Threads was based on an existing feature in Slack, All Unreads, which displays all a user’s unread messages in a central view. The success of that feature proved we could build views detached from the context of a channel, and it seemed like a logical template to use for this feature, as well.
All Threads made it easier to notify users about new replies, and easier for users to browse recent replies. None of our other designs allowed you to go back to older Threads once you closed them, and ultimately, this is what convinced us that it was the best option to start with. After a few days and a few tweaks, the feedback we were receiving was mostly about adding more features to this view — a positive sign! To avoid the risk of making All Threads too complicated for its initial launch, we decided to keep those ideas for future explorations.
Exploration 7 — Broadcasts
The last thing that we needed to address is the fear of missing out that people felt, with replies no longer appearing in channels. For this, we made broadcasts — a way of letting users choose to post their reply back to the channel.
As subtle as it seems, this was the final touch that gave stability to the whole model we were trying to build. The most valuable aspect of Threads was the reduction of extra noise in channels, but in some cases, that was problematic.For a few people, the previous design (where all replies were posted in the channel) was exactly what they needed. By adding the ability to also send your reply back to the channel, we allowed people the flexibility to use Threads in whichever way made sense to them.
As Threads were also built on mobile platforms at the same time, each new exploration meant that the mobile version had to be adjusted as well. This was very new for our mobile team, as they were used to receiving projects in a mostly finished state. The Threads project was a catalyst for many of the changes that were made in the way we structure the product team at Slack today, like merging mobile and core product teams. To fully explore the impact of Threads on our mobile process will require a separate (future) blog post.
Launch & Post Mortem
Having an exceptional Customer Experience team was crucial to launching Threads successfully, as they establish a direct line of communication between people using Slack and our product team. They helped us launch the featurein the best way possible, and even replied to hundreds of users who had requested Threads over the years. We went as far back as early 2015.
Looking back at all the work we’ve done, it almost sounds crazy that we thought that any of our early ideas could ever work.
Even though it was a long road to get there, launching Threads was only the first step of the real journey. Launching is always the easy part. Since then we’ve made many adjustments, and have kept a very close eye on the feedback we’ve received.
Looking back at all the work we’ve done, it almost sounds crazy that we thought that any of our early ideas could ever work. But with every iteration of our design, we were convinced that this time we had the right solution, which made each failure even more difficult to admit. This journey was long, exciting, and sometimes painful, but it helped us remember that failing is an essential part of the design process, and you just have to be okay with it.
Every one of our failing explorations was successful to a small portion of people. It’s impossible to make everyone happy when releasing such an important feature, but after all our efforts, and all our failed attempts, we were able to face critics with a much stronger confidence about our solution.