“I’d love to improve this design, but I just haven’t got the time”
“I really want to tidy this up a bit more, but it’s not in the scope of this task”
“We don’t have time to re-think the architecture of this module right now”
Every developer has heard those phrases a hundred times. Hell, every developer has said those phrases a hundred times.
And, as much as we hate to admit it – many times it’s the right thing to do.
I would’ve loved to be payed to deliver elegant, beautiful code, but the reality is, my employer pays me to deliver functionality that is useful for them and for their customers; AKA Value.
Focusing on value delivered to the customer is the biggest emphasis of modern tech businesses, becoming even more prominent following the popularity of Eric Reis’s “The Lean startup”, and the whole “Tech product development” school of thought it inspired.
However, we all (including Reis & friends) also recognize that focusing entirely on customer-facing functionality is a mistake; This is where you get into the oh-so-familiar “tech debt” zone, and then “tech bankruptcy”, leading to the dreaded, and wasteful, admission of failure – the “complete re-write”.
Therefore, we can generally agree that, as software developers, Maintenance, i.e keeping the codebase in a healthy state, is an important part of our job.
But if we all recognize that keeping a healthy codebase is an important part of our job, how do we so often find ourselves with our “value” dials at 100%, but our “maintenance” dials at (nearly) 0%?
We know that maintenance is a must. Our tech lead knows it. Our CTO talks about it, sometimes even the CEO is familiar with the concept of “tech debt” and how terrified the techies are of it.
Yet, on the ground, priorities remain the same. “I don’t have time to fix it
right now ever”.
Is there a legitimate reason?
The most popular explanation is the “Big Bad Product manager” theory: I don’t get to do technical maintenance because the evil business person keeps pushing features on me.
I find this explanation insufficient, for two reasons:
Firstly, contrary to how we like to portray them, product managers are reasonable human beings. They, too, know and fear tech debt, and they want to avoid it.
And even if they don’t, keeping the technical side of the business healthy is what your tech leadership team is there for.
Secondly, as we observed above – maintenance is part of your job.
Since when do you have to ask for permission to do your job?
A doctor won’t forgo thorough examinations and tests because “we promised the client we’d be healthy by the end of the quarter”.
A professional contractor won’t start laying down foundations before she’s verified that the ground can sustain the structure she’s building.
So why is it different in software?
A lot of the reason lies in the extreme immaturity of our industry.
We don’t have enough professional standards in place to make code health a non-negotiable part of the process, like safety checks in construction, or sanitization in health services.
(This, in turn, is because haven’t demonstrated enough professional ability to justify such standards; i.e – We took the time to ‘repay tech debt’ in the last project, but it sill turned out crap. So how can we credibly demand to do the same thing in the next project?)
(Of course, this observation will not be news to anyone who listened to what Uncle Bob Martin, and many others, have been saying for years now)
But I believe that this not the whole story – it’s not just that we’re not good (i.e professional) enough to do maintenance properly. Part of the problem is that we don’t even try.
(Remember – it’s “I didn’t do it”, it’s not “I tried, but failed to do it”)
Why don’t we even try to do maintenance?
Let’s consider your typical developer. In any given day, they have the choice to deliver either value or maintenance. We know that they (nearly) always choose the former over the latter. Even though their tech lead, CTO, colleagues, all talk about the horrors of tech debt every single day.
Why is that?
How many times have you (or a colleague) been praised for delivering a feature that was very beneficial to your clients?
Now, compare that to how many times you (or a colleague) have been praised for refactoring, maintaining, or adding technical documentation to your project?
Or, from a different angle – what do you think would be the consequences for you, personally, if you fail to deliver one, out of 100 planned features, to your client?
Compare that to what you think the consequences would be for you, personally, if you fail to improve / maintain the codebase in 100 out of 100 opportunities.
If your workplace is even remotely similar to any workplace I’ve ever seen, you know that delivering excellent maintenance might gain you the gratitude of your coworkers, but delivering features will gain you a promotion.
Which would you pick?
This conclusion is hardly surprising or novel; if there’s one thing I know about market economy (and there is only one thing I actually know), is that people will optimize their behaviour based on the incentives presented to them.
Pay developers by line of code? You get the same functionality written x10 more verbosely.
A bonus for every bug fixed? You get bugs planted in the application, so that they can be fixed later.
No tangible reward at all for maintenance? You get tech debt.
Walk the walk, don’t talk the talk
How can we move the ratio for developers away from 100% value – 0% maintenance?
Simple – managers need to put their money where their mouth is;
Stop talking about wanting to tackle tech debt. Instead, show that you’re willing to pay people to tackle it.
(Balance is important here; while we don’t want the split between value and maintenance to be 100/0, a 50/50 split is also unreasonable)
How about having maintenance-related line items as part of your yearly review process? As part of the developer role specs?
Why not, for every 10 times you ask “how’s such-and-such feature coming along?”, ask “how have you improved the code lately?” once?
Once people understand that there’s an incentive for them to keep the codebase healthy, that their promotion, raise, status within the organization, is affected by it, they will find the time, scope, and energy, to get it done.
(*Huge caveat: To effectively judge whether someone is achieving a certain goal, you need to be able to measure it. Measuring code quality, or the amount of improvement of code quality, is not a solved problem by any means. It’s a subject worthy of a blog post (or book, or academic research) of its own.)
What do you think? Does this description map to your own experiences? Is there a legitimate reason why we’re prevented from paying back tech debt that I’ve missed? Or maybe this isn’t actually a problem at all? Let me know below.
15 thoughts on “Why we all choose to not pay back tech debt”
We’ve been experimenting for ~1.5 years with a large project (~1 M LOC, including tests, web framework pages, etc.) where we deliberately reward people who improve unit-test coverage. I keep track of the changes, and every quarter the top 2 developers (positive delta test coverage) get a $50 gift card, and get listed in the official “Rewards/recognition” program.
It’s not much. But I think it changed the *flavor* of the conversations, a carrot to go with the stick. I think SOME SORT OF REWARD/RECOGNITION is really, really important.
(sorry for being a year late to the party)
Brilliant article! I’ve recently heard (not just) from a Chief Architect of one SaaS company the idea of improving code quality and decreasing tech debt via code ownership. The idea being that it’s easier to maintain high standards in a tight group that is well-informed about their part of the codebase, the fact that it’s their “assigned code” or “responsibility” makes that argument even stronger. What do you think?
(Disclaimer, I currently work for a company that is looking into this)
I think what you’ve mentioned in the caveat “To effectively judge whether someone is achieving a certain goal, you need to be able to measure it. Measuring code quality, or the amount of improvement of code quality, is not a solved problem by any means. It’s a subject worthy of a blog post (or book, or academic research) of its own.” is particularly interesting. What if we would measure their effect on tech debt reduction, rather than the quality of code?
Measuring tech debt is tricky on its own though (what do people think about those 3 metrics that are attempting to do so https://www.notion.so/stepsize/3-Metrics-to-Understand-Tackle-Technical-Debt-4e7442a592cf40759bdd7e3733b7f815 -> BS / not BS?)
Let’s say that there’d be a leaderboard of engineers whose activity is tight to reducing churn and increasing cohesion in the codebase…?
Let me know what you all think, incentives for engineers to pay off tech debt are indeed managed very poorly.
Thanks for your comment, Stefanie, and for the linked blogpost – I think it’s the best I’ve read on the subject!
regarding measurements – the ones you’ve outlined in your post – cohesion, churn and ownership, seem like a pretty good stab at measuring quality (or at least measuring trends in quality)!
regarding the ownership comment – I think I would agree. It seems to me like it could be a variation / re-phrasing of Brooks Law, perhaps? By keeping team size small, you avoid reaching that critical number of developers which make work worse, rather than better..
Thanks for getting back to me and glad that it resonates! And yeah I can see a direct link with Brooks Law now that you’ve brought it up.
Out of interest – do you know of any other pretty good stabs you’ve seen for measuring tech debt/trends in quality by any chance? I’d love to have a look!
Technical debt is a metaphor and the metaphor is useful in some contexts to explain something to people with little or no experience in software development. We should be careful to use the term our self (as software developers) as if technical debt equals ‘real’ debt. To name a few differences, unlike financial debt, technical debt isn’t quantifiable and highly subjective. Technical debt doesn’t have an interest, and can rarely be used as a leverage.
That’s why you’d often won’t be praised for ‘paying back technical debt’. Maybe you think you’ve paid back technical debt, but for your colleagues’ point of view, you’ve made the code-base or architecture more complex. You make like using OO-patterns, but maybe your team-member doesn’t. Maybe you think introducing an ESB makes the architecture awesome, but your successor could hate it. Splitting up the code base in tine repositories could be nirvana for you but hell for others. FP can be awesome, but if you never take the time to explain others won’t be able to understand you one-liners.
Not that resolving technical debt, accidental complexity, legacy, etc, isn’t useless: every improvement that saves times for your colleagues or makes adding new features simpler is easy to sell. Once done, others will often pick up without the need for any mandate. These kind of improvements often won’t even cost you a lot of time.
Thanks for your comment, although I disagree with much of what you’ve said.
The concept of tech debt is not meant just for non technical people, but is useful for us as well.
Exactly like real debt, you leverage it to allow you to ship working software faster.
Exactly like real debt, it accrues interest – when you develop on top of unnecessary complexity, you add to it, thus increasing your debt.
I did touch on the other part of your comment very briefly – since the software “engineering” profession does not have well established standards, it’s pretty much always down to opinion and personal preference.
Therefore, the examples you gave are very true – one person’s opinion might be different to the other’s.
LikeLiked by 1 person
Since tech debt is so often used, I agree it’s more a ‘concept’ then a ‘metaphor’. Just like a desktop is no longer a metaphor (I don’t think anyone will use the term desktop to indicate the top of their office-table), but an actual concept.
Financial debt is different still from tech debt: financial debt and it’s interest is quantifiable. Debt and interest can be represented by an real (or rational?) number. Technical debt is not quantifiable as such.
Great post. I maintain two web apps that were both written around 2005 and, as you can probably imagine, we have piles of technical debt.
Part of the reason I find technical debt so difficult to pay back is that the “interest rate” is so high. I’m sure everybody’s seen Steve McConnell’s chart showing that fixing a requirements defect in maintenance can cost 100-200 times what it would have cost to fix it where it was introduced. Well, the reality of that math is punishing. For example, we could spend 100 hours fixing a database schema problem affecting multiple tables or we could crank out 10 new features that will help the business earn x thousands of dollars.
And that’s just the cost to fix one deeply embedded defect. We’ve got hundreds of defects just like it. So, any rational person must choose their priorities very carefully. And, yes, I’ve said all the things you’ve said at the top of the post, repeatedly. You have to choose your battles and not be tempted into fixing things that are going to cost a fortune for very little benefit–no matter how much it you’ll like to just fix it.
Our primary strategy is to stop making the problem worse. New code must be reviewed, must have automated tests if tests are reasonably attainable, must pass our coding style guide, must pass our static analysis, and so on. It’s slow and tedious but at least our new code is not adding to our problems.
The next part of our strategy is to push for technical debt repayment. Sometimes we just pick an inspection error that’s causing problems and just eliminate it from the whole code base and then never let that particular inspection pass code review ever again. These are good Friday afternoon tasks. You’re tired and you don’t want to start anything big so you spend an hour stomping out inspection errors.
And a final strategy we use is to clean up the code in the area where we want to create or change an existing feature. We’ve got buy-in from the product owner to do these clean-ups so they are happening a little bit each sprint.
There’s no silver bullet. Neither of these systems is ever going to be amazing. We just have to accept that. But we can avoid declaring bankruptcy by working hard and remembering the punishing math I mentioned above whenever we’re tempted to take a shortcut or make a mess.
Sounds like you have really thought this through, put in a detailed plan in place, and are executing through it diligently.
I’m guessing that this is a major reason why you’ve got buy-in from your product persons – you’re providing results that are measurably impacting the business!
That’s super impressive, I’m sure you’re all very proud of your efforts, and of the results!
I don’t necessarily agree that monetary incentives are the right option. Acknowledgement is and praise is a better place. Think of it this way. If you don’t give incentives monetarily for product features and swing to only monetary incentives for tech debt how many revenue bearing features will be delivered. There is a balance when it comes to product development. If you work on a commercial product you have to balance revenue versus tech debt all the time. It definitely is a challenge. I believe holding technical debt with some level of revere in your organization can help. You also need to determine the motivation of the individual. Some folks care about $$ and some don’t. Some people care about being praised in front of the company some don’t. At the end of the day you need to find the motivation for each engineer and address it somewhat individually.
Thanks for the blog post it is definitely intriguing and thought provoking.
Thanks for sharing your thoughts – indeed different people are motivated by different things.
I think that, a broad common ground, is that many people are motivated to do well in their jobs – some for monetary reasons, some for the reasons you mentioned above.
Tying maintenance into the definition of what “doing well” in your job means, can work for different people with different motivations
LikeLiked by 1 person
> Why don’t we even try to do maintenance?
Because of the drastic pace of change in the technology ecosystems. System of systems are nowadays designed so that individual cells are optimized for replaceability rather then maintainability.
I don’t think that’s necessarily true in all cases – See how many systems developed 5 or 10 years ago are still in use today.
Have you seen a lot of cases where it made sense to replace a whole component rather than keep it in good health?
I personally am over a code base of 10 Million lines of code that has survived 15 years. In some industries this is actually the norm. Especially in enterprise based solutions that tend to live for a long time.