7 mins

Senior Software Engineer at Netflix, Laurie Barth, has some ways to successfully prioritize tasks, including her tried and true “three buckets” model.

Modern engineering teams are almost always understaffed and asked to do more with less. Recent industry-wide layoffs have only exacerbated these challenges; forcing lean teams to make hard cuts and compromises about what work they can commit to. As such, one of the hardest things to do as an engineer is to decide what, among the many tasks on your plate, you should tackle next. While it would be nice to think that we can do it all in due time, that’s rarely the case. The reality is that you need to be ruthless with your prioritization. 

The three buckets model

To be successful with ruthless prioritization, the first thing you must recognize is that you’re likely to be working on more than one thing at any given time. There are many reasons for this, but the main one is efficiency. Having multiple tasks allows you to keep things moving. While one task is in a non-active cycle of development, e.g., code review, design feedback, etc.; or you’ve rabbit-holed too deep on one particular problem, your brain has an opportunity to change focus and work on another task. My version of this is quite intentional, and I call it the three buckets. 

At any given time I am rotating my attention between one of three tasks, each of which comes from a different bucket filled with like tasks listed in order of priority. When I finish one, the next prioritized task in that bucket is on deck.

One bucket comprises my current long-term feature. This is the task bucket that takes up the majority of my time, but it also alternates frequently between active development and waiting for input from others. While I’m in a paused phase, blocked by a dependent piece of work, I don’t want to shift my attention to another long-term feature. If I do that then there’s no saying how far I’ll get with task two before I’m unblocked with task one, leaving me in a weird place with two large projects to juggle. Instead, I want to work on a task in one of my other buckets.

My second bucket is a mindless, smaller task that needs to be completed, but that allows me to kill time between meetings, giving my brain a break when I’ve been staring at a bug for too long. This can be something like changing the color scheme for a page, updating a dependency that requires a lot of repetitive code changes, or cleaning up unused types. To be clear, this isn’t busy work, it’s work that needs to get done, but it can be done at a slower overall pace. This is the bucket I turn to when my first bucket feature is on pause and I don’t have anything urgent in my third bucket. 

That’s because my third bucket is my bug bucket. This is something as small as a typo on a page, to as large as production being down. Most of us consider the tasks that fill this bucket under the “firefighting mode” umbrella, where something is wrong and it needs to be fixed immediately. However, this bucket includes all bugs and issues, including those that aren’t necessarily quite that urgent.

The three bucket perks and cautions

The usefulness of the bucket approach is that it recognizes the reality of a development workflow and that your highest priority item is not always going to be the thing you’re actively coding. 

Furthermore, not only does it help you prioritize similar items together, but it is designed in such a way that once you’ve finished one task, another one is lined up. 

But there is a reason this is a bucket and not a list. Your priorities from one point in time to another aren’t set. Priorities can change both within a bucket and between buckets; rearranging based on urgency is a given, e.g., a production outage that needs sorting right away. However, most prioritization decisions aren’t as clear-cut, and determining them requires putting some thought into the potential tasks at hand. So, how do you prioritize your buckets?

Prioritize based on urgency

The first thing to consider when determining the prioritization of a task is how important it is that it gets done quickly. This isn’t as simple as it looks, because “urgency” is a vague term when applied to engineering tasks. It’s better to break it down into more objective measures.

  • What other work is dependent on this task? This applies to both bugs and features. Is the task being incomplete a blocker to others?
  • How many people are affected by this incomplete task? Does finishing it unlock major productivity wins for a large group of folks?
  • What happens if the task goes uncompleted for some period of time? Is it merely inconvenient, or catastrophic?

Asking yourself these questions helps you think of prioritization as if it were triage. How can you place the highest return on investment (ROI) tasks first?

Consider the size of the task

The next thing to consider is how long the task will take. Some tasks could rank about the same on your prioritization list, but there may be a clear answer as to which one will take a little longer to finish. This is not to say that shorter tasks should always take precedence. But, doing the shorter task first and then the longer one gets at least one bit of incremental value out the door faster.

In fact, there may be a way to use prioritization tactics to rethink the scope of large projects: they may not be currently framed in the most effective manner. If it’s a large task, is there any incremental value you can unlock sooner? Is doing so going to address some of the task’s urgency? To be clear, this doesn’t mean writing the feature now and then the tests at a later date. It means delivering a portion of the functionality if that portion can still provide value on its own.

Delegating to preserve priority

Offloading tasks may seem an unnatural thing to consider when prioritizing, but it’s good to think about whether this task needs to be completed by you. If it’s going to take you a long time to get to, would it be prioritized higher on someone else’s list? Are you able to pass it off to that person?

Visibility

This is the item that no one likes to think about. As engineers, we value objective, measurable criteria for determining what is most important. However, we all have a boss. And most of our bosses have bosses. As a result, some tasks with visibility will be more important to leadership. Instead of prioritizing those tasks first out of habit, here are some better things to think through.

  • How often will you need to communicate status updates while the task is being completed? If it’s going to eat into your time to constantly be answering questions about when it will be done, it might be worth doing sooner. If you can answer those questions upfront and it will not further eat into your time, then it may be a task you can postpone.
  • Is this task visible because it’s urgent? When you made your urgency determination did you use your lens or the lens of leadership who thinks this is a priority? Can you find out what context you may be missing?

A highly visible task does not need to become your highest priority the minute you learn about it. But if it isn’t, make sure you understand it and can communicate to stakeholders where it is on your list, and why it’s at that level of priority.

Be ruthless

You can’t do everything all at once. Some items will naturally come later, or fall below the cutline and get pushed even further out. There may be some unhappy parties on the other side of tasks you have pushed back. But it’s important to recognize that no prioritization system is perfect. Context and circumstances are fluid, something that wasn’t important yesterday can become your highest priority tomorrow.

The best we can do is communicate with stakeholders about when a task is meant to start, when it might be completed, and any changes to those expectations. Giving people that information with as much notice as possible helps you continue executing on that backlog.