Three Kinds of Good Tech Debt(engineering.squarespace.com)
The article links tech debt to financial debt early on, and this is exactly what the analogy is - it is best to be as literal as possible about it.
What is good debt? It's taking money from someone, promising to pay them back more money in the future, and using the original money to make even more money than that, so both you and the lender profit.
Good tech debt is just the same. It's taking shortcuts now to save time and get something shipped, knowing that it will cost you more time than you're saving now to fix it later. But by shipping now, you ensure there is a later, with a product that's out there and being used, a bigger team and therefore adequate time and then some to fix the debt and keep improving the product. Everyone wins.
That's the theory anyway. I think mostly where it goes awry in the wild is people forgetting the paying it off part. Part of this deal is you have to pay back your lender - they have to win too. It's just easily forgotten because you're the lender, so the incentives get a bit conflicted, and you'll keep giving yourself more time. But if the lender ultimitely doesn't get paid back and loses, you lose, and it's a bad debt.
One important difference between tech debt and financial debt, is that if the project you accrued a bunch of tech debt in gets killed for unrelated reasons before it's completed, your debt is forgiven. You never pay it off, and you never have to.
When you're validating an idea, don't worry about making everything perfect. Worry about validating the idea. Once you're more confident that you're actually gonna do it long-term, then it starts being more beneficial to pay off the tech debt.
I think what you're saying is the more common use of "tech debt", basically just using it as a synonym for "bad code". Don't worry about code quality, figure it out later.
It ignores the stronger debt analogy -- sure, there is a high chance that the idea fails. But if it succeeds and, all else being equal, you have taken on a less tech debt to get there, you will be able to iterate on and grow it more efficiently. So to the extent you're taking on debt, it should be an explicit trade-off to increase your chances of proving out the idea. Which is not the same as "don't worry about bad code at all."
From what I've seen, when it comes to talking about tech debt from an early prototype, it's often an excuse/euphamism to be considerate to the people that wrote it. The truth is often that it's just bad code due to them being inexperienced or lacking the skill or discipline to write better code. Which I don't mean as an insult, it seems like there's a strong inverse correlation between the kind of person who's passionate enough about product over tech, and is creative/naive enough to build and validate a brand new product, and the kind of person who understands enough to architect a great system and make the best tech debt trade-offs.
I absolutely agree - that's the whole point of the article and my comment. If you're in an experimental space, and 9/10 of your ideas are never going to make it to market, I'd rather spend 1 units of time on each to figure out which one's going to work, and then 20 units of time redesigning it the right way (i.e. 21 units of time to be done), rather than 10 units of time on each to make them all ready for production (i.e. 100 units of time to be done). But those ratios will vary depending on how sure you are about what needs to be done next, so yes - you've gotta weigh the cost / benefit.
> One important difference between tech debt and financial debt, is that if the project you accrued a bunch of tech debt in gets killed for unrelated reasons before it's completed, your debt is forgiven. You never pay it off, and you never have to.
This happens with financial debt as well. It's the risk that drives interest rates. Financial debt is abandoned (or restructured) when people or companies file for bankruptcy, when homes are foreclosed on, etc. Sure, it might ding your personal credit history in some cases, but financial debt is constantly abandoned at little or no cost to the borrower.
I thought interest rates were more driven by inflation. Mortgages are insured, for instance, removing much of the risk, but you pay for that insurance much of the time (THAT'S driven by risk), but $500,000 is worth more now than it will be in 30 years, so you're gonna have to pay to get it fronted to you.
Maybe a better word than "technical debt" is "rusty Ferrari".
Would you accept a free rusty Ferrari tomorrow? If it would take $60k in repairs to get into usable form, and probably not that great even if you put in those repairs, which you have no inclination to do, probably not. Especially if you couldn't easily sell it. If you were a broke college student and it was in roadworthy condition, and you had no other way to make it to your job - probably you would.
This captures that it's not really that you're "$60k in the hole" if you accept the free rusty Ferrari. In a sense, yes, you are.
I propose rusty Ferrari as the new, more precise term for technical debt. "We have a lot of rusty Ferraris in our garage" isn't a debt, but I think might capture the meaning. "I don't want a rusty Ferrari in my garage" = I don't want this technical debt. Let's make it work with some rusty Ferraris = let's cobble together a hack we should probably throw away.
what do you guys think?
There is no difference. Regular debt is also discharged in bankruptcy.
But that affects your ability to borrow in future, whereas a canceled project doesn't affect your ability to write rushed code in future. Unless you get fired, I guess...
You’re nit-picking when I think the analogy is clear but it doesn’t effect your credit if the company you work for declares bankruptcy, so the comparison to the company’s tech debt seems to hold up even if you push it.
The whole thread is nit-picking. The point of bankruptcy isn't "fuck being fiscally conservative - we don't even know we want the stuff we're buying so who cares if we can pay our credit card bills", whereas that's literally how you should approach some projects.
Commercial lending has this component as well. Any real estate operator working at scale will have some experience with giving this or that project back to the bank.
Isn't that more of a similarity than a difference? When financial debt gets overwhelming you can declare bankruptcy and abandon the project as well.
No. Bankruptcy doesn't just eliminate the debt and let you move on consequence-free - it's a legal process in which a plan is put in place for everyone to get their fair share of what's left, or to recover from the debt without the debt itself destroying future productivity. It can also be very detrimental to your credit opportunities. If you abandon a project, you're just never going to repay the debt or suffer from any consequences of it.
delete the whole code (or just throw away the keys) and all the debt is paid.
> I think mostly where it goes awry in the wild is people forgetting the paying it off part.
Which also fits the financial debt analogy perfectly.
What would bankruptcy be analogous to... the business going under? Having to rewrite the application due to unmaintainable code?
Probably a rewrite – HNers always seem to have stories about being brought in to work on companies with incomprehensible rats nests of code that are impossible to extend any further. I bet that's pretty common, more common than technical debt actually forcing the company under.
Still if you really want to take the analogy further declaring technical bankruptcy could cause business bankruptcy (see Joel Spolsky). You probably want to refinance your debt and get onto a repayment plan (an incremental rewrite) instead.
The key part analogy isn't bankruptcy so much as interest. You incur technical debt and you pay it off later in interest (by spending time to clean up the hacky code). If you don't pay off the interest, you end up incurring even more technical debt. Eventually, you could end up paying several times more in interest than the principal (end up spending more time working around the hacky code than if you've just addressed the issue properly in the first place).
Bankruptcy is more correctly letting you get away from obligations to creditors with lesser terms to the creditors than originally agreed because you can no longer pay it back. I think there’s nothing very close to this for technical debt because even in a rewrite there’s new debt involved. A rewrite is a lot closer to refinancing where the value of the asset is re-evaluated and new terms of debt repayment are structured that stakeholders agree to. Most people seem familiar with chapter 7 bankruptcies but there’s 11 and 13 too. Furthermore, bankruptcy is about handling an original amount lended - rewrites oftentimes are done with lessons learned from the original version (rewriting from Python to Go isn’t bankruptcy).
Technical debt bankruptcy is probably closer to shutting down a service / product with no replacement - the effort has already been spent and you’re walking away from costs without caring for the creditors (customers and engineers alike).
The question of whether technical debt can be zeroed in a technical bankruptcy is who the creditors of technical debt really are - is it the business as a whole or the engineers that maintain this stuff?
To me, the state of technical debt bankruptcy is a business in a zombie state unable to grow to service the debts because of the technical debts keeping them uncompetitive rather than something more fundamentally wrong with the business like product market fit or bad reputation.
Virtualization probably comes closest for a subset of scenarios.
Bankruptcy occurs when your debt exceeds your ability to it off. I suppose that would be the point at which it's easier and cheaper to write new code than try to fix the old code. The debt can no longer be paid back. That said, somehow there are still COBOL programs running, so even though that program should shut its doors and liquidate any useful assets, real world money prevents that from happening.
oh it definitely is a rewrite
Ward Cunningham, who coined the term "Technical Debt", would often use the analogy "If you borrowed $500K for a house that is now worth $1M..."
Michael Feathers said that he doesn’t use the term when working for banks as they don’t see it as a negative term...
A big part of technical debt is that often... you just don't have to pay. This is what makes the comparison to financial debt a very poor one.
Whenever I'm moving from one framework to another I find loads of todos I can now delete. Or even if I have a well designed class, if I can find a nice third party library that does the exact same thing, I can now get rid of all that useless code and any debt around it.
Honestly I think calling it technical 'debt' makes programmers unreasonably averse to it, but unfortunately I haven't been able to come up with a better term.
So you're declaring tech bankruptcy.
Tech debt is mainly a problem with code that needs frequent updates as it makes changes harder.
If you have messy code that doesn't need updating, then it doesn't cost a thing to leave it in a bad state. The act of refactoring in these cases is a waste of effort and often does more harm than good by introducing bugs.
I take the YAGNI when it comes to refactoring. Just pay back the stuff if the code actually slows you down in the future instead of doing it in advance.
There is a lot of tech debt you can get away with for free without ever having to pay back.
> The article links tech debt to financial debt early on, and this is exactly what the analogy is - it is best to be as literal as possible about it.
Financial debt has a clear quantitative measure.
Tech Debt is an incredibly fuzzy concept, even as a qualitative measure, to the point of being useless for anything other than covering one's ass. We can do better as engineers than resting on such fuzzy thinking.
I'm curious what you think is better. Any links you could share? I suspect you're wrong, or not quite right, tho. Technical debt is a great analogy and even if it's fuzzy, being able to think about the relevant tradeoffs in a familiar way is too useful to ignore.
Surely there are situations in which it's only useful to cover one's ass, but often it's a great way of explicitly understanding specific tradeoffs being made.
At any given crossroads in a business endeavor, you encounter a problem.
Now you have two choices:
1) You select and articulate your assumptions. You select and articulate your requirements. You also may try to capture and articulate your Black Swan list of unknowns and risks. The key thing is that you are clear. Clear what you know and clear about your concerns and risks. You then articulate your solution, holding it accountable to your assumptions, requirements. And then you move forward.
- or -
2) You come up with some solution sketch. You have a general vague notion that it isn't ideal. You're not sure why but it just doesn't feel right. You need a way to psychologically contend with this vagueness. So you give the vagueness a name. The first thought that comes to your head is: "Vague Notion That This Design is Not Very Good". This is not very flattering to your ego. So you think a little bit more and come up with: "Tech Debt". And you like this, because it sounds quite nice. It sounds like you're back in control, that you know what you're doing. You proceed to blame the design deficiencies over time to "Tech Debt". Everyone nods their heads.
I work on a product with a large amount of tech debt, and that debt was almost universally created using the methodology in your first category. Most of it is extremely well documented. That doesn't magically make it not technical debt.
Debt implies you consciously accepted it.
What you’re describing with your product is the fruit of unskilled (amateur) labor.
Yes, it's a nebulous metaphor. Taking it too seriously is a mistake. But I'm not sure we can do much better? What would you suggest?
I like the Go concept of aji  but that's too obscure, nobody will get it. Maybe something like "unfinished business" would work? A nebulous term for a nebulous concept.
What I suggest is you try to run a project and deliberately avoid reaching for the concept of "Technical Debt".
You will find yourself squirming a little. It will be uncomfortable at first. But if you hold to your guns, you will find that you're forced to speak in much more clear terms about your process and decision-making.
And you will certainly find yourself saying humble things like "I have a sense that this isn't the best solution, but it's all I got right now."
But over time you'll find yourself improving. You'll find yourself saying "I have a sense that this isn't the best solution -- oh, you know what I just realized, this design choice is going make this other requirement over here nearly impossible to implement."
And with this kind of clarity you'll be in a much much better position to navigate the territory ahead and make clear, conscious decisions based on what you know and don't know.
"Tech Debt" is simply a way to dodge -- e.g., dodge the discomfort of not knowing stuff, of holding yourself to clear thinking, of admitting the need to improve...
A little trickier maybe in that some tech debt is in the eye of the beholder. Some may consider an Angular UI tech debt, others might consider it an asset versus, say, React + whatever other parts it needs.
Two points I really enjoyed:
> Not Fixing All the Edge Cases
We’ve all seen bugs that occur so rarely, and fixing requires destroying some part of the original design architecture. The ability to acknowledge these types of bugs as not worth fixing is liberating.
> Err on the side of building too little because you can always build more later. Build things to be easy to throw away and replace;
I find developers tend to really dislike throw away code or temporary solutions knowing they might break in the future. If the quick hack is well documented, written in a very encapsulated and removable way, who cares about removing it later.
Writing hacks and throw-away stopgap solutions is generally a bad idea in reality. The only time when it can actually be allowed is when it it concerns a feature that is a pure leaf in the system with nothing else built on top of it. If you violate this rule and build other features on top of shortcuts, two things will inevitably happen: you will have to replace the shortcut with a proper solution eventually (it is only a matter of time) and by the time this happens, the assumptions underlying the shortcut have implicitly been taken on by the code depending on it. This means that you will have to review and replace a lot of dependent code as well.
I have gone through that dance often enough. It ends up being more time consuming than doing it right in the first place each and every time.
Yes, it's more time overall, but that's not the point.
From the example in the article, if it would take them 2 months to build a robust email delivery system or 2 weeks to put a temporary hack in place, it could be worthwhile to the business to do the hack if it means they can start user-testing 6 weeks earlier.
Also, if they're still in the product-fit stage of their business development, they might find that the product isn't as useful/worthwhile as they thought, and scrap it after 2 weeks testing. This would allow 6 weeks of overall developer effort to be spent on another initiative.
Just because you know that developing throwaway code is waste, doesn't mean it's necessarily a bad business decision.
Is it worth the while when you have to spend more than weeks to do it right later? Again, in general it is not. You are citing a very, very specific business reason as a justification. In 99% of all cases, no good business reason exists to waste more money later. Essentially, this is what you are asking. In your example, it's either 8 weeks total to do it right in the first pass or 10+x weeks total to do it right later when you have the still unquantified extra overhead of not breaking stuff that has been built around the insufficient solution.
You have to look at it differently: if you hack something in two weeks, you will:
- be able to switch to other, more important tasks more quickly;
- allow the business to better discover what the actual requirements are while they have an MVP solution in place.
Resources are finite: you only have a limited number of engineers, and the business needs to be moving forward. This approach allows you to do so, while mitigating a lot of risks at the same time.
The costs are not lost: they bring back business value in terms of fast progress, and mitigates risks.
That is actually the point of the metaphor. Taking on debt without a clear business reason is supposed to sound bad.
Not all spending is wasteful, even when, in an ideal scenario, it could be avoided.
I like that delineation between branches and leaves. If it’s a branch, solve the real problem. If it’s a leaf, consider just getting it done.
Writing hacks and throw-away stopgap solutions is generally a bad idea in reality. The only time when it can actually be allowed is when it it concerns a feature that is a pure leaf in the system with nothing else built on top of it.
I worked at a company where there was an API and an explicit place for such hack code, for consultants to customize the product. The way it was done, was to ensure such code was a pure leaf.
> by the time this happens, the assumptions underlying the shortcut have implicitly been taken on by the code depending on it.
If this has happened, your encapsulation was insufficient or you waited too long to replace the stop gap solution or maybe your documentation wasn't clear about what assumptions made by the throwaway component are safe to make in the main codebase.
> The only time when it can actually be allowed is when it it concerns a feature that is a pure leaf in the system with nothing else built on top of it.
I think the article's description of when stopgap solutions should be used is far better. Yes, a leaf feature is likely to have fewer encapsulation issues, but that is only part of it.
Another way to say this could be if you decide to take the route of explicitly not solving an edge case or write throwaway code, that feature becomes a leaf until the branch of immature code can be pruned and a new, stronger one put in place.
It doesn't become a leaf automatically. You have to force it to stay a leaf. If you don't find a way to do this, and if things grow on top of it, then you are in trouble. This is hard to do in most architecture patterns.
"Crap is OK until you build on top of it. Then you need to clean it up."
Building things to be easy to replace often does not mean quick hacks. Quick hacks are most likely hard to trow away, not easy.
Building things to throw away means componentizing your code, that is extra work overall.
You are right. You have to make architectural choices to build a soft layer that can absorb such hacky throwaway code that can be pruned easily later. Usually a hard platform layers sits underneath it and supports this. Following Conway's law, usually there are teams to build and enforce the platform constructs that are relatively debt free and there are teams that work on the soft application layer on top of those platforms where these throwaway hacks can be easily put. You have to design for this in your architecture. But if this strategy is right for your business domain, then once you make the initial investment, it will pay for itself multiple-folds. You will see this pattern in online gaming code bases.
> Building things to throw away means componentizing your code
No it doesn't. You can really tell who has and hasn't worked at a start-up by the responses to OP.
He's right that it doesn't mean quick hacks, but it doesn't really mean "componentizing" either. It means keeping it simple. Don't over-engineer it (componentize it) but don't use some ugly hack or cut-n-paste off SO either.
I’m not sure how you can have such a strong no reaction to a statement that can mean almost anything.
The word “component” barely means anything at all. Lots of room for interpretation there.
What does it mean, then?
>If the quick hack is well documented, written in a very encapsulated and removable way, who cares about removing it later.
I do. I care very deeply about removing it later.
The problem is that encapsulation is often mistaken as a strong justification for existence, and code that is written tends to justify its existence just by existing.
That's to say that once code is in production, it's scary to delete. It's much less scary to delete a couple of lines of inline code wrapped in a comment that says "this is a hacky solution," because code that isn't encapsulated probably probably isn't used elsewhere. Or if it is, it's copy-pasted.
The scary thing about removing encapsulated / abstracted things, is that oftentimes, other things refer to them, unbeknownst to the original author or their intent.
It's pretty common (especially on larger teams) - the first developer writes up a hacky solution, the second developer abstracts that hack into a module due to some sensibility (abstraction, aesthetics, organization, etc), so now the hack has legitimacy. A third (or often the first developer) sees that the hack is in a module, assumes that the person who put it in a module had more information than when the hack was written and that it's now a first class member of the system. And first class members of a system take thought and time to delete.
It sounds like a lot of those problems could be solved, or at least mitigated, by better communication between these developers.
Right, except that communication between developers is the least scalable part of running a software team. For every new member you add, there are n existing developers to communicate with, so your communication costs go up as O(n^2).
If the goal is to grow a piece of software over time (as in many startups), any architecture that relies on "better communication" is doomed to fail, simply because it limits the size of the team that can handle it (and thus growth).
That's true, although I would expand communication to encompass code comments and other documentation, which can scale better.
Encapsulation shouldn't be used to make it OK to remove something later; it should be used to make it OK to replace that thing later.
Then your hacky solution goes on the inside, as inline code, and then it's no problem to delete it.
> Not Fixing All the Edge Cases
This can also be a part of tackling very complex tasks. To prevent getting overwhelmed when implementing something huge, I sometimes do what I call, "Implementing something stupid." Want to build an MMO? Build something that manages to send sync information to a multiple clients, but ignores auth, security, being cheat-proof, robustness, etc... Then once there's something running, start addressing those issues.
So instead of not fixing all the edge cases, it's not implementing all the edge cases all at once.
If the quick hack is well documented, written in a very encapsulated and removable way, who cares about removing it later.
When it starts causing "lava flow" then it's time to remove it.
> I find developers tend to really dislike throw away code or temporary solutions knowing they might break in the future.
IMHE, it's usually management that feels this way.
> I find developers tend to really dislike throw away code or temporary solutions
This is good way to level up: Learn to love throwing your code away!
Maybe programmers need to listen to Marie Kondo more.
"Does this code bring me joy?" :P
does this for loop make me happy?
It's also great that the author gave concrete examples of times where it made sense to eschew purity for pragmatism. Very good article all-around.
I love throwing away code!
We found a better way to do this - boom, you're gone!
I do dislike coding solutions which I know to be temporary, sometimes it's necessary but it feels wrong if we already know something's not going to be adequate.
That said it's also very bad to future proof (by which a lot of people mean abstract) the code to be able to do everything you can possibly think of that might be needed in future, or even (and I've seen this attempted) things we might possibly want that we don't even know about and can't think of!
My thoughts on this is that a code base is a living thing. Things go out. Things go it. We have a history of every change made (and often you can interpret the reasons why)
> If the quick hack is well documented, written in a very encapsulated and removable way, who cares about removing it later.
That's fine in a system with a small number of quick hacks. In reality, the number of quick hacks grows over time and you end up with a brittle system that has a lot of unanticipated behavior that only a few people understand how to work with. You will eventually have quick hacks that exist to fix bugs in the other quick hacks.
I like the framing of tech debt as value-neutral; whether it's good or bad depends on how you use it (just like financial debt). Of course, all else being equal, you'd rather have zero debt.
One higher level consideration that's particularly relevant for early-stage startups, is that you often simply don't have time to build the ideal "tech-debt free" solution. Focusing on 80/20 solutions almost necessarily involves adding tech debt. However, if you're mindful about where you take on tech debt, and commit to tapering and then paying it down as your resources grow, then you're more likely to avoid the debt spiral where your development grinds to a halt, due to everything breaking all the time.
One other point I'd make is that a common form of "tech debt" for early-stage startups is simply doing things that don't scale; it's often beneficial to make your domain models flexible so that you can support one-off manual interactions, for example if a new customer appears that requires it. Then automate that thing and constrain the domain actions once you have collected enough use-cases to know what makes sense to forbid.
I like to point out as well that it isn't tech "debt" if there's no "IOU". For instance, in the hard-coding example, it's conventional wisdom to avoid hard-coded magic constants for a few reasons including it sometimes is hard to figure out later why a magic constant was used, and in an if/else branch situation like that maybe tough to figure out when you can cleanly refactor those branches. If the case is well documented (it's the date of a given feature release) and the code reasonably factored already (the "off" branch isn't a ticking time bomb bug that needs to be removed after the date in question), then it may be a code smell, but it isn't necessarily an IOU to a future developer (such as yourself), so it isn't necessarily "tech debt", it was just a trade off made at the time. Of course, if a future developer adopts a hard linter rule against that sort of code smell, they may come to see it is tech debt retrospectively, but that's also where the analogy starts to get fuzzy.
(Pushing the analogy to a breaking point: Is adding a linter then, doing an audit and depreciating assets for "tech taxes"? Come to think of it "tech taxes" would be a fun alternative term to add to the "tech debt" family. "Hold on, just paying my tech taxes; npm install, npm audit, and npm run lint.")
I have a good example of no IOU. Friend 20 years ago worked on a content streaming platform. They needed a dispatcher and someone wrote one in TCL in a week. Just to get something working. And they never got around to replacing it because it worked 'fine'. Turned out while everything else needed to be hyper efficient and scale the dispatcher not really.
An unexpected tech debt jubilee!
A good talk about the "technical debt" metaphor.
tl;dr: Technical debt can be categorized on 2 axes: Planned vs unplanned, and high interest vs. low interest. Interest is paid down in pain. If you are not experiencing any pain, it's not actually tech debt.
Low interest, planned tech debt (akin to a mortgage) is ok because presumably the cost of the interest is lower than the returns.
High interest, unplanned tech debt (akin to a loan shark, or pawn shop) is best to be avoided, because you're experiencing a lot of pain probably without a clear vision for paying it off. You're just continually paying the interest/experiencing pain.
I don't like the metaphor. With financial debt, you get $X up front for $Y (where Y >= X) and pay $Y amount over N months. It's known up front what it's costing you (Y - X) over what time span (N). If the difference between Y-X is low, congrats! You got a great interest rate. If it's large, well, good luck!
But in both those cases, the pain is known up front. The discussion here seems to be no one knows what X is, nor Y, but it's expected that Y > X by some large amount that you may or may not have to pay off. Crazy!
I disagree about the pain being known up front - you are aware of an obligation and that obligations units in dollars, but how those dollars translate into future missed opportunities is unknown... additionally you always have some risk due to currency fluctuations if you're operating an international business, if you're primarily operating in AUD and payroll is in AUD but the loan repayment is in USD then a profitable quarter may end up being much less able to pay down your debt.
I agree that money is much more comprehensible, but there isn't so as stark a difference in knownability as it might initially appear.
The aspects of debt that you're focusing on aren't really relevant to how I use this metaphor.
Rather than trying to use the tech debt metaphor to actually calculate the interest rate, I think it's more useful at a higher level of abstraction.
When faced with the product decision to do more work now and build something better, or less work now and cut corners, what are the consequences of doing less? Without some way of conveying the long-term costs, your stakeholders will always push you to do the least work possible to tick the box.
The debt analogy is a universally-understood way of conveying the fact that if you cut corners, you'll likely pay interest later in the form of slower development speed. And if you take on too much debt, then all your spend will be going to paying off your interest, and your progress will stall. Non-technical people understand this analogy, and so it's a useful way of conveying the shape of the problem without having to start from first-principles.
As I’ve gotten more senior in my career, I think one of the most enlightening things has been anticipating debt before it happens (in planning/architecting), acknowledging it when it does and then taking prudent measures to minimize it and log it for future refactoring.
It’s also been funny seeing managers try to rebrand tech debt with other business speak like “tech health”. Debt shouldn’t be a bad thing but one that’s anticipated and respected.
"Health" of a system isn't synonymous with debt. It's what happens when debt isn't respected and becomes bad. Debt is a tool; health is a state. If you carry six months of salary as credit card debt,a financial advisor isn't going to talk about how you're using debt as a tool, they're going to talk about your "financial health".
Managers rebrand because their bosses and non-technical people start ignoring a term once it's used long enough, so we have to market it in another way.
There's also a distinction between "we made intentional decisions that we need to fix up now" and "We (or people before us) made unintentional decisions and it is in such a bad state that it endangers the health of the business."
The term "debt" is really helpful. It also explains that while you can pay off debts by taking on other debts, there is a good reason why this is illegal (if done with money) in the real world.
Technical debt in your solution is fine. Running a Ponzi scheme in your solution isn't.
> there is a good reason why this is illegal (if done with money) in the real world.
Erm, it very much isn't illegal. At least not in most places.
Taking on fresh debt to pay off other debt is the very definition of a consolidation loan which is perfectly legal in most, possibly all, jurisdictions.
There are limits of course, like not using a loan to pay the deposit on a mortgage, or simply not lending beyond defined means, but these are set by the bank to manage their own exposure to risk rather than limits set by law. Such limits are merely encouraged by law, via regulatory limits on standing capital compared to debt held and so forth.
also basically any 'balance transfer' option on pretty much every credit card ever.
In the brick and mortar world rolling debt is common.
I think debt is also useful for the interest metaphor. An unfinished kludge by itself may not be very expensive to fix up and change, but if that kludge doesn't change and becomes a dependency in a complex environment it is likely to become much more painful to fix later.
> while you can pay off debts by taking on other debts, there is a good reason why this is illegal
Loan consolidation is quite normal in the UK
Sorry, I was mentally adding "without the consent of both parties".
Because otherwise, what would stop you taking on a loan for X, then paying it off after a while by taking on the same amount from another bank?
> Because otherwise, what would stop you taking on a loan for X, then paying it off after a while by taking on the same amount from another bank?
Nothing. That's why lenders do credit checks and due diligence.
Absolutely nothing stops you. The bank you owe money to has no rights whatsoever to control where the payoff money comes from.
The bank lending the money may we'll care where it's going.
A bank's primary business is managing risk. And borrowing from Peter to pay Paul (having previously borrowed from Paul) is a significantly different risk profile than borrowing for investment or even present consumption.
In business/commercial lending the purpose of the loan is typically a part of the contract. You can’t say you will use the money to buy equipment and then use it to pay off another debt. Also you will have to provide regular (yearly/quarterly) financial statements (typically audited) that include a balance sheet that would list all outstanding debts and assets. As long as you abide by all your existing and future loan covenants you certainly can use loans to pay off debt and many people do. When you can’t it’s due to contracts, not “laws”.
I've also come to realise that technical debt is everything. Anything that is resistant to change is technical debt, which includes the code you are writing "now", whether you anticipate its need to change in the future or not. There's the stuff that you know is painful or messy, but then there's the stuff that is suitable for today's needs but those needs may change in the future. Nothing is free from debt.
Technical debt is a wonderful ally when building prototypes.
Imagine you are building a prototype and you are clever enough to only focus on validating an idea. Having this focus you ignore all best practices and maintainability issues you might tend to out of habit.
What you are likely to end up with is a functioning application that resists change beyond its original goals.
And this is good. It lets you declare technical bankruptcy early enough to avoid painful rewrites on a software that was not meant to exist for long anyways.
As long as both sides (developer, management) are aware of this (he says, as his "proof-of-concept" was installed into production directly by his manager with no warning).
Tech debt is inevitable and is good as long as you keep the level of debt reasonable, so maintanance cost doesn’t sunk too much of your dev time.
More good examples:
1. Technology progress: Long time ago JQuery was the best for UI library. Today you would use React or friends.
2. Company stage. As a early startup you usually prioritize for speed and validating hyphothesis. As you got a significant user base quality matters more.
3. Size of development team. With 5 or less developers having a monolite is good enough. With 50 developers you likely take more advantage of microservice architecture so each team can be decoupled and move faster.
> With 50 developers you likely take more advantage of microservice architecture so each team can be decoupled and move faster.
Microservices aren't magic. There still has to be a contract between the services. Microservices are best when they are something which need to be scaled independently of the rest of the system.
I think it's almost part of most companies' lifecycles that they start with a monolith, and anticipate rebuilding it as microservices if they get traction.
I prefer the definition of technical debt being an uncovered call option: at some point the debt will come due and you don’t have anything in place to mitigate the issues it will cause and may not know when it will come due. This debt might look like a manual deploy process, a lack of automated testing, insufficient alerting, no rate limiting on public endpoints, etc. These are things that are fine and then when they’re not, they interrupt the schedule and require urgent and immediate attention.
Bad architecture can cause urgent issues and it can also impact new feature development. The debt is a barrier that makes new features either take much longer than they should or make them just infeasible from a business standpoint. This can exist in both technical architecture or information architecture (i.e. you chose the wrong model and now it’s too engrained across everything to change).
Tech Debt is never good, but it can be acceptable in exchange for a greater gain.
So, just like this article's opening:
> Financial debt isn’t universally reviled in the same way. Your friend takes out a mortgage to buy a house and what do you say? Congratulations!
Except it is universally reviled, no one wants debt - they just accept debt in reasonable quantities as a way to efficiently get things done.
I think, in particular, the success of not-quite-agile-but-similar business practices has confirmed this, plan carefully and evaluate business needs, then get it done in a way that's fast and leaves you relatively free of debt - don't plan for everything. So don't get stuck in analysis paralysis trying to build the perfect things - and don't just code with no thought of the future... it's a difficult road to follow.
I'm not sure if I'd even consider these things tech debt. I tend to distinguish between:
1. Unfinished/unpolished implementations 2. Implementations that are architectural flawed, such that fixing them requires throwing away the existing code.
Issues in (2) are a lot more problematic than issues in (1).
Yea, I was going to say the same thing. Work undone as part of prioritization is not debt. Debt to me is causing more work than it would take otherwise so that less work can be done now (or because the developer / architect just doesn't know any better). Using a switch statement instead of a factory. Using role based auth instead of attribute based. Things like that.
The problem is, the debt metaphor is not being applied correctly. Not doing future work now does not take on responsibility for the future work - so it's not like taking a loan. Doing work in a way that commits the team to extra work that didn't exist before - that's like taking on a loan. For instance, I don't want to do this 80 points of work now, so I'm going to ship the same requirement by doing 40 points of work on a solution that will take another 60 points to get to the original 80 point solution which is the way we know we have to go long term. I just borrowed 20 points on behalf of the team.
I'm not sure how this classifies as tech debt, but in my experience the worst type of tech debt is found in parts of a system that is relied upon and whose business logic has become unmaintainable, is too complex/poorly understood and is not possible to throw away as too many things depend on it. Also usually whose initial creator is long gone, the documentation is conflicting with the code implementation. This kind of debt causes eternal confusion and constantly lowers the productivity of the team. In cases like these, workarounds are created and more tech debt accrues on top of it that is even harder to reason about. Nobody sane can fix a mess like this and the only hope is death of the system or complete overhaul.
Another kind of good tech debt I was hoping to see here is when something is built somewhat poorly/quickly because it will give you information that you need to have in order to know whether it's worth building it any better.
Prototypes are very valuable as long as you know to throw them away and build the real thing. The unfortunate aspect of many business environments is that low knowledge outsiders see something "working" and demand that it be thrown into production for [insert business speak reasons]. Tech debt isn't always a decision made by the subject matter experts.
I thought that was exactly the kind mentioned first:
> We realized we could build something cheap that we didn’t mind throwing away later—scaffolding—to unblock getting user feedback sooner.
If not, can you say more about the difference? I'm interested.
If you aren't spending tech debt, you don't have a sound monetary policy. Zero tech debt is not a healthy goal.
Unlike financial debt, which has a clear quantitative measure, Tech Debt is an incredibly fuzzy concept to the point of being useless for anything other than covering one's ass. We can do better as engineers than resting on such fuzzy thinking.
But that's the point. It is a fuzzy thing. Software is built on business priorities, not technical ones. These align a decent amount of the time. Spending the extra time and money to set up tests is very much worth it.
Is it worth implementing a cache layer in a system? One on hand, you have a better system that can handle more load, on the other, you've spent time that could be spent doing something else. Your systems will almost always have limitations, it's important to understand these and communicate them well. Tech debt should be managed so it doesn't tip over and cause issues. Really good devs and dev managers develop the eye to see when that's about to happen and make sure they convince product that you need to pay that down soon.
> Is it worth implementing a cache layer in a system?
This isn't a "Tech Debt" thing. This is a feature/scoping thing. Does my system need to handle 1M concurrent users? If so, support that. If not, don't support it.
But we don't need the absurd concept of "Tech Debt" for effective analysis. We can be specific. We can be clear. Does my system need to support low latency in the face of 1M concurrent users? Yes or no. Now proceed.
"Tech Debt" is such a ridiculous dodge to otherwise avoid real analysis, real work, real clarity.
I think it's pretty clear that there are often, clearly, no right answers to a lot of questions.
The answer to "Does my system need to handle 1M concurrent users?" could be "Yes", "No", "Not for the foreseeable future" or even "I don't know".
Given that 'debt' is a way to, in effect, allocate (possible) future resources today, it's pretty clear why it's valuable, especially in the face of uncertainty.
What you're saying is no one has perfect forsight.
That's a given.
You don't need the notion of "Tech Debt" to deal with that.
It is a complete given at any given time, during any given sprint, that all the features in the queue are ASSUMPTIONS.
That's just a tautology.
"Does my system need to handle 1M concurrent users?"
Maybe you answer Yes or maybe you answer No, but you have to answer something to make decisions about the work ahead of you.
The worst possible place is to be in the fuzzy middle saying fuzzy things like Tech Debt and rolling along fuzzily.
Many teams -- especially teams that love this term "Tech Debt" -- do exactly this.
But they are willfully navigating in the dark and "Tech Debt" is just a term that makes one feel psychologically okay with their ignorance.
But it's euphemism, that's all it is. It does not aid in rational navigation.
I don't like the term technical debt at all. It's really just a way of saying a feature is willfully incomplete in some respect. A feature that using pulls from git instead of having a CMS isn't debt-laden anymore than a house without a garage is.
The code review articles are good too: https://engineering.squarespace.com/blog/2019/code-review-cu... https://engineering.squarespace.com/blog/2019/code-review-cu...
I've always believed that "debt" is not a great term for this. Because it does not really apply to financial debt.
Financial debt is often repaid simply by bringing in more revenue because of the benefits gained from bringing on the initial debt. The only risk involved in the debt is that there will not be enough money to pay it back later. It is a very predictable and obvious issue.
Technical debt is closer to educated gambling. You are taking a risk that the shortcuts you are taking will not pop up and hurt your company before you fix them. You are essentially saying, "We know this is a problem, but we are estimating that it won't hurt us for the foreseeable future".
The better analogy to technical debt is investing. You are getting a certain percentage increase in productivity(a dividend or other capital gain) for the (hopefully low risk) gamble that your investment will not have a problem and wipe it out or simply cause significant losses.
Developers typically do not like this because when the inevitable few cases of these "investments" turn bad, they tend to be the ones that take on the majority of the blame.
To me they even sound the same after you explained them.
Not being able to pay back money sounds like the same as not being able to fix bugs.
Tech Debt, to me, grows with every line of code you write that didn't replace a line of code. Consider how many projects start with the idea, 'I'll rewrite this and get rid of the tech debt'.
First, If the original code isn't deleted, you've added to the tech debt. Now every new engineer will need to learn two chunks of code, and every existing engineer will need to support both.
Second, unless you've had a major epiphany between the old code and the new code, you're more likely to run into the trap of the first example. Major epiphany's could be, 'wow, we really didn't need all of that extra stuff', or, 'we've duplicated so much code, we should re-organize this all'.
I've been at plenty of companies where you have to understand that the Perl code is really old and these components use that, the Mason rewrite was 80% done and is over there, the Next Gen code was in Ruby these components do that. But now, we're embarking on a new Node/React project to replace all of it, finally going to get rid of the tech debt! (Said with no sarcasm)
And I would say that's an example of when it can be good to purposefully take on technical debt.
In my experience there have been plenty of significant refactorings that simply would not have been done if we didn't allow ourselves to get into this state where there is simultaneously an old and a new way of doing something.
Especially if it's an area that sees frequent addition - it's not helpful to have people constantly adding code in the old way while off to the side people are trying to create a new way and completely finish switching everything over to it before integrating.
Managing risk and balancing other active tasks in the pipeline also push towards integrating smaller pieces over time while multiple ways of doing the same thing exist.
But you need to have organizational continuity, which can be rare when everyone is trying to hop jobs for better salary every couple of years.
If tech debt is inevitable, what’s the solution? Good internal documentation and rewrites every few years?
a practice of constant refactoring..
Nicely done. Good to see an engineering blog acknowledging tech debt openly.
I'm with you all the way until the last paragraph which short-changed the conversation a bit. Quoting a few lines to respond below:
>> Build things to be easy to throw away and replace; it’ll make your code more modular.
One valid strategy to manage debt is to declare bankruptcy or amnesty on debt – that is throw away the code (because this code is no longer needed). In domains where this possible, definitely use it. But in most real-world touching software domains this is not likely possible.
>> Good tech debt has clear, well-known limitations. Document these in code comments, READMEs, FAQs, and conversations with the people who’d care.
Doing tech debt accounting in a more formal manner is required to intentionally take debt. In the locking example, it is a design debt (not just a code debt). If the debt isn't document well and then it can become a ticking time bomb to be tripped by a clueless developer later.
The defining characteristic of technical debt is attempting to avoid paying it, taking shortcuts that create "interest" in the form of increased effort and cost; it's always bad, but depending on timing and costs it can range from a "correct" minimum cost choice (e.g. badly tested truly throwaway code) to a stupid mistake to an existential threat.
Technical debt is a close relative of externalization (I save time, you waste time) and of mistakes that result from incompetence rather than from haste and shortsightedness.
All three sections of the article, instead, describe healthy planned evolution from a decent provisional product to a better one, with solutions that might be rough but not necessarily bad. In other words, a clickbait title for sound (but maybe unrealistically mature) examples of properly pragmatic project and product planning.
@1: One could also have automated tests instead of scaffolding.
@2: Sure, but this it not really technical debt. It is the wise policy of not immediately writing code for the most general case. If one writes several instances of this it would lead to code duplication that would need to be refactored immediately.
@3: Careful with this one. The thing is that the thing you call an edge case might have the more proper name of 'bug'. If you deliberately leave in bugs at the time of writing the code it can lead to very difficult to estimate 'stabilization time' at the point where the code is supposed to go into production but is not quite reliable enough. It becomes somewhat difficult to explain if that 'stabilization time' turns out to be months or even as much as a year.
> Good Tech Debt Is Intentional
When it comes to accelerate development in my opinion this is most (80/20) of it.
Love love love this article. I'm so tired of hearing lazy, unskilled, disorganized, mismanaged, etc. companies handwave the shit they write as simply being "tech debt". Sticking 50ms waits throughout your code, because you're not good enough to figure out how to actually trigger your action from an event or await something completing isn't "tech debt". Maybe hiring people not good enough to figure it out could be considered that from a higher level..
If we are going to allow the tech debt metaphor to continue, too much of the debt I see is the equivalent of a pay-day loan.
I take a chance and say it right out: Fix some kind of image library functionality! As a customer who's also used Wordpress (everyone?) its just madness that I have to keep originals on disk somewhere to post it onto another page. I can hardly figure out how to download the full size original to be able to upload it again. I ask you humbly, please, you have the power to improve my life!
If you want me to stay on topic -- this is the worst wasted time debt Squarespace has to me as a customer :) code wise the product is really solid so their philosophy is obviously good!
I think that "Good Tech Debt Is Intentional" is the key point. If you are able to recognize something as technical debt as it is created, you can also more effectively plan for paying it down later, and note what you think the solution would be at a high level. The real issue with tech debt is not that it exists, but that people wait too long to pay it down, and then end up taking more dependencies/making more technically bad decisions to deal with the tech debt which just makes it even harder to fix.
"Financial debt isn’t universally reviled in the same way. Your friend takes out a mortgage to buy a house and what do you say? Congratulations!"
There's an implicit assumption there that your friend can afford the purchase. If banks did no credit checks & your friends were impulsive & broke you might try to talk sense into them instead.
Maybe we need to store PM's technical debt for 10 years and perform a credit check when they say "I don't care, just ship it & we'll clean it up later"!
> Financial debt isn’t universally reviled in the same way. Your friend takes out a mortgage to buy a house and what do you say? Congratulations!
We do say Congratulations! - we say well done on finishing the project you were working on.
I do agree with the part on not putting too much worth on edge cases, however the biggest issue for me with Technical Debt is the increased time it often leads to in further development. So I wouldn't say it's something to completely ignore.
I'm going to take a more controversial position here, and it bothers me that it is even controversial.
The very concept of Tech Debt, though prevalent, is pernicious, because its a concept that is far, far, far too fuzzy and therefore can -- and is -- always applied as a convenient narrative to explain away mistakes, process deficiencies, bugs, etc rather than a true conceptual problem-solving tool that aids in optimizing the software development process. In short, "Tech Debt" is a euphemism for incompetence.
We can see this play out in this post, which covers "3 kinds of good tech debt.
1) "Scaffolding" ... what the author describes here is good ol' fashion Prototyping, aka Learning. No invocation of a fuzzy concept like "Tech Debt" is needed here. You don't know something, so you go and learn what you need to learn. Learning takes many forms. In this case, it is product understanding -- and this author reaches for prototyping in particular and calls it Scaffolding. Why a new term? Why obfuscate, why fuzzify? Because that's what Tech Debt is good for: fuzzy thinking. If we move to more clarity we can be specific and we can take specific actions to optimize: here, maybe or maybe not prototyping isn't the most efficient way to learn what is needed: often, wireframes shown to customers will suffice. There are plenty of ways to skin this once the framing is clear.
2) "Hardcoding" Again, no fuzziness is needed here. Developers have a fetish for fully flexible and feature-rich subsystems and we tend to call anything else a pejorative like "hard-coding" but that's a psychological problem in us, not a technical or process problem. We already have a clear framework for talking about this and it's called feature Scoping. There are, again, plenty of ways to skin this cat, but the short of it is - if you can understand what features you are interested in with clarity then you can build a system whose flexibility is in accordance. This isn't a fuzzy "Tech Debt" thing. If you only need feature X now and going forward, then build that - and call it something pejorative like "hard coding" if you want: I call it being rational. But bringing in a fuzzy term like "Tech Debt" helps nothing here. Only confuses.
3) "Not Fixing Edge Cases" This one is the worst of all. By using a fuzzy term like "Tech Debt" we're able to completely alleviate our responsibility. And start down a path of extreme cost and pain. Here, he wants to avoid having to implement correctness because it would cost too much. The example is a good one: it reflects a pattern I've seen over and over again. And unfortunately I've seen the same choice this author makes -- and the terrible downstream cost it creates, as well. By avoiding implementing a correct solution (by purposefully shipping a race condition) he is not being clever, he is being irresponsible. If this sounds draconian, let me explain further. Perhaps he finds, as he mentions, that in production this is inconsequential. Okay, great. But first thing to point out is that most likely it will become an issue as the system grows and when are you going to notice that? Are you going to go build monitoring to make sure that this "effective correctness" holds over time? Of course not, that's more work. But even if you are happy with his choice here, there's a bigger issue. He has chosen to build a system with transactional needs on top of an eventually consistent/NoSQL solution. From my experience, it's rare that you have just one feature like his that needs transactional correctness and that is it. Tomorrow, next week, soon--he and his team are going to find out that they need another transactional capability and then they are going to be right back where they started: having to ask a question, do I slack off here, as well? Again -- we've created cost for ourselves by forcing us to ask, should I ship a bug in this case? One might say this is what "Tech Debt" lets you do! It lets kick the can down the road, save you some time now... But I do not buy it. I've seen this exact kind of choice made plenty of times and the can always comes back next week, next month and the tax you pay for not getting right is immense. "Tech Debt" here is simply letting us avoid responsibility, avoid having to understand the needs of our overall system. The cost of getting transactions right/correct is not even that high if you face it squarely and truly make sure you need NoSQL and in which cases. What's happening here is not clever process optimization but inexperience. And if not inexperience, laziness (not the good kind).
The concept of "Tech Debt" is awful. And always ends up being a euphemistic excuse. I've never seen the idea of "Tech Debt" help the actual process and technical quality of things. I've only ever seen it give developers an excuse for inexperience, laziness, etc. I don't mean to denigrate here -- I mean to challenge and ask for us to be more intentional, clear, and frank in our work. "Tech Debut" is fuzzy thinking and fuzzy thinking isn't much good for anything other than excuses.
I think you are being overly harsh. Since you seem to take issue with the term tech debt as a fuzzy term, I suggest you read up on the research on this matter (Researchers talks and paper published by https://sei.cmu.edu is a good starting point).
A developer aiming for technical supremacy for its own sake isn't useful in a real-world business scenario. I've seen enough technically superior software products utterly fail in the market due to poor product-market fit iteration speed.
Tech debt isn't a choice an individual developer should make. Tech leaders at the top of any evolving software based product/service should deeply understand the pros and cons of the concept of tech debt and then decide to use it as a strategy lever.
They will have to make appropriate choices w.r.t people and process that is right for their company to leverage tech debt.
This will reflect in the technical architecture of the systems as well. There will be different layers of the stack where tech debt can be more vs less.
There are automated measure that can keep you informed if the tech debt is exceeding to the point where it is becoming a net liability (vs being a net asset as a strategic lever).
It may be true that many organizations use the term tech debt very fuzzily and don't really give it conscious and serious thought and put effort to structurally leverage it. In this, your rage against may be justified.
For those who are interested to read more on tech debt should visit these links:
> Researchers talks and paper published by https://sei.cmu.edu is a good starting point
Please link to a real paper that explores Technical Debt. This is just the link to SEI's home page. I'm looking for clarity, not hand waves.
> A developer aiming for technical supremacy for its own sake isn't useful in a real-world business scenario.
We're not looking for technical supremacy at all. (See my point #2 and my emphasis on brutal practicality.) We are looking for business optimization and all of the pragmatism that comes with that.
My objection is to using a dodgeball term like "Tech Debt", which in no way helps to carve a pragmatic path forward.
It is akin to hand-waving. If you move forward with any degree of efficiency, it will be in spite of your use of the fuzzy notion of "Tech Debt". You can do just as well without this (non-)concept.
I would call this "My Thesis" but that acts as if the burden on me is to justify my objection.
The burden is on whoever introduces this silly "Tech Debt" notion to 1) clarify what exactly it means and how to measure it; and 2) give a model in which the measurement can correlate with an improvement to the software process.
Otherwise you're just talking Santa Claus.
I have yet to see anything close to that kind of clarity when one discusses Tech Debt. There are a dime a dozen posts on "Tech Debt" and if you dig just a little you'll see that it is nearly always used to avoid clear analysis.
To be fair, clear analysis is hard, so I can understand why people give up and take the easy path. But let's call the spade a spade. "Tech Debt" is a dodge. It's not a constructive tool.
Your links are not helping your case either.
Fowler's writing explicitly makes a distinction between quadrants of Tech Debt and the only one he calls "Prudent" is the panic "We must ship now scenario."
If this is the only form of "good" Tech Debt, then my case rests completely.
Because all that is being said then is that "I literally have no idea what situation my code assets are in but I have to ship now, so let's go with whatever's on disk!"
Again, this is fair business. Anything is fair business.
But this is certainly a position of ignorance and not a position of strategic choice. So if can admit that "Tech Debt" is simply "Ignorance", then we are all in agreement.
Admitting ignorance, incidentally, is the only way an experienced practitioner can emerge and reduce the likelihood of being in such positions to begin with.
Matters are even worse. Besides "Tech Debt" being a useless concept. For the individual it creates no clarity, no admission of deficiency, and no incentive or need for growth.
>> The burden is on whoever introduces this silly "Tech Debt" notion to 1) clarify what exactly it means and how to measure it; and 2) give a model in which the measurement can correlate with an improvement to the software process.
I would highly recommend this book: https://www.oreilly.com/library/view/managing-technical-debt...
Also, read the papers presented at this conference series. https://2019.techdebtconf.org/#program
Thanks for these links. I read through the book's examples of Tech Debt.
The book enumerates some examples of failed software projects and calls their failures "Tech Debt".
I have two issues with this.
The first is how fuzzy this still is. This term is thrown over all of these various kinds of failure. And the examples are also quite varied - most are phrased as mere symptoms of failure not root causes, which gives us little insight.
The bigger problem I have is that these examples are retrospective.
If Tech Debt is simply a term for "mistakes I have made", then by all means use it -- obviously in this form it has no strategic/constructive value.
But the way I've seen it typically used is for people to act as if it is akin to real debt, consciously acquired.
"Oh I didn't make this transactional because Tech Debt."
And indeed if Tech Debt as a concept is to have any value it should be able to be used this way.
But my objection is that there is no way it can be used as such, because it is far too nebulous a concept to have any navigational benefit.
It gives no helpful path forward. It is purely a euphemism for mistakes. That's how I've seen it used universally, at least.
For , it seemed pretty clear in the post that the limit was 'arbitrary' in that there was business reason to impose some limit, but no specific limit was motivated by any reasonable "intentional" or "clear" thinking, and that, moreover, trying to discover some kind of reason was unnecessary and thus wasteful to even try. The author clearly points out that, apart from the limit, there is no need for "transactional correctness', i.e. no other part of the system required that the limit be strictly enforced.
And if that was some day no longer true – if they realized later that they really did need "transactional correctness", then it still seems like they may have made the correct decision in incurring technical debt, especially given that the author mentioned that the limit was never exceeded in production.
If that system did in fact require a hard limit then they probably would have focused on implementing "transactional correctness" as that would have then been a core feature of the system.
I can certainly sympathize with your comments in this thread. But all of your examples rather seem to confirm the utility of the analogy/metaphor as it's certainly, clearly, true that some people incur too much technical debt and are never able to 'pay it off' later when it comes due. That's not a knock against the analogy but instead a mark in its favor – debt should be taken on mindfully and carefully.
Contrary to what seems to have been your experience, I've seen technical debt incurred to great benefit.
You're letting him off the hook for . Unless the PM's are saying "Generally try to limit the number of items to 10 but it's okay if there's 11, 12, or so. And if there's some case where there's a 100 that's okay..."
Sure, fine, the PM can give this as the requirement and all can go ahead. But you're gonna have a crap time trying to analyze and test in staging, making sense of load testing scenarios, validating this feature in anyway, etc.
And I think you know this, or you intuit that this is not very good but you're not quite sure why so you say hmm let's slap a label on this that effectively covers my spidey sense that it is crap even though I can't quite articulate why. What should we call that... hmm... oh, let's call it:
This is precisely how "Tech Debt" is wielded. It's a fuzzy term to apply to a fuzzy understanding of our design choices.
And there you might say, Great, that's it, that's what Tech Debt is. But I can guarantee you -- from long experience -- that not understanding the consequences of your design choices means that you have NO IDEA the cost of that misunderstanding. It could be 10 units, it could be 1000 units, it could be 10000.
"Tech Debt" is akin to saying "I don't know." This is a big reason why the concept is useless. It's fuzzy, it's akin to saying "I don't know" and therefore there is no way to quantify the impact.
And not being able to quantify the impact means that the analogy to other forms fo debt (eg, financial) is completely disjoint and unhelpful.
Bad design choices cost you over and over again. Universally when someone has called Tech Debt on something, it almost inevitably reflects their suspicion that something is not quite right about the design but their inability to say what and quantify the cost. Otherwise, you simply would not need such a fuzzy term; you'd have a much clearer analysis and articulation of your situation.
> Contrary to what seems to have been your experience, I've seen technical debt incurred to great benefit.
Write a paper then and show me the money, so to speak. Quantify this. Because the only "great benefit" I've seen of the term "Tech Debt" is to the ego of the individual or team that invokes the fuzzy term.
I can only understand  based on what the author wrote. But it certainly seemed like it really was the case that generally limiting the number of items to 10 was fine. And, based on their subsequent observations, there was no practically realizable situation that would result in more than 10 items, let alone 100.
Lots of terms – really, every term – is fuzzy at some resolution and thus all understanding is inevitably fuzzy too.
Empirically, you seem to be almost entirely wrong about people not understanding the consequences of their choices. It's absolutely true that sometimes people are wrong about the consequences, but that's true even with financial debt – maybe the interest payments on some debt that should have reasonable end up being the straw that broke the financial back of the organization.
> Bad design choices cost you over and over again.
In the sense in which you seem to mean this, this is a ridiculous statement because every design that's not perfect, and none is, must then be a "bad design choice". That's just not true in any reasonable interpretation.
It's also unclear why invoking 'tech debt' precludes a clear analysis or articulation of the relevant situation. And regardless of whether anything is quantified, it's also inevitably 'fuzzy' too. Why would quantification itself be good?
Take the first example from the article – implementing a 'bad' version of the component to actually send emails. They did this, consciously, because they wanted to test the editor component first, before implementing the more robust email-sender version. And they did supposedly quantify a lot of that 'technical debt' – they estimated how much time they'd need to implement the initial throwaway code and how much time doing that would save in terms of them being able to more quickly test the editor. And they seemed to have a very clear idea about what exactly was wrong with the initial version and thus an approximate idea of the costs of not eventually replacing it with a better one later.
> Write a paper then and show me the money, so to speak. Quantify this. Because the only "great benefit" I've seen of the term "Tech Debt" is to the ego of the individual or team that invokes the fuzzy term.
The blog post for this very thread is a good example of the great benefits of thinking in terms of technical debt! You should write a version of the same blog post, using all of the same examples, and clearly indicate why using 'technical debt' is pernicious and furthermore how exactly you'd have dealt with all of the same issues and considerations mentioned.
>> Bad design choices cost you over and over again.
>In the sense in which you seem to mean this, this is a ridiculous statement
The point is to acknowledge the Cost. There is tremendous cost in design choices. No design choice will be perfect. Nobody is perfect.
The whole point is to optimize. To minimize bad design, to minimize Cost. That's the game.
And my whole point is that by using a fuzzy term like Tech Debt you are completely side-stepping the game. You are completely avoiding a best-effort at solving the optimization problem, so to speak, by waving your hand and saying Tech Debt something.
We already have clear terms for dealing with problems, solutions, axioms, risks, etc. There is already a clear vocabulary for problem-sovling that includes all the pragmatic real-world admission of imperfection.
But by avoiding these clear terms in favor of an umbrella kitchen sink, we are most definitely opting out of optimizing and into ouiji board mode. Which is fine for many people and the euphemism "Tech Debt" makes them feel good about this. But that's all it's doing; anyone leaning on "Tech Debt" as a concept is operating at sub-sub-optimal productivity.
> You should write a version of the same blog post...
In my original commment I broke it down point by point. 1) and 2) do not need a new term. There are already clear terms for these strategies, Prototyping and Scoping -- and these have much much clearer meanings than an umbrella term like Tech Debt.
So then we're left with 3). And I try to demonstrate the flawed reasoning behind this choice, as the author explains himself.
I'll take another stab using your statement:
> And, based on their subsequent observations, there was no practically realizable situation that would result in more than 10 items, let alone 100.
This is the famous last words that I've seen over and over again.
The simple fact of the matter is you will see 100 in some environment. Perhaps six months from now when you decide to load test your system in staging. Etc. And you are in no position to say how much that will cost you at that point.
But what I can tell you is that if you have a professional on your team, you can solve this OP's problem in very little time right out of the gate. You won't even need to have to try to do this impossible calculus.
Totally agree. How many times have I seen Tech Debt as a task to be completed in some future sprint (ya right), or seen it as the title of a category in a dev schedule containing missing product features.
Tech debt is such a general term it does more harm than good, and is often abused by people that have no clue what their actual tech debt may be..
It also implies that someone knew what the price tag was in the first place to accrue the debt, which they most likely didn't. No one knows what needs to be built or how to build it beforehand, except maybe NASA, this evolves along the way.
JS-mandatory text-only blog posts are bad tech debt.
But the only reason their approach to the "11 item" edge case works is that they manage their own data. So they can monitor and might potentially cull manually if it became necessary (eg. What if the race condition caused more than 11 or a future codechange elsewhere stumbles on it).
In a non-cloud product where the cost is higher for a vendor to come verify and fix data, this wouldn't fly.
So we asked ourselves, “What’s the simplest thing that would make the editor useful to our coworkers?”
To me, technical debt is associated with a sense of regret. The example in the quote above doesn't have that, perhaps that is what makes it the good kind.
Perhaps this isn't "Tech Debt" at all. Perhaps this is a long understood, well-known activity called Prototyping or Learning. Perhaps the concept of "Tech Debt" is just fuzzy thinking.
Yes, something like that. When a suboptimal solution serves a strategic purpose it is not TD.
I'm failing to see the point in calling a technical dept "good". As far as I can tell from the article, the author is measuring 2 possibilities of technical dept and choosing the one that incurs the least dept. I can see how good a decision this is but I don't see how this makes the dept good.
> I don't see how this makes the dept good
Time to market, for one. If you get the feature out faster to your customer, eating some debt can be worthwhile. This article is merely providing a structured way to think about the debt you're taking on.
Technical debt is a luxury companies with an excess of resources have. Startups without an excess of resources do not have technical debt in that, if you have no more runway and shutter thr business all you have is a bunch of code that didn't justify its own existence. By definition it is a positive situation to be in.
So code that you can propose may be technical dept that make your Series A is good debt.
It’s tech debt, as in a liability that you will have to pay back on the future.
This is a good take.
> if now >= NEW_CONTENT_DATE
No canary? Tsk tsk.
This was an amazing article.
Sometimes going in a Hardcode way is much better than going around in circles to get the perfect code. Saves time and is more intuitive.
No, and no, and no.
Just fix it. Repeat until completion.