Convince your CEO that tech debt matters
Paying down tech debt is an investment in future productivity. Legible code is an investment in the ease of the next person who reads, debugs, or replaces it. Building a DevOps pipeline is an investment in future deployment speed. Maintaining a robust test suite is an investment in our future sanity. Elegant refactors are an investment in the development speed of new features. These are all investments in the morale of developers.
But other teams cannot see (or often understand) this kind of work. This is natural, but tragic. Hopefully your company agrees that tech debt matters (if not, you should run screaming). But even when that’s true, it can be difficult to justify why you're working on it. Let's call this set of activities "dev investment."
Dev investment is fundamental to productivity. But it is also invisible, like the roots of a tree. When you ship a new feature, business teams can see it, interact with it, and show it off to customers. When you do a big beautiful refactor, they might see nothing at all. This is a serious problem.
Companies that don’t embrace dev investment can be hellish. Non-technical teams think devs are screwing around. Executives will replace important investment projects with customer-facing features, despite the warnings of developers. God forbid, your team might not get to work on tech debt at all (again, run screaming).
But even a company with a healthy dev investment culture can struggle. I was a Product Manager for years at an organization that is great about making time for dev investment. Our CTO and Product teams encouraged us to carve out time to do this. I had built web apps before — I cared about this a lot. And still, I often balked when it came time to do it. There is a real short term tradeoff between (1) delivering features, or (2) making dev investments. And (1) almost always wins.
This is an uphill battle. Even in the best case scenario:
- Dev investment is not immediately visible work.
- It is hard to explain why it matters without using jargon that non-technical teams won’t understand.
- Working on long term investments instead of new features is always a painful tradeoff.
I’m using the word "investment" on purpose. Investments have returns. You don’t typically see those returns the next day — investing is a long game. So, explain the Return on Investment (ROI) to the business teams. Don't describe what you're doing, describe why the company will benefit from these changes.
Great refactors improve site performance, and make it easier to ship features. Deleting bad code improves morale. Upgrading to the latest package versions improves security and unblocks future features. Fixing flaky tests makes us more confident our product works.
Get specific. Literally write down the ROI as, “If we invest __ weeks into __, we will get __.” Here’s why this kind of explicit ROI justification helps:
- We should evaluate all projects on the basis of ROI. Whether that project is a cool new feature, or a foundational investment in our processes, we're primarily interested in the return. Justifying all projects this way means we can weigh the relative importance of dev investment projects against other projects.
- Without this justification, you will operate in a black box, and other teams will get suspicious. Is that fair? Maybe. Maybe not. But you have the power to preempt that suspicion by justifying your projects.
- This clarifies your own prioritization because it forces rigorous product thinking. Imagine you have 2 projects you’re itching to do. The ROI on one is “This will improve site performance, and will make it easier to build that cool new feature.” The ROI on the other is, “This refactor is just better code.” The latter project is still valid. But the justification for the former is clearly higher priority. If you struggle to come up with a clear ROI, consider whether it’s worth doing right now.
It’s easy to slip into programmer jargon. Give non-technical teams a metaphor. I like the tired old metaphor of the factory.
Let’s say we run a factory. On an ongoing basis, we need to clean the factory floor, tidy up, do maintenance on our machines, and upgrade to better machines. A healthy, clean, productive factory floor is good for the company, product, workers, and customers.
Instead of, “We should carve out a few points for tech debt for every sprint,” try:
Maintenance, repairs, and installation of new equipment are all part of the job. We want a culture where everyone on the factory floor invests in making the floor better. You should count on us always spending 10-15% of our time making these kinds of improvements. We're building stuff here, and regular cleanups are necessary.
Instead of, “This refactor is going to make our code beautiful,” try:
Everything works better when our processes are clear. When we rush, we build haphazard manufacturing processes and machinery. New hires have a difficult time learning how things work. We end up wasting time down the road teaching and maintaining these bad processes. When we take our time to build elegant processes and better machinery, things work better, they are easier to understand, and easier to build on.
Instead of, “If we don’t pay down this old tech debt now, we’re going to be adding to the debt with this new feature,” try:
A big part of our factory floor has a shaky foundation with a lot of complex machinery on it. To fix it, we will need to disassemble and reassemble a lot of machinery. This will be costly but necessary. The more we build without repairing, the more complex and costly the eventual repair will be.
Instead of “We need to upgrade to PHP 8.2,” try:
We are working on old machines. They have safety issues, they are slower, and they make us less productive. Newer machines will allow us to build ___, and build it faster than we can today. The machines are free, but it will take us a week to install them.
Instead of, “We gotta fix a bunch of flakey tests, or I’m going to lose my mind,” try:
We have automated QA tests that ensure everything we ship actually works. Right now these tests are on the fritz. If we take a week to fix these, it will mean three things. (1) we’ll be confident again that everything we ship actually works. (2) we ship faster because our tests won’t be randomly failing anymore. (3) It will make our team happy, because they are sick of fighting with these tests.
Instead of, “Let’s replace that old janky feature with our new React components,” try:
This wing of the factory floor is a mess. Old boxes lying around, grime on the machinery. When there's a problem over there, it takes me hours to figure out what's wrong. Sure, it’s not hurting the product. But it’s a huge bummer to look at, and it’s actually a big pain in the butt to deal with. Let’s rebuild it.