← Back to front page

Blockers: A missing piece of project management?

Last updated 2021-06-27. Written by Magnus Holm (judofyr@gmail.com).

There exists a hundred different project management tools, and yet they all manage to disappoint. They’re a lot of hassle to keep up-to-date and even after you’ve done that, it’s not trivial to understand what’s going on in a project. It’s tempting to start thinking about how this can be improved — which explains why there are so many different solutions. However, when looking more into the different solutions you quickly realize that most of them are only superficially different.

In order to improve the situation it’s clear that we need to introduce different concepts as well. This article presents the concept of a "blocker" which is something I haven’t seen in any existing system. Maybe this concept can help?

Note that this article is written from my perspective as a programmer working on a team with 5-10 other people. The ideas and concepts should transfer to other contexts, but the examples may not resonate with you.

What are blockers?

Let’s consider a pretty standard project management tool where we have tasks. A task has a state (backlog, in progress, completed etc.) and is assigned to one person. The intention of a task is for one person to see it through from the beginning until the end. Some systems calls these for "stories", "issues" or "card", but I like the terminology of "tasks" since it makes it clear that it’s about one person completing a defined task.

Example of how blockers would look inside a project management tool

Every task in this system has a list of blockers. As the person starts working on the task they will start to write down any blockers that occur. A blocker is something which the assigned person is not capable of doing by themselves; it’s something where they need help for someone else. The blocker itself has only a simple state of either unresolved or resolved.

A blocker can’t be "in progress" as this makes no sense: The blocker only represents that the person is stuck. If someone else needs to do something to unblock the person then you’ll create a separate task for this purpose — and connect it to the blocker. This task will have its own state (i.e. from "in progress" to "completed") and might also end up with their own set of blockers. Once the task is complete, the original blocker will not be automatically resolved. This is actually a very critical point: It’s up to the assigned person to make the decision of whether they are still blocked.

Many existing systems have a concept of "blocking tasks" which is somewhat similar to what’s presented here. The difference with blocking tasks is that when you are blocked, you will create a new task directly and then relate it to the original task. There is no concept of a blocker by itself, but instead you connect tasks together by "blocks" or "blocked-by" relationships. In the rest of this article I’ll show that the introduction of an explicit concept of "blocker" gives a significant improvement in organizing projects.

How blockers work in practice

To better understand how blockers are useful I’m going to show an example of how they can be used. I’ll use a (hopefully) simple and relatable example: We’re working on web-based application and we want to introduce a new feature. The designer has already done their part and we have full sketches for how the feature should be implemented. All that’s remaining is for the programmer to implement it.

Step 1: We create a task "Implement feature X" in the task system and assign it to the programmer.

Step 2: The programmer starts working on it. They mark the task as "in progress".

Step 3: While working on it there comes up a few problems:

  • The sketches are missing error handling in a few cases. How should the error be presented?

  • It’s unclear if this feature should be available for all users or if it’s only available on some plans.

The programmer then adds these, verbatim, as blockers to the task. A blocker is a completely separate thing (it’s not a task in itself) and each task has a list of blockers. The task is then automatically marked as "blocked" in the task system.

Step 4: In their daily meeting, the team goes through all "pending blockers" across all tasks. This is a separate view in the task system and it serves as a backdrop for what needs to be discussed together. Many of the blockers just need clarification which can be decided right there and then. If so, the blocker is marked as resolved. Other blockers require more work in order to resolve. Then the team will create new tasks and connect them to the blocker. In this example they created a new task for the designer to clarify the error handling.

Step 5: At the moment, the programmer’s task is blocked, but the designer has an unblocked task. They start working on it and complete it to its finish. When they’re done they mark the task as complete, but the blocker remain unresolved.

Step 6: Since the blocker no longer has any pending tasks connected to it, it now resurfaces as a "pending blocker". The programmer can then double check that the work the designer did actually resolved the blocker. There is always a chance of miscommunication and it’s important that it’s the requester (i.e. the programmer in this case) which decides if they’ve been unblocked.

Step 7: The programmer marks the blocker as resolved and his task is therefore marked as unblocked. They continue working on it and is able to complete it. However, this code also requires a review from another programmer. They add a new blocker ("Review") and connects it to the pull request in GitHub.

Step 8: The review is being de-prioritized (or forgotten) so the blocker remains unresolved for three days. At this point the blocker resurfaces in the task system and it will be discussed in the daily meeting. They figure out that it can be reviewed by someone else (who doesn’t have so many other critical tasks).

