“Tech debt boo, engineering excellence yay.”
You could say that all you want — as an engineer, those are my fundamental sentiments too; but it’s also a Fact of Life™ that tech debt will always happen; and I argue that it’s in fact necessary for any application/product/service that’s actually being developed upon; any application that’s actually growing.
If there’s no tech debt, it follows that the product’s not evolving, and that spells trouble for you because… Why isn’t the product growing? Are there no new customers? Are there no new features being requested for?
Tech debt exists because abstractions always break.
Design decisions made with a product’s best interests can become tech debt in a year. In a fast-paced startup environment, it may even be termed a bad life decision in a matter of weeks.
But that’s OK.
Tech debt means that the product is actually existing in a realistic world with realistic users. Real users fuck things up, real users change their minds ever so often, real users seek new things. It’s a human condition to seek progress and therapy/executive coach-types even have a term for this — it’s a VUCA world we live in.
VUCA: Volatile. Uncertain. Complex. Ambiguous.
It is as it sounds and this is reflected in tools we create for each other as humans to use. One day, we’re happily using a piece of software, the next we’re demanding that the software do more than it already can. And we needed wanted it yesterday. So a change request is raised; a contract to deliver it in 3 business days has been agreed upon; the change is made in 3 business days.
3 business days (arbitrary, YMMV) isn’t enough to patch an abstraction, much less restructure it.
After much sighing from junior ‘uns and grumbling about how the company doesn’t care about the craft; after much coddling from seniors and leads about how “we’ll fix it someday”, the change is pushed to production; because someone paid for that change to be done within an expected timeframe.
And the cycle repeats ad infinitum.
Since tech debt is a given (I hope I’ve convinced you by now), how can we as technical people handle the soul-crushing realisation that we’re just tools to deliver a product that makes money for a capitalist organisation? How can we maintain our pride and passion about our craft as people who are genuinely interested in building things that last?
Can we actually be craftsmen in the first place?

After three years spent bringing a high-growth startup from pre-seed funding to series A, my answer has everything to do with the philosophy behind the Japanese practice of Kintsugi.
The philosophy behind Kintsugi is that breakage and reparation is a natural — and thus, expected — process of the life of any given thing. Rather than preventing breakage, breakage is something to plan and provision for. What if craftsmanship meant accounting for an imperfect, partly-broken-but-still-working thing to continue existing?
As a self-declared perfectionist myself, that’s blesphemy; but hear me out.
Taking a point of view where things will break while considering we want to keep using those things, we can change how we approach certain practices in the realm of software development.
Like tech debt. Yes, we’re still on that topic.
If we treat tech debt as a constant — represented by cracks on a bowl through daily usage and unadulterated human carelessness — we can then begin to imagine and potentially accept a world where we can live with tech debt without it haunting us at a personal level.
To me, it’s a skill that’s required of every engineering manager: What’s your relationship with tech debt and how do you handle it as a recurring nightmare concept?
Answers may vary according to life experience but a correct answer is never to try and prevent it completely.
And it’s not even from an ideal of honing one’s craftsmanship: A software with ongoing new features/change requests means I can be somewhat sure I’ll be paid in the near future. Part of it is self-serving.
To me, one answer to handling tech debt that has emerged relatively recently to me given the experiences of the past few years, is to standardise the tech debt.
In general, standardisation is accepted as a Good Thing™ in engineering circles, though we rarely think to apply it to tech debt. It’s usually a hack here, a hack there — an unregulated mess.
What if we accepted tech debt as a way of life and applied our obsession with standardisations on them?
Standardised hacks mean standardised fixes.
Assuming you’re in a team building a product that serves actual users in an actual world, there will eventually come a time when the team size grows; people without context of a codebase’s past will onboard. When that time comes, an unregulated mess of hacks will be almost impossible to understand even if the capacity to fix it has realised itself. You probably know this as legacy systems — systems no one wants to touch less some organisational elders.
IQ — the capitalist’s idea of intelligence — is measured by our ability to recognise patterns and apply solutions to these patterns. Professional software developers are generally above average when it comes to this measurement, which means that tech debt from standardised hacks can be resolved with much less effort than an unregulated mess of hacks.
In the world of live performance, there’s a (half-serious) concept where if you play a wrong note once, it’s a mistake; but if you play the wrong note twice, it’s art. Miss a semi-colon once, it’s a compiler error, remove semi-colons altogether, you get Python.
Easy to say though, I hear you say. What does that even look like?
In code, what this could look like:
Continuing with directory structures and file naming conventions which the team already knows might need to be changed at some point in future. Think how much easier it is to find an replace a single phrase than to see what each repository/team has done.
Do refactors based on proper prioritisation cycles — continue to use a to-be-deprecated function until the task for updating the function has come. It’s much easier to track down the logic of a feature chain’s functions if there’s no
functionAlt
orfunction2
in play that does something similar-but-different
Considering the philosophy behind Kintsugi opens us up to wisdom we wouldn’t acquire if we fall back into patterns of “something is wrong, let’s fix it now” and “product needed it yesterday”.
IMO it allows us to be responsive instead of reactive; which is something that’s really important especially when trying to engineer things that last in an environment where change is moving at a breakneck pace and hacks are needed to be thrown in.
There’s a time for craftsmanship, there’s a time for simply… Delivering.
Especially so in startups, this delivering might continue for an overextended period of time. Everything will seem hopeless and it’s too easy to just give and say “that’s life” and not learn anything from it.
The challenge of being in the engineering discipline in this day and age is to always have the long-game in focus. Even if that means setting aside your inner craftsman to deliver a craft that wasn’t made perfectly. As my personal experience goes, you can dislike what you’re delivering, but acknowledge that it’s still making a difference to the person on the other end using what you’re creating.
Will these hacks ever be resolved?
Maybe the right question to ask is: will the organisation sustain the team financially without those hacks in place?
Tech debt, love it or hate it, is a natural — and maybe even positive — property of any codebase behind a product that works. And sometimes, a product that works… is what’s needed.
Enjoyed my ramblings? Subscribe to it:
Till next time-