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.
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.
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.
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 examples of taxes:
- 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.
Whether these are good choices or taxes or bad choices depends on the context of your organization. Are you a tiny startup desperately searching for product market fit? A larger team maintaining an existing product? How many taxes do you already have in place?
There are a few types of initiatives for which taxes just don’t work. Regardless of context, these should be explicitly prioritized:
- 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.