The post has several definitions of “tech debt”, but none of them use the “debt” metaphor. The most useful framing of tech debt for me is when you deliberately make choices that get you to a certain result faster, but you will have to work more time later because of it.
For example, maybe you want to demo a cool new feature to investors in two weeks, so you decided to implement a somewhat slow version of it, but after the demo you need to re-implement some parts to make it scale better, so you can actually release it to all your users. Something like that.
Of course there is also a maintenance burden with all software, and you should try to keep it low. But that seems a bit unrelated? Either way, I think devs mostly like the phrase because it makes it easier to explain to managers that they can’t always churn out new features, and sometimes have to do other tasks.
The post has several definitions of “tech debt”, but none of them use the “debt” metaphor.
It sounds like the usual language drift due to sloppiness (like “RESTful”, or “cloud” or any other phrases from tech pop culture). It doesn’t mean the tech debt metaphor is useless, it more likely means that people should stop calling anything they don’t like technical debt. It’s fine to want to improve and refactor some code, but it’s only technical debt if it was a corner cut deliberately in order to ship sooner, or fix a burning problem.
Perhaps the term technical debt is being used for maintenance work and refactors to get buy-in from management? If management is only willing to allow maintenance work when it’s labeled “technical debt” (because debt is bad, right? Even nontechnical folks understand that), that’s when people would start labeling any maintenance work as such. There are enough dysfunctional organisations where management doesn’t understand the need for upgrades, refactors and other such ongoing work that I suspect that’s probably the reason why.
But then the message of the article “stop saying technical debt” is extra wrong. The term is very useful, but misusing it to mean other things dilutes the concept and usefulness. It should be instructive to see why people are misusing the term, though.
Yes, I feel like that is the commonly accepted definition of technical debt. I think the author is kinda on to something in that a lot of engineers have a hard time articulating this, but instead of clarifying what’s useful about the metaphor and how to use it, they take this angle of trying to enact a sort of taboo.
I think that’s very rarely, if ever, the way to go with communication problems. If anything we should be trying to expand our vocabulary, not decrease it.
That’s just the thing: a lot of stuff gets sorted under “tech debt” even by developers. For the reasons that the author is mentioning - no clear definition.
I tend to get my team to differentiate “tech debt” (one-off decision we made before to speed up something) from other types of technical tasks we want to do. And I always try to write tech debt tickets specifically, and at the time of “borrowing”.
This brings several thoughts to me (without consolidating them, just randomly):
sometimes you don’t know you’re borrowing. So “bad code” is “debt” in the sense that you borrowed money by hiring less experienced people, who then incurred this debt.
as mentioned, a lot of other devs would not consider this definition (unless you push for it). How do you get them to not address everything as “tech debt”?
what do you do with other tech stuff? Upgrading framework would go under “maintenance”, or “operations” or something. This should (but most often isn’t) be scheduled regularly. Refactoring bad code might go under “platform stability”, “tech improvements” (or perhaps, sometimes, “tech debt”). And don’t even start “architecture” user stories.
For business, all of that means cost that needs to be paid. So to them, it’s close-enough.
Another problem is that if you suddenly have 5 different cathegories of things that you want done, the business will say, oh great, instead of 10-20% budget for tech debt, now I also need to pay 10% for architecture, 5% for maintenance, 15% for stability… Where does it end?
Also, “why do we need to change it, it works as it is?”
it is not always trivial to quantify the value you gain from these types of tasks:
“We’ll have 10% less crashes” - “so what? they don’t cost us anything anyway” - “but devops” - “they’re paid anyway”
“we’ll improve developer productivity by 7%” - “prove it!” - “we need to measure jira ticket latencies etc” - “great, now you want be doing more work that doesn’t get me anything”
One clarifying tool is Brooks’ adage that we should always throw away the first attempt at implementing a feature. We should consider our first try to be a prototype, and only productionize the second try after considering the lessons learned. This immediately tells us that prototypes are technical debt!
The corollary to that is Brooks’ “second system syndrome” - the second one you build will contain all the things you didn’t dare to try the first time around and collapse under its own weight.
So it’s more useful to be deliberate about prototypes, and build more proof of concept systems to explore the possibility of a new approach, using some synthetic benchmarks and toss that away, then integrate the idea properly into the system you’re building. It doesn’t necessarily mean the first attempt at a product has to be a complete prototype in and of itself. You can refactor as you go along and address decisions that turned out to be suboptimal (which is not technical debt).
Perhaps this just means that when building something novel (to them), a business should always set aside a “regret budget” to address such bad decisions. This would be on top of the regular maintenance and tech debt budgets you’d have in a project that’s more bread-and-butter for the business.
Nice writeup, though I think it’s overly optimistic about how hostile the business can be to even maintenance.
A company’s goal is to do maintenance as late as economically feasible, and the engineer’s goal is typically to do it as early as possible. The extremes result in maintenance either never occurring or occurring so soon that the feature never ships before additional maintenance is required.
Good project management, to the extent that such a thing is possible, is about finding on a case-by-case basis where on the spectrum the current operating regime should be.
(It also sucks that devs have overplayed their hand w.r.t. technical debt and it is now a bozo bit if you bring it up for most biz folks. I have one report who has never met a problem that wasn’t caused by not being on the latest version of something, or by not using a more idiomatic recent best-practice, and dealing with them is tiring.)
The author touches something that struck home for me:
I once worked on a team that complained ad infinitum that customer information required a query that drew from two different tables. The team assumed that the structure remained in place because of inertia or because changing the database structure had backward compatibility implications. After spending a non-negligible amount of time bashing the database design and dreaming up ways to fix it, the team learned that their plan was…illegal.
In my experience, the lack of documentation of decisions and their constraints is one of the most overlooked causes for toil. Having no searchable tangible history of your decisions is also a technical debt because “we can always document after launch”, but we rarely do.
People having to constantly re-learn and re-think things slows teams down in a way that is hard to measure. Specially when companies attribute this to the “learning curve” and even praise members that are better than others on inferring and reverse engineering things that should just be (for instance) a few lines in a wiki.
Exactly my thought - this example could’ve been easily prevented by adding a few comment lines to the model file, the query or a comment on the database table. Or like you said, on a wiki or other documentation file. It’s just good practice to document a not-perfect piece of code with the reason you had to do it, e.g. “NOTE: this should really be one table but we have to split it up for privacy reasons” or some such. No need to put in very long document explaining precisely why and how (that could be done, but generally speaking once you put the hint in, people will be able to derive it from first principles or ask a person who knows more about such things, like the legal dept.)
This metaphor helped when our team used it! I mean, much like with housework,
one discussion didn’t magically make things better. But the resulting
discussion was refreshingly concrete, and we stayed away from that awful
abstract question ‘how much (technical) debt is too much debt’.
Some excerpts from her thread below. But do read the original, it’s only
21 tweets.
I think housework is a better metaphor because it allows you to ask questions
like, “Is this ‘not cleaning the bathroom’ bad, or ‘running out of toilet
paper’ bad?”
[…]
The thing with tech debt is that in order to have a useful discussion, you
need to be able to talk about who is affected and how – who is going to be
woken up, be pulled off other work, be unable to perform some critical
function, etc. You can’t hide risk [by packaging it as debt -S] and have that talk.
[…]
As anyone who has ever argued about housework knows, housework arguments are
disturbingly specific. It’s always “Who minds the most?” and “I don’t use
that,” and “Who’s going to do the work?” and (rarely) “Who’s going to manage
getting this done?”
The fundamental issue here is that we’re micro managed. Changing the language we use when speaking to our micro managers isn’t going to have an impact.
Couldn’t agree more. I have, sadly, went on a lot of bad tangent refactoring code whose only fault was to be unaesthetic to my eye. I like to think that with age, I learned, but maybe I am deluding myself.
Lets be honest. What we call tech debt, is more that often code we don’t like it because it doesn’t conform to our personal standards, or what is our flavor of the week of “clean” code. Not OOP, enough not Functional enough, not Reactive, not Event Driven, the DB is a RDBMS rather than NoSQL (or vice-versa). Or its not in our favorite language.
Personally, I try to work around that by banning “tech debt” from my language, and rather state directly the problem with the code
It’s hard to understand and newbies take forever to ramp up
It’s hard to modify without introducing regressions
Adding new feature is abnormally long and tedious
It has performance problem because it has too many layer of abstraction
It’s not secure, some dependencies have CVE
One of our dependency keep breaking backward compatibility, forcing us to spend a lot of time updating it
The tech is not well suited to what we want to do with it (e.g. php for websocket, CPU bound code in node, LOB app in C)
When its easy to see the ROI from the statement of the problem, its easier to focus our effort on solving something real.
What we call tech debt, is more that often code we don’t like it because it doesn’t conform to our personal standards, or what is our flavor of the week of “clean” code.
My personal flavour would be not short enough. When I see small functions whose only role is to call another function, or small static functions that are called only once, I know there will be trouble ahead.
Personally, I try to work around that by banning “tech debt” from my language, and rather state directly the problem with the code
And above all your criteria are measurable: time to ramp up, number of regressions, time to introduce features, runtime timings, number of vulnerabilities or close calls… I think I’m going to steal your idea.
The post has several definitions of “tech debt”, but none of them use the “debt” metaphor. The most useful framing of tech debt for me is when you deliberately make choices that get you to a certain result faster, but you will have to work more time later because of it.
For example, maybe you want to demo a cool new feature to investors in two weeks, so you decided to implement a somewhat slow version of it, but after the demo you need to re-implement some parts to make it scale better, so you can actually release it to all your users. Something like that.
Of course there is also a maintenance burden with all software, and you should try to keep it low. But that seems a bit unrelated? Either way, I think devs mostly like the phrase because it makes it easier to explain to managers that they can’t always churn out new features, and sometimes have to do other tasks.
It sounds like the usual language drift due to sloppiness (like “RESTful”, or “cloud” or any other phrases from tech pop culture). It doesn’t mean the tech debt metaphor is useless, it more likely means that people should stop calling anything they don’t like technical debt. It’s fine to want to improve and refactor some code, but it’s only technical debt if it was a corner cut deliberately in order to ship sooner, or fix a burning problem.
Perhaps the term technical debt is being used for maintenance work and refactors to get buy-in from management? If management is only willing to allow maintenance work when it’s labeled “technical debt” (because debt is bad, right? Even nontechnical folks understand that), that’s when people would start labeling any maintenance work as such. There are enough dysfunctional organisations where management doesn’t understand the need for upgrades, refactors and other such ongoing work that I suspect that’s probably the reason why.
But then the message of the article “stop saying technical debt” is extra wrong. The term is very useful, but misusing it to mean other things dilutes the concept and usefulness. It should be instructive to see why people are misusing the term, though.
Yes, I feel like that is the commonly accepted definition of technical debt. I think the author is kinda on to something in that a lot of engineers have a hard time articulating this, but instead of clarifying what’s useful about the metaphor and how to use it, they take this angle of trying to enact a sort of taboo.
I think that’s very rarely, if ever, the way to go with communication problems. If anything we should be trying to expand our vocabulary, not decrease it.
That’s just the thing: a lot of stuff gets sorted under “tech debt” even by developers. For the reasons that the author is mentioning - no clear definition.
I tend to get my team to differentiate “tech debt” (one-off decision we made before to speed up something) from other types of technical tasks we want to do. And I always try to write tech debt tickets specifically, and at the time of “borrowing”.
This brings several thoughts to me (without consolidating them, just randomly):
One clarifying tool is Brooks’ adage that we should always throw away the first attempt at implementing a feature. We should consider our first try to be a prototype, and only productionize the second try after considering the lessons learned. This immediately tells us that prototypes are technical debt!
The corollary to that is Brooks’ “second system syndrome” - the second one you build will contain all the things you didn’t dare to try the first time around and collapse under its own weight.
So it’s more useful to be deliberate about prototypes, and build more proof of concept systems to explore the possibility of a new approach, using some synthetic benchmarks and toss that away, then integrate the idea properly into the system you’re building. It doesn’t necessarily mean the first attempt at a product has to be a complete prototype in and of itself. You can refactor as you go along and address decisions that turned out to be suboptimal (which is not technical debt).
Perhaps this just means that when building something novel (to them), a business should always set aside a “regret budget” to address such bad decisions. This would be on top of the regular maintenance and tech debt budgets you’d have in a project that’s more bread-and-butter for the business.
Nice writeup, though I think it’s overly optimistic about how hostile the business can be to even maintenance.
A company’s goal is to do maintenance as late as economically feasible, and the engineer’s goal is typically to do it as early as possible. The extremes result in maintenance either never occurring or occurring so soon that the feature never ships before additional maintenance is required.
Good project management, to the extent that such a thing is possible, is about finding on a case-by-case basis where on the spectrum the current operating regime should be.
(It also sucks that devs have overplayed their hand w.r.t. technical debt and it is now a bozo bit if you bring it up for most biz folks. I have one report who has never met a problem that wasn’t caused by not being on the latest version of something, or by not using a more idiomatic recent best-practice, and dealing with them is tiring.)
The author touches something that struck home for me:
In my experience, the lack of documentation of decisions and their constraints is one of the most overlooked causes for toil. Having no searchable tangible history of your decisions is also a technical debt because “we can always document after launch”, but we rarely do.
People having to constantly re-learn and re-think things slows teams down in a way that is hard to measure. Specially when companies attribute this to the “learning curve” and even praise members that are better than others on inferring and reverse engineering things that should just be (for instance) a few lines in a wiki.
Exactly my thought - this example could’ve been easily prevented by adding a few comment lines to the model file, the query or a comment on the database table. Or like you said, on a wiki or other documentation file. It’s just good practice to document a not-perfect piece of code with the reason you had to do it, e.g. “NOTE: this should really be one table but we have to split it up for privacy reasons” or some such. No need to put in very long document explaining precisely why and how (that could be done, but generally speaking once you put the hint in, people will be able to derive it from first principles or ask a person who knows more about such things, like the legal dept.)
I’ve switched to using Yvonne Lam’s metaphor: those problems in the codebase behave like housework, not like debt.
https://nitter.nl/yvonnezlam/status/1376628481878990852#
This metaphor helped when our team used it! I mean, much like with housework, one discussion didn’t magically make things better. But the resulting discussion was refreshingly concrete, and we stayed away from that awful abstract question ‘how much (technical) debt is too much debt’.
Some excerpts from her thread below. But do read the original, it’s only 21 tweets.
I’m going to introduce this to my team at work next week. I love this!
The fundamental issue here is that we’re micro managed. Changing the language we use when speaking to our micro managers isn’t going to have an impact.
Couldn’t agree more. I have, sadly, went on a lot of bad tangent refactoring code whose only fault was to be unaesthetic to my eye. I like to think that with age, I learned, but maybe I am deluding myself.
Lets be honest. What we call tech debt, is more that often code we don’t like it because it doesn’t conform to our personal standards, or what is our flavor of the week of “clean” code. Not OOP, enough not Functional enough, not Reactive, not Event Driven, the DB is a RDBMS rather than NoSQL (or vice-versa). Or its not in our favorite language.
Personally, I try to work around that by banning “tech debt” from my language, and rather state directly the problem with the code
When its easy to see the ROI from the statement of the problem, its easier to focus our effort on solving something real.
My personal flavour would be not short enough. When I see small functions whose only role is to call another function, or small static functions that are called only once, I know there will be trouble ahead.
And above all your criteria are measurable: time to ramp up, number of regressions, time to introduce features, runtime timings, number of vulnerabilities or close calls… I think I’m going to steal your idea.