Step 9: The review is complete and the blocker ("Review") can be marked as resolved. The programmer can now take the feature live by deploying it (i.e. merging it into the main branch). After this the task is marked as "complete".

Advantages of blockers

Suitable for even the tiniest issues

Many blockers that come up while working on a task are quite minor. "How should this look when there’s more than 3 featured articles?" "The backend API isn’t finalized yet." In a system based around blocking tasks it doesn’t feel natural to create tasks for these issues. Tasks are designed for bigger chunks of work, and creating tasks for minor issues tends to steal focus away from what’s actually going on in a project.

So what do people do to communicate minors blockers? They use comments and/or another communication medium. They’ll post a message on Slack saying "oh, btw, should this look when there’s more than 3 featured articles?" And then they’ll write a comment on the task saying "I’ve completed everything except X."

This often works okay in practice, but has some flaws. There’s the fundamental flaw that we’ve bypassed our task system. The task system has no knowledge about what’s going on. This means that these minor blockers escape all reporting. The system can’t help you easily understand what’s going when critical details are hidden in comments. And if you as a user has to dive into the comments to understand what’s going on, then I’d argue that you’ve lost the main advantage of a task system in the first place.

Using comments for these sort of blockers also tend to cause problems when there’s a lot things going on. Project management tools are useful because humans are not able to keep track of everything that needs to be done. We will forget about things — that’s the reality of being human. Once issues are being raised outside of the task system then they will be forgotten and will "suddenly" re-appear at an inconvenient time.

Maintains focus on the task at hand

Writing down a blocker is a very simple operation: You write down, in plain text, a sentence explaining the problem. You don’t have to set a priority, decide which person to assign it to, make sure it’s labelled correctly into the same project, or consider which sprint it should be placed into. This lets you quickly write down the problem so you can carry on finishing the other parts of task that you’re not blocked on. This makes sure you can remain focused on the problem which reduces costly context switching.

At the end of the day you can go over the blockers and decide how to approach them. This typically requires a very different mode than solving the hard problems of the task.

Encourages communication, reflection and discussion

Once you have a list of blockers the natural next step is to discuss them with the rest of the team. Any unexpected blocker which comes up during the work of a task demonstrates in some sense a failure of the planning process. Discussing them is a golden opportunity to reflect and learn from the "failure".

Increases precision and visibility

Let’s say that there’s currently a refactoring of some code going on. This is scheduled to take two weeks to complete. One planned feature is highly dependent on this refactoring and it’s completely impossible to implement it in the current setting. In fact, this was actually the reason for the refactoring in the first place. There’s also another planned feature which relates to the same code. This one is possible to implement today, but it would have to be completely rewritten once the refactoring lands. Therefore you’ve decided that you’re going to implement this feature after the refactoring has landed to minimize the total amount of work.

In a system with blocking tasks you’d mark both of these planned features as being blocked by the refactoring. However, this loses the critical piece of information that the second feature isn’t actually blocked. This will become very relevant once it turns out that the refactoring starts being delayed (maybe it’ll be closer to six weeks), and there’s signal that the second feature is highly anticipated. The simple relationship ("feature A is blocked by refactoring Y") isn’t precise enough to easily see what’s actually going on.

Blockers on the other hand let’s you express what’s actually blocking:

  • Feature A: "Touches the user system so will conflict with refactoring X"

  • Feature B: "Impossible to implement today since a user can’t have two roles in the current system"

By having this information structured it’s a lot easier for the tool to help the user understand the impact of what happens when a task becomes delayed. While looking at the task for the refactoring it can show the list of blockers, and we quickly see that one alternative would be to start working on the second feature and accept that there will be more total work in the end.

Problem-oriented, not solution-oriented

The previous section also showed another interesting effect of blockers. When writing down the blocker we expressed that feature A is blocked because it’s "impossible to implement today since a user can’t have two roles in the current system." Notice that "refactoring the user system" is one solution to this problem, but it’s not necessarily the only one. Other solutions could be:

  • Do we need the full refactoring? Is there a way to add support for two roles without the refactoring we first envisioned?

  • Can we change the feature to not need support for two roles per user?

Once we’ve decided on a solution we have tendency to get stuck on it. We’re so focused on the implementation details that it’s hard to imagine that there’s another way of solving it. Blockers naturally highlights the problems and once a solution turns out to not pan out they serve as an entry point for finding another solution.

Summary

The concept of blockers seem like a minor additional to a project management system, but I hope that I’ve been able to show that it would enable favorable interactions. Hopefully one of the readers of this article will be inspired and integrate it into an existing system.