Priorities and Taxes

Nailing prioritization is the holy grail of effective software teams. To get it right your team needs to understand the difference between implicit and explicit prioritization.

To illustrate, let’s discuss a scenario that’s all-too-familiar to many of us. You have a bunch of code in an old JavaScript framework. It’s part of a monolith, or at least a large service. It’s time — past time, really — that you start to clean it up.

Your tech lead wants one of the application teams to take on the rewrite. You consider the cost and benefit to engineering productivity and it looks like a good idea, a positive ROI effort. The team sizes the project, puts it next on the backlog and gets started.

That’s explicit prioritization: a task or project explicitly requested from a team.

Unfortunately, our front end rewrite is taking longer than our team estimated, and it looks like not only will we not finish on time, we expect there to be another quarter of work for the full team. You dread telling the rest of the company that critical projects will have to wait while you continue to refactor. At the same time, you know the destructive power of accumulated tech debt and can’t afford to wait any longer.

What do you do? You come up with a clever solution: any JavaScript file touched going forward needs to be rewritten in the new framework. This way you can get started on critical projects while continuing to chip away at tech debt.

Implicit priorities are a lot like incremental taxes. Image credit: Pictures of Money

That’s a form of implicit prioritization: a task added to each new project that adds complexity to that project. Implicit priorities are a lot like incremental taxes, you don’t notice them, but they add up. Therein lies their power, and also their liability. It’s easy to add a tax to tackle a new problem, but taxes tend to accumulate. Before you know it, you’ve added so much complexity to each new commit that you’ve materially slowed the organization’s progress.

Furthermore, implicit prioritization doesn’t resolve the issue all at once, leaving projects partially complete. In today’s world you’re lucky to have just an old and new JavaScript framework (my organization has at least three and we’re doing pretty well), so you find yourself with an inconsistent code base which is itself a tax.

How do you know when a tax is a good idea?

Good candidates for taxes are simple, consistent, lightweight and low risk. Checking for adherence to these processes should be automated (like running an automated check for consistent style standards), but come with a escape door when adhering to the tax just doesn’t make sense. Bad taxes add significant complexity and risk to the processes they accompany.

Some tax examples:

  • Every new feature needs to make the home page load faster.
  • Tag every bug fix with the full root cause of the bug.
  • Update every code path you touch to use the V2 API.
  • Increase test coverage every time you touch a file.

On the other hand, explicit prioritization is best for:

  • Mission-critical projects justified by ROI or strategic fit
  • Fixes that impact security, privacy or safety of users
  • Fully implementing changes when the tax approach proves too onerous

A well-versed engineering leader learns to balance explicit and implicit priorities. He or she audits the development process for tax accumulation regularly and schedules an ask when taxes start to slow the team down.

One practical strategy I like is to start with a tax, but convert it to an explicit priority in a defined amount of time. For example, let’s say you’re adding a linter to some code (of course you should have had a linter from the beginning, but we’ve all worked in a codebase where that just didn’t happen). You start out by asking each team member that touches a file to convert that file to pass the linter. You actively collect feedback on what works and what doesn’t while the linter is a tax. Once you have the rules and process calibrated and the linter starts adding value, you probably have enough information to determine a more accurate estimate of the total cost of converting the code base.

You can also try the opposite approach, using an ask to add the linter to the 20% of code paths that experience 80% of the edits, and adding a tax to propagate out to the remaining code only when it’s changed.

Like with many engineering management challenges, the key is being honest with your decisions, understanding the pros and cons of both kinds of priorities, and creating clear channels of communication where your engineering team can tell you if that taxes are becoming burdensome.