3 ms·
I sympathize with the author's take that our industry is way too trigger-happy and willing to throw away perfectly working code, but none of this: > Python 3 c
by alxlaz 6y ago
I sympathize with the author's take that our industry is way too trigger-happy and willing to throw away perfectly working code, but none of this:
> Python 3 changed all the string handling, have to make adjustments. The build is too slow, should make it faster. Security vulnerability found in one library, time to update libraries.
is what (most?) people mean by technical debt.
If the build is just slow, but can be improved, that's not technical debt. Technical debt is when the build system is actually a bash script that was written ten years ago because none of the developers wanted to waste time on a proper makefile, and none of the interns knew make (or cmake, or ant, or whatever), and now just adding a new source file takes three hours.
(Edit: oh, or my favourite example, how could I forget this?
I've worked on a very large (MLoC) codebase that used autotools as a build system. Unfortunately, at some point, someone didn't want to learn m4 -- totally understandable -- and committed a manually-mangled configure script and a bunch of generated makefiles...
...and from that point, autotools were eschewed completely, and the configure script, and the generated makefiles, had mangled by hand each time something was required. Adding a new module to that program took 2-3 days of grepping and hunting through a bunch of files, just to make sure you didn't miss anything. That's more than enough time to learn the basics of how to use autotools. Multiply it by several hundred modules and weep.)
If a security vulnerability is found in a library, and that's solved with a library update, that's not technical debt. Technical debt is when message signing is done via MD5 hashes produced by a slightly buggy in-house implementation. You got to ship on time, but not by shipping a functional product -- that's a bug, and it still has to be fixed at some point.
If some stuff is single-threaded and slow, but easy enough to parallelize so that it's faster, that's not technical debt. Technical debt is when there's a single, global object containing absolutely all application state, and splitting an extra thread to do some computation in the background requires four weeks of extra manual testing just to be sure you didn't introduce another race condition.
(Edit: unfortunately, nope, none of the examples above were invented. I had the pleasure of working on a codebase where adding a new thread literally required written approval from the product manager because of the extra testing it required. Calling that "maintenance" is much like calling a bridge collapse a "vertical position readjustment" -- it gleefully ignores the fact that it was readjusted downwards, through gravity, possibly involving mass casualties, and had to be rebuilt).
Some maintenance work is legitimate and is just the result of normal software progress. But some maintenance work is entirely self-inflicted. Ignoring that is just an excuse for the kind of "first we do git push, then we think about it" crunch mentality that lots of companies encourage, for reasons that have absolutely nothing to do with either productivity or technical excellence.
- andreareina 6y agoYup. Technical debt is a liability you take on now in the hope that it enables later being better than if you hadn't taken out on. But it's still a liability that may impede forward progress.
- rkangel 6y agoYes, the author seems to ignore that there is a difference between good code and bad code. There is an enormous amount of subjectivity in that difference, but sometimes things _are just worse_. Maybe they're worse for the product (e.g. buggy code) or maybe they're worse for the developers (e.g. your tedious build system and global state). Either way, it takes time to do something about.
- shoo 6y agoThank you - I think you're framing the discussion in a more nuanced way than the author, by talking about different kinds of issues or technical decision which lead to qualitatively and quantitatively different footprints of future maintenance effort. We could go a bit further and start trying to categorise decisions by the different footprints of future maintenance effort that they cause. Roughly, we could differentiate between decisions that: (a) cause no additional effort in future, (b) cause a once-off impulse of additional maintenance effort in future, (c) cause an ongoing pattern of periodic maintenance effort in future, separately from any other change, (d) cause the effort required to make any other change in future to be amplified linearly, and (e) cause the effort required to make any other change in future to be amplified superlinearly. So now we've invented five somewhat arbitrary, non-exhaustive categories of maintenance effort to talk about [+]. Technical decisions that cause future maintenance effort of the form (a) are (relatively) fantastic, and (b) are often fine as well. (c) can become problematic depending on how often and how much effort regular maintenance has to be performed, but maybe can be dealt with by hiring an extra pair of hands to perform the activity. (d) and (e) will act as productivity dampeners and bog down any other development efforts, if they get out of control may completely prevent progress. Technical debt issues of the form (e) might be: the system is built in a hand-rolled programming language that is not well defined, doesn't have specified behaviour or test cases, the developers are terrified of changing it but need to change it in order to make functional changes or fix defects in the system, but changing it tends to introduce more regressions that are discovered a few months later. Or maybe the code is arranged in an exponentially growing number of long-terms forks that need to exchange patches to support different special features sold to the latest key client, without good tooling support or test coverage. Or generally any system that's ended up in the state where the least-energy solution to fix any local problem makes the overall system globally worse, and for whatever reason no-one ever overcomes the energy barrier to do anything other than the locally easy globally corroding fix. [+] We can define a lot more than five categories -- for simplicity let's assume we live in a world where it is not possible to make a technical decision that can ever _reduce_ the effort to make changes in future ("what if we migrated from using global variables, if expressions and goto to prefer using locals and structured programming constructs wherever practical") and act as a global productivity amplifier for all future development. Let's assume for simplicity that maintenance burdens are never probabilistic or conditional ("approach X will never require additional maintenance effort in future unless the client ambushes us with unlikely requirement R, which will invalidate the entire theoretical and practical foundations of X at the core of the product. it's a wager, most likely the debt won't ever be called in") edit: i guess this could be characterised asymptotically with big-oh notation: "what's the asymptotic complexity of future maintenance effort introduced by this decision? as a function of t, time, or c, the cumulative number of changesets? O(0)? O(1)? O(t)? O(c)? O(c log c)?" Although it is slightly wacky focusing on asymptotics of maintenance burden as the time or number of changeset goes to infinity, since in relatively finite timescales all the clients will defect or go bust, the product will fall out of use, the company will go bankrupt, the developers will quit or retire. hopefully someone remembers to ceremoniously burn all remaining copies of the source repository.