Technical debt is actually a really good analogy, precisely because non-technical finance people understand the tradeoff pretty intuitively. Sometimes incurring debt is the right thing to do, but you'll want to pay it down or you'll have to live with the interest. This is true of both monetary and technical debt. For extra credit, you might assign notional interest rates to your technical debt... if they're in the double digits I promise you they'll scare the finance guy.
Ehhh, the analogy doesn't hold totally because you might not have to pay it back. In that case you're ahead. FTA:
Call options are a better model than debt for cruddy code (without tests) because they capture the unpredictability of what we do. If I slap in an a feature without cleaning up then I get the benefit immediately, I collect the premium. If I never see that code again, then I’m ahead and, in retrospect, it would have been foolish to have spent time cleaning it up.
That's the home run point: you might not have to pay it back. That is exactly why the debt or credit card analogy doesn't hold. An uncovered call is exactly the correct metaphor. This isn't even high finance we're talking about, this is fundamental options stuff. I'm not sure I understand the resistance to using the uncovered call terminology as opposed to the highly innaccurate (but more Main Street comprehensible) "debt" analogy. Debt (aside from bankruptcy ALWAYS has to be repaid. Yet we all know that technical debt doesn't always have to be repaid. Debt is a terribly imprecise way of thinking about it.
> I'm not sure I understand the resistance to using the uncovered call terminology as opposed to the highly innaccurate (but more Main Street comprehensible) "debt" analogy.
Specifically, it is because the managers I am attempting to communicate with understand the concept of "debt" and do NOT understand the concept of "uncovered calls". I work at a bank and VERY few of the managers I need to explain things to would really understand uncovered calls. I would guess that people at other kinds of employers may find it even worse.
Debt doesn't always have to be repaid. It can be refinanced and carried indefinitely. People do it all the time with mortgages. I know people who have lived in the same house for 15 years, but due to frequent refinancing and cashing out equity they still have 29 years left on their mortgage.
I agree, the analogy is imperfect, because you don't pay interest unless you need to extend or maintain the code. It's only useful in a world where the codebase in question is under ongoing development, but those are the situations where I've used it. Naked calls work fine as an analogy in the case you describe.
Agreed. Startups have very high capital costs. Even a usurious credit card can look lo-cost. It's not very scary at all. It's like writing Little Red Riding Hood with a "big bad groundhog."
The counter also assumes all code lives in a vacuum - that cleaning that particular code will not impact any other parts of the code base. I find this to be very far from the truth. Often cleaning up one area will lead to abstractions that can have an effect far beyond the original code.
>Ehhh, the analogy doesn't hold totally because you might not have to pay it back. In that case you're ahead.
The analogy totally holds. If you don't pay back financial debts (e.g. airlines going through chapter 11 and shedding their pension obligations), then you ALSO come out ahead.
Calling it "selling insurance" is pretty good. People blank if you say "options", but selling insurance captures the immediate small upside with potential massive downside later
This is exactly the analogy I use with developers who tend to over-engineer.
In a perfect world, we'd be guaranteed that our code will never need to change. In this world, abstraction is worse than worthless - it is a cost with no benefit.
In the real world, there are risks. Bugs will be fixed, requirements may be changed, back end systems may be replaced or scaled, and so on.
Building things the "right way" is exactly like buying insurance against those future risks. Business-savvy developers know how to estimate the probability and cost of the risk this code will face over its lifetime, and weigh that against what it would cost to build in extra code to mitigate those risks right now.
Thus, choosing the right level of abstraction and engineering overhead to add to a particular feature should be a series of decisions and tradeoffs, not just a determination that it's always better to build the "right way".
In my experience, developers tend to be overly confident in their ability to predict and mitigate future risks, and suffer severely from hindsight bias. They rarely lament the extra abstraction layer they built and never needed, but are quick to point out when modifying a feature will cost more because of weak abstraction.
Even in those perfect conditions right level of abstraction may cause the system to be build with less code and faster.
That being said I agree that it's always a trade off; I actually did many refactorings where I threw an abstraction level out instead of adding more of them, resulting in faster and easier to maintain code. It's definitely not good to invest in abstraction blindly.
In a perfect immutable system, I'm still going to want my code to be as DRY as possible, because I don't like typing the same thing over and over again.
In this perfect hypothetical world, you wouldn't eschew abstraction; you'd just know exactly what abstractions to use to perfectly model the problem you're solving. Those ideal abstractions would be different, since the problem is immutable.
Ask yourself this: in this perfect world, would you code with a magnetized needle and a steady hand? Why not?
Not sure how the magnetized needle analogy applies here. The point of the hypothetical is to avoid developing your own extra layers of code for future reuse. Avoiding those that others have developed for you already would not make sense.
As to the rest of your point, yes. Anything in service of pure development speed would be desirable. If you could abstract and reuse something faster than you could implement it in some other way (eg copy/paste), then it would make sense to do so.