Managing technical debt is one of them most important parts of engineering. When you're resource constrained, which is almost a given in the real world, you need to think carefully about what kinds of debts are worth accruing, and what kinds are absolutely not.
I think this is both an art and a science, and the right balance comes with not just engineering experience, but also domain experience, team maturity/talent, market/competitive pressures, leadership, and culture.
There are so many factors involved that it's not surprising so many projects accrue horrible debt.
Sure, and credit cards can be a good thing, too. The problem is that most non-technical and formerly-technical project managers just charge everything to their credit cards and don't even know they own debt and are making interest payments on it.
When that's the level of awareness the average development team is dealing with, there's limited practical purpose in exploring the nuances of healthy debt management. It's more useful to talk about technical debt like nutritionists talk about empty calories and transfats.
This article has a clickbait title with a more reasonable premise in the body. No, technical debt isn't good, just like getting jabbed with a sharp object in the throat isn't good for you. The reasonable point the article is making is that there are some things worse than accruing technical debt, like spending too much time making an ivory tower system that doesn't actually have product fit. Similarly, getting jabbed with a sharp object in the throat in the case of a tracheotomy can be necessary, but that doesn't mean that you should run around jabbing yourself in the throat just for the sake of it. Technical debt is similar; sometimes necessary, but never choose it for its own sake.
The title of this article matches the tone, but doesn't really match the content. The author makes several good points that would be better characterized as, "given that technical debt is inevitable, try to make simple, easy to manipulate tools."
More likely that contrarian headlines garner more activity than their obvious or expected counterparts, pushing them to higher rankings more frequently. Here on hn, it’s possible that if a user reads a headline they already agree with, they will say to themselves “oh ya, I know that already, don’t need to read that.” Then when they see a contrarian headlibe they say to themselves “hmm, what’s this.” I would posit something more along those lines. Although I now realize, your comment may have been rhetorical in the sense of suggesting that this post (and others like it) take advantage of this trend but lack in substance.
It is a strange phenomenon, that the brain tends to ignore things that are expected, and is often jarred by the unexpected. It’s maybe one of the downfalls of expecting the unexpected. Because it makes even the unexpected seem ordinary. Or maybe the reverse is true, and expecting the unexpected makes the ordinary seem extraordinary.
It is clickbait. Just enough for you to click, read and comment. If the article actually relayed the content - How to manage technical debt better you might not even open the link.
I feel it’s easy to become a compulsive contrarian on Hackernews because of how many people are often willing to support or defend your contrarian view.
From my recent experience in a new team, this article strikes a chord.
Joining a team that is scared of technical debt and runs circles round themselves in a bid to avoid it end up producing more debt than they would otherwise. For example, making code overly DRY and wrong abstractions coupling unrelated parts of the system unnecessarily.
We must embrace the reality of technical debt. It is unavoidable and not something to be scared of. It can be managed by keeping things simple, clearly tested and keeping a cool head.
> making code overly DRY and wrong abstractions coupling unrelated parts of the system unnecessarily
I would say that's just bad engineering due to lack of insight or experience. DRY is the most simple and most dangerous principle (or "best-practice") of them all, because when it goes wrong it's the one that hurts the most.
One mentor of mine taught me the "rule of three". The first time you have to do something, you write it in-place. The second time, same thing. The third time is when you refactor into a common module all three components can use.
When you're writing it the second time, you're accruing technical debt. You pay it off when you refactor for the third component.
I'd say that technical debt is often the best kind of debt you can take on as a startup. Difficult to maintain code is not going to be the thing that puts you out of business. Usually that's making the wrong product or not being able to reach your market.
Compare that to the other kinds of debt (convertible, for instance). They cost a lot of time to obtain and, potentially, a lot of money in the long run if you do well.
Many of the most successful startups had (have?) shitty code. Of course there's great counterexamples (i.e. WhatsApp having a 5 person backend team when they were acquired), but as a programmer and founder I find that my urge to make shitty code and ship fast is waay smaller than my urge to make fantastic beautiful code.
Of course shipping fast does not imply writing crap code in general. At all. But sometimes it does, and when it does, I've learned that hard way that maybe it's better to choose the crap code.
Technical debt can benefit from being managed in it's own category - it's inevitable as bugs and features. Unmanaged technical debt is sometimes the 'bad' technical debt we think and read about in hindsight.
When I'm a little more aware of technical debt being created - I track and manage it just like a feature or a bug in the project management system. Separate type, label or category of ticket. It surprising several tools don't have this out of the box for some reason.
There's a few benefits to technical Debt being categorized separately:
Tracking technical debt helps provide a sense of the technical debt tickets that are being opened, and floating around both in numbers, size and unknowns.
Keeping technical debt items tracked along side features, and bugs in it's own category is an invaluable form of cross-training to new team members who are learning the why the current code base came to be how it is, and not just what they may see or think is best.
We see how good we might be as a team and individually at identifying technical debt, and if we are improving at identifying it, and help develop a ratio for future accuracy.
Regular technical debt review helps create a sense of what technical debt is occurring, and what can be fixed under the hood on another project, if desired, or possible.
Keeping an eye on technical debt is important too, if something initially small is at risk of painting the project into a corner, or becoming exponentially difficult to re-factor.
Would love to hear strategies and tactics you might use in your TD practice.
even if its not timely to implement - design the replacement right away, and update it if necessary. this helps scope the work, understand what other components are being effected, and allows related systems to be written with an eye towards the fixed version instead of the damaged one.
I've often thought that what software projects need is some equivalent of a balance sheet and P&L report - "assets" and "liabilities" together with "income" and "expenditure" equivalents.
Looking at technical debt in isolation and always regarding it as a bad thing always seemed simplistic to me.
Agreed. I've seen teams use no metrics. And I've seen teams use one or two metrics. I haven't seen management deal with complexity like a professional analyst for a pro sports club would: with a range of different metrics to inform human judgements.
"If there's a chance that the code you're writing will never be touched again, why bother to invest a lot of time in it?"
In that case, leave some Technical Debt at the end and allow the next requirement to drive a better design."
This is one of those things I don't understand about about software engineering and developers lacking professionalism.
Articles and handwavy comments tend to dismiss technical debt as a shrivelling pesky geek who keeps waxing on about how vi is better than emacs. (Someone who doesn't have a lot of influence, nor as important).
Pushing techincal debt to be managed by the PO, Scrummaster, busuiness, and/or managers creates major concerns and problems with what you're producing. The passive agressive response: "well convince them" is naive and wrong. They don't care. If we've seen anything from the experiences below, they just end up hoping those days won't come.
Examples:
1. Experian- I'm fairly confident that they had at last one engineer there that bitched about how much the dependencies were falling behind. If they have good ones, there would have been talk about how to automate that process.
2. Half baked products/data loss bugs - (See mongo)
3. Frequent "redesigns of projects" - There are major companies out there that have had to redo their entire product range due to this. It can't possibly be affordable. I'm sure theres lot's of lessions on the migrations. But it's a lot more expensive in the long run. Side rant: I guess if you believe that you're going to go out of business tomorrw, this is justified.
My point:
1. Be a professional developer, get deep knowledge on frameworks
2. Take your time and develop correctly at the start
3. Build experience with engineering, not the latest JS library that ignores experience.
4. Actually give a shit. Venkat Subermanian made a great qoute at one time: Your code quality is a reflection about how you feel about yourself and your coworkers.
Programmer morale is another factor in good/bad technical debt.
It can be quite enjoyable to take something like three separate implementations of a similar function, combine them, and delete a bunch of duplicate code.
On the other hand, it is nightmarish to toil through some tightly coupled mess and try to rewrite it in a manner that is more maintainable.
One makes you feel happy and in control, the other makes you feel like everything is falling apart.
> it is nightmarish to toil through some tightly coupled mess and try to rewrite it in a manner that is more maintainable.
I'm doing that right now, and it's great. There's several responsibilities that are all tightly coupled, and I'm pulling them into multiple components. It's requiring a lot of code archeology and reverse engineering of intent, but it's incredibly satisfying at the end.
I'd like to quibble a bit with the definition of technical debt being used. A decision not to refactor code when you don't know if you will be improving it is not technical debt in my book. There are many times when I look at a piece of code and say, "This is a smell here, but until we know better what we are building I can't remove the smell". It actually would be technical debt if I covered up the smell with something pretty that wasn't related to what I actually needed. Later on I'll have to remove that pretty code (or work around it). Hopefully making me feel better about apparent lack of smells is worth it ;-)
The idea of technical debt is that you are trading some kind of completeness/correctness in the code for something else that is valuable. Usually that valuable thing is time, but it can be something else. For example, perhaps you know that your requirements are wrong. However, the client is unhappy with answering questions. You could pester them some more, or you could implement the obviously wrong requirements and wait for them to find the problem themselves. In this way you defer the frustration of your client to a later time when they might be more approachable.
It should go without saying that you should almost never do the above: I'm only using it as an example of tech debt that isn't to do with saving time.
There are lots of times where technical debt is beneficial. The key is to understand the cost/benefit. This is where we usually go wrong. The cost/benefit analysis is usually done by someone who only understands the benefit. It's just making the analysis of borrowing money and making the assumption that you don't have to pay it back. Hmm... how much money should I borrow in that case? Obviously, as much as I can get!
I think this is just another way of saying "avoid gold-plating." Building a new service to stand up to millions of users and nation-state attackers is probably overkill until you know whether anyone actually wants it.
That said, there are definitely early technical decisions that will be very painful to change later on, like how you authenticate users and protect PII.
A lesson I learned early in my career was to avoid spinning out too much on why a particular piece of code someone else wrote was so “bad”.
The metaphor in this article fits perfectly- the developer who wrote this borrowed from the future, and without being there at the time, I can’t really judge their calculations.
Also, ugly code that solves a problem for your customers is worth more (ie. is more 'good') than pretty code which doesn't. Customers don't care what the back-end looks like, they just want their problem solved, and pretty code never increased revenue.
I’ve always found the metaphors around Technical Debt really interesting. They simplify it to a point where everyone “gets it”; however I have often worried whether there’s a cult of “anti-technical-debt”, much like there are the cults of “absolutely no credit card debt / usage ever”. Sure, it works for some, but I’ve also seen product progress completely halt over the argument of “that’s adding to our technical debt”, surely it would be phrased better as “this is adding to our customers experience, at the cost of our chase for purity and technical perfection”?
As has been said a few times in this thread: there’s nuance to engineering, and a careful trade off. I think the metaphors are weaponized to a point where that nuance is lost in harsh memories of student-era credit card debt.
I know most here are focused on the dev side of things, but coming from the sysadmin side where I've had to deal with the technical debt of devs + the entire rest of the business IT technical debt, it is anything but good.
I've seen the insides of hundred of companies, and the number one cause of technical debt is lack of proper manpower to work ratios. Usually due to short term thinking of IT as a janitorial cost sink instead of as an investment.
any company that can break this mold is going to be light years ahead in the long run, because I have a secret to tell you all...
The infrastructure holding most businesses up is set to crumble at the slightest puff o wind, whether that wind be legal, like a lawsuit or an audit, or technical like an internal data breach...
"If there's a chance that the code you're writing will never be touched again, why bother to invest a lot of time in it?
In that case, leave some Technical Debt at the end and allow the next requirement to drive a better design."
I found the article excellent and I like the financial debt metaphor a lot. However, the quote above is somewhat confusing. I usually get rid of technical debt (post task) so that a developer can read and understand the code better. They need to do this in order to make some future unknown change. Since a "better design" would at least involve understanding the current design then a strongly disagree with leaving technical debt in code you do not think will be touched again.
While it's excellent to make the code readable for the next guy, I read this as talking about the architecture level, where reading the code will be largely unnecessary because it is all junked for Rev.2
I did this for one SAAS company and it worked out great. Although I had been very much a design-everything, pre-optimize excessively type of coder/designer, for this project at a company I co-founded I went completely the opposite direction.
With only a slight nod to the architecture I expected we'd need later, I just coded up the first version in the easiest high-level tools we had, separating only one module. This allowed us to get a much better handle on the actual requirements, especially since the marketing guys of course went out and sold some of the prototype. Fortunately the sales were small enough that we didn't get swamped, but it gave me real data, and strongly reinforced my plan to build a highly modular set of interacting services such that each could run on separate hardware, which could also be scaled in hours. This very scaleable architecture later allowed us to take business from competitors who were (AFAICT) were stuck in a monolithic architecture.
But after the first version had served it's purpose, no one has ever read any of the code again in the 15 yrs since. We just started on the main version and never looked back.
So as a person who formerly would have recommended the opposite, I can strongly recommend making a really brief Plan A prototype / first version that you plan to throw away. Just make sure that you do actually throw it away, and soon (code that sort-of works does have a way of sticking around too long).
There's a fine line between iterative development ("first do it, then do it right, then do it fast") and actual technical dept caused by bad practices (e.g. copy-and-edit instead of re-use). The former method is well-aware of shortcomings and heading towards eliminating them eventually, so I'm not sure if it should even be called technical debt. Actual technical debt (like real life debt) has the problem of "interest" attached to it, so it grows exponentially. So if you're not constantly working to reduce it, it may grow out of hand quickly.
[+] [-] zeroxfe|8 years ago|reply
I think this is both an art and a science, and the right balance comes with not just engineering experience, but also domain experience, team maturity/talent, market/competitive pressures, leadership, and culture.
There are so many factors involved that it's not surprising so many projects accrue horrible debt.
[+] [-] humanrebar|8 years ago|reply
When that's the level of awareness the average development team is dealing with, there's limited practical purpose in exploring the nuances of healthy debt management. It's more useful to talk about technical debt like nutritionists talk about empty calories and transfats.
[+] [-] nautilus12|8 years ago|reply
Why bad for you thing is actually good for you. or Why thing everybody likes is not so great after all.
Is everyone on hacker news just a compulsive contrarian?
[+] [-] CydeWeys|8 years ago|reply
[+] [-] reificator|8 years ago|reply
No we're not.
[+] [-] grigjd3|8 years ago|reply
[+] [-] tommymachine|8 years ago|reply
It is a strange phenomenon, that the brain tends to ignore things that are expected, and is often jarred by the unexpected. It’s maybe one of the downfalls of expecting the unexpected. Because it makes even the unexpected seem ordinary. Or maybe the reverse is true, and expecting the unexpected makes the ordinary seem extraordinary.
I’m gonna go and have some breakfast.
[+] [-] humanrebar|8 years ago|reply
[+] [-] thisisit|8 years ago|reply
[+] [-] onion2k|8 years ago|reply
[+] [-] spaceribs|8 years ago|reply
[+] [-] Finnucane|8 years ago|reply
[+] [-] bad_user|8 years ago|reply
We agree!
I woke up immediately because that isn’t possible.
[+] [-] DoreenMichele|8 years ago|reply
[+] [-] matte_black|8 years ago|reply
[+] [-] unknown|8 years ago|reply
[deleted]
[+] [-] Dowwie|8 years ago|reply
[+] [-] allyjweir|8 years ago|reply
Joining a team that is scared of technical debt and runs circles round themselves in a bid to avoid it end up producing more debt than they would otherwise. For example, making code overly DRY and wrong abstractions coupling unrelated parts of the system unnecessarily.
We must embrace the reality of technical debt. It is unavoidable and not something to be scared of. It can be managed by keeping things simple, clearly tested and keeping a cool head.
[+] [-] wvenable|8 years ago|reply
That's just another form of technical debt. Over-engineering is also a well known cause of debt accumulation.
[+] [-] spdionis|8 years ago|reply
I would say that's just bad engineering due to lack of insight or experience. DRY is the most simple and most dangerous principle (or "best-practice") of them all, because when it goes wrong it's the one that hurts the most.
[+] [-] wes-k|8 years ago|reply
[+] [-] bcbrown|8 years ago|reply
When you're writing it the second time, you're accruing technical debt. You pay it off when you refactor for the third component.
[+] [-] bpicolo|8 years ago|reply
[+] [-] skrebbel|8 years ago|reply
Compare that to the other kinds of debt (convertible, for instance). They cost a lot of time to obtain and, potentially, a lot of money in the long run if you do well.
Many of the most successful startups had (have?) shitty code. Of course there's great counterexamples (i.e. WhatsApp having a 5 person backend team when they were acquired), but as a programmer and founder I find that my urge to make shitty code and ship fast is waay smaller than my urge to make fantastic beautiful code.
Of course shipping fast does not imply writing crap code in general. At all. But sometimes it does, and when it does, I've learned that hard way that maybe it's better to choose the crap code.
[+] [-] j45|8 years ago|reply
When I'm a little more aware of technical debt being created - I track and manage it just like a feature or a bug in the project management system. Separate type, label or category of ticket. It surprising several tools don't have this out of the box for some reason.
There's a few benefits to technical Debt being categorized separately:
Tracking technical debt helps provide a sense of the technical debt tickets that are being opened, and floating around both in numbers, size and unknowns.
Keeping technical debt items tracked along side features, and bugs in it's own category is an invaluable form of cross-training to new team members who are learning the why the current code base came to be how it is, and not just what they may see or think is best.
We see how good we might be as a team and individually at identifying technical debt, and if we are improving at identifying it, and help develop a ratio for future accuracy.
Regular technical debt review helps create a sense of what technical debt is occurring, and what can be fixed under the hood on another project, if desired, or possible.
Keeping an eye on technical debt is important too, if something initially small is at risk of painting the project into a corner, or becoming exponentially difficult to re-factor.
Would love to hear strategies and tactics you might use in your TD practice.
[+] [-] convolvatron|8 years ago|reply
[+] [-] gowld|8 years ago|reply
http://www.ontechnicaldebt.com/blog/bad-code-isnt-technical-...
[+] [-] arethuza|8 years ago|reply
Looking at technical debt in isolation and always regarding it as a bad thing always seemed simplistic to me.
[+] [-] humanrebar|8 years ago|reply
[+] [-] davidhyde|8 years ago|reply
[+] [-] monksy|8 years ago|reply
Articles and handwavy comments tend to dismiss technical debt as a shrivelling pesky geek who keeps waxing on about how vi is better than emacs. (Someone who doesn't have a lot of influence, nor as important).
Pushing techincal debt to be managed by the PO, Scrummaster, busuiness, and/or managers creates major concerns and problems with what you're producing. The passive agressive response: "well convince them" is naive and wrong. They don't care. If we've seen anything from the experiences below, they just end up hoping those days won't come.
Examples:
1. Experian- I'm fairly confident that they had at last one engineer there that bitched about how much the dependencies were falling behind. If they have good ones, there would have been talk about how to automate that process.
2. Half baked products/data loss bugs - (See mongo)
3. Frequent "redesigns of projects" - There are major companies out there that have had to redo their entire product range due to this. It can't possibly be affordable. I'm sure theres lot's of lessions on the migrations. But it's a lot more expensive in the long run. Side rant: I guess if you believe that you're going to go out of business tomorrw, this is justified.
My point:
1. Be a professional developer, get deep knowledge on frameworks
2. Take your time and develop correctly at the start
3. Build experience with engineering, not the latest JS library that ignores experience.
4. Actually give a shit. Venkat Subermanian made a great qoute at one time: Your code quality is a reflection about how you feel about yourself and your coworkers.
[+] [-] hinkley|8 years ago|reply
Scapegoating the business is the easiest thing to do. But when push comes to shove they just don’t want to put in the work.
[+] [-] ericmcer|8 years ago|reply
On the other hand, it is nightmarish to toil through some tightly coupled mess and try to rewrite it in a manner that is more maintainable.
One makes you feel happy and in control, the other makes you feel like everything is falling apart.
[+] [-] bcbrown|8 years ago|reply
I'm doing that right now, and it's great. There's several responsibilities that are all tightly coupled, and I'm pulling them into multiple components. It's requiring a lot of code archeology and reverse engineering of intent, but it's incredibly satisfying at the end.
[+] [-] mikekchar|8 years ago|reply
The idea of technical debt is that you are trading some kind of completeness/correctness in the code for something else that is valuable. Usually that valuable thing is time, but it can be something else. For example, perhaps you know that your requirements are wrong. However, the client is unhappy with answering questions. You could pester them some more, or you could implement the obviously wrong requirements and wait for them to find the problem themselves. In this way you defer the frustration of your client to a later time when they might be more approachable.
It should go without saying that you should almost never do the above: I'm only using it as an example of tech debt that isn't to do with saving time.
There are lots of times where technical debt is beneficial. The key is to understand the cost/benefit. This is where we usually go wrong. The cost/benefit analysis is usually done by someone who only understands the benefit. It's just making the analysis of borrowing money and making the assumption that you don't have to pay it back. Hmm... how much money should I borrow in that case? Obviously, as much as I can get!
[+] [-] candu|8 years ago|reply
[+] [-] bloudermilk|8 years ago|reply
[+] [-] snowwrestler|8 years ago|reply
That said, there are definitely early technical decisions that will be very painful to change later on, like how you authenticate users and protect PII.
[+] [-] unknown|8 years ago|reply
[deleted]
[+] [-] nwhatt|8 years ago|reply
The metaphor in this article fits perfectly- the developer who wrote this borrowed from the future, and without being there at the time, I can’t really judge their calculations.
[+] [-] taneq|8 years ago|reply
[+] [-] dayjah|8 years ago|reply
As has been said a few times in this thread: there’s nuance to engineering, and a careful trade off. I think the metaphors are weaponized to a point where that nuance is lost in harsh memories of student-era credit card debt.
[+] [-] arca_vorago|8 years ago|reply
I've seen the insides of hundred of companies, and the number one cause of technical debt is lack of proper manpower to work ratios. Usually due to short term thinking of IT as a janitorial cost sink instead of as an investment.
any company that can break this mold is going to be light years ahead in the long run, because I have a secret to tell you all...
The infrastructure holding most businesses up is set to crumble at the slightest puff o wind, whether that wind be legal, like a lawsuit or an audit, or technical like an internal data breach...
[+] [-] davidhyde|8 years ago|reply
I found the article excellent and I like the financial debt metaphor a lot. However, the quote above is somewhat confusing. I usually get rid of technical debt (post task) so that a developer can read and understand the code better. They need to do this in order to make some future unknown change. Since a "better design" would at least involve understanding the current design then a strongly disagree with leaving technical debt in code you do not think will be touched again.
[+] [-] toss1|8 years ago|reply
I did this for one SAAS company and it worked out great. Although I had been very much a design-everything, pre-optimize excessively type of coder/designer, for this project at a company I co-founded I went completely the opposite direction.
With only a slight nod to the architecture I expected we'd need later, I just coded up the first version in the easiest high-level tools we had, separating only one module. This allowed us to get a much better handle on the actual requirements, especially since the marketing guys of course went out and sold some of the prototype. Fortunately the sales were small enough that we didn't get swamped, but it gave me real data, and strongly reinforced my plan to build a highly modular set of interacting services such that each could run on separate hardware, which could also be scaled in hours. This very scaleable architecture later allowed us to take business from competitors who were (AFAICT) were stuck in a monolithic architecture.
But after the first version had served it's purpose, no one has ever read any of the code again in the 15 yrs since. We just started on the main version and never looked back.
So as a person who formerly would have recommended the opposite, I can strongly recommend making a really brief Plan A prototype / first version that you plan to throw away. Just make sure that you do actually throw it away, and soon (code that sort-of works does have a way of sticking around too long).
[+] [-] blauditore|8 years ago|reply