The many loan sharks of system debt
So. Technical debt. If you’re working in software development, you’ve probably heard this phrase thrown around the office like a hand grenade just out of the microwave. It gets mentioned in sprint plannings or whispered anxiously during post-mortems. Yet, for a term that’s so common, it almost always lacks a nuanced explanation. Technical debt is generally portrayed as code shortcuts taken to deliver quickly, but this is a lot like blaming the paint job for a building’s structural issues after it burned down, exploded and collapsed over a pile of kittens. In that, rather confusing, order.
In reality, the problem is bigger, deeper, and a bit more philosophical[1] than that. We need to talk about system debt—a broader concept encompassing the many types of debt that can pile up, making systems clunky and difficult to maintain. Think of it as technical debt’s more complicated sibling, who not only skipped a few steps in coding but also neglected the architecture, forgot to update the documentation, and might have been sleeping through the company re-org. In this article, we’re going to walk through six kinds of system debt that go beyond the usual suspects: ontological debt, design debt, implementation debt, organizational debt, knowledge debt, and cultural debt.
The Burden of Ontological Debt
Let’s start with the most abstract one—ontological debt. You know me, fancy terms are my favourites but don't let it scare you. It’s basically what happens when the system’s vocabulary or core concepts don’t quite match up with what the system is actually doing. Or more specifically what it should be doing now. It’s like having an app where every button is labeled “Submit,” even though one submits your payment and another submits your hopes and dreams into the void. Ontological debt sneaks in when the original terminology used in a system becomes irrelevant due to a shift in the system’s purpose or evolution in business needs.
Imagine you’re working on an e-commerce platform that originally only sold books, but now it’s selling everything from kitchen sinks to NFTs[2]. The original data models might still refer to “Book ID” or “Author Name” even when the item in question is a brand-new NFT of a digital cat. This mismatch between terminology and actual system use creates confusion and forces developers to perform mental gymnastics just to keep things straight. It’s as if the system is speaking an outdated dialect, forcing everyone to carry around a language dictionary just to understand what’s going on. Or more frequently, try to shoehorn everything into the original model because "it makes sense and it works and if it ain't broken...".
The remedy is to acknowledge that these changes need to be made regularly and accept that business evolution isn’t something the system can simply ignore. Regular updates to domain models and system vocabulary can help bridge the gap between reality and your data structure’s stubborn nostalgia for the “good old days.”[3]
Design Debt: When Those Early Decisions Come Back to Haunt You
Design debt is what happens when trade-offs made during the system’s initial architecture design come back to haunt you like an ex who still has your Crunchyroll password. These trade-offs might have seemed wise at the time, but hindsight has a funny way of pointing out flaws. Sometimes it’s due to time constraints or business priorities that shifted faster than your favourite show gets cancelled. Other times, it’s simply a lack of experience or foresight that resulted in poor decisions.
Fixing design debt can be tricky, requiring significant refactoring or even re-architecting parts of the system. It’s like renovating a house while you’re still living in it. You can’t just knock down the walls without considering what might fall apart in the process (like your sanity). The trick is to adopt an incremental approach, improving the design where you can while keeping an eye on the big picture.
Implementation Debt: The Price of Rushed Code
Implementation debt is what most people think of when they hear “technical debt.” It’s the accumulation of rushed code, quick fixes, and “we’ll clean this up later” implementations that never got revisited because, well, later never came.[4] It’s the kind of debt that happens when you’re given an unrealistic deadline and someone utters the classic phrase, “Let’s just get it working for now.” It works. Barely. But it’s hanging together with duct tape, and the duct tape is also made of code that no one quite understands.[5]
This kind of debt is often exacerbated by short-term thinking and prioritizing quick delivery over long-term maintainability. At the end of the day it ends up being a lot like choosing to drive on a flat tire because you don’t have time to change it—you’ll get where you need to go, but sooner or later you’re going to end up stranded on the side of the road. And you can just hear the banjos playing. The key is to strike a balance. Sometimes, quick and dirty solutions are necessary, but they should come with a plan for when to circle back and do things right.
Organizational Debt: When Structure Gets in the Way
Organizational debt is the debt that forms when your system and your company’s structure are out of sync, like a mismatched dance duo where one partner is always a beat behind. This often happens when organizational changes aren’t reflected in the system’s architecture, processes, or responsibilities. The symptoms can be subtle at first—like different teams having conflicting workflows for the same system—but they grow into full-blown dysfunction over time.[6]
Maybe the system’s design still reflects a division between two teams that were merged six months ago, leading to duplicated efforts and a general sense of “does anyone even know who’s in charge of this?” It’s the kind of debt that accrues quietly but can explode into chaos as soon as you try to scale, pivot, or - more frequently - even just make sense of who should be working on what. Addressing organizational debt often requires more than just tweaking code; it may involve rethinking workflows, reassigning ownership, and sometimes even adjusting the company culture to foster better cross-team collaboration.
Knowledge Debt: When No One Knows How It Works Anymore
Knowledge debt is the debt that accumulates when the shared understanding of how a system works erodes over time. This happens because people leave, documentation gets outdated (or wasn’t great to begin with), and the only person who knew how that one obscure subsystem worked is now off living in a remote cabin writing a novel about AI ethics. Without a solid knowledge base, new developers take longer to onboard, existing developers struggle to maintain systems they don’t fully understand, and the system becomes a black box with a growing number of “Do Not Touch” labels.[7]
Tackling knowledge debt requires making documentation a priority and not just something you “get to if there’s time.” It’s also about encouraging knowledge sharing within the team, whether through “lunch and learns,” technical deep dives, or even informal Slack channels where someone can ask, “Why exactly do we use this ancient Perl script?” or "Who is Haskell and why is it handling the financial reporting?" without getting a hundred eyes rolled at them.
Cultural Debt: The Debt You Didn’t Know You Were Accumulating
Cultural debt is the most insidious of them all. It’s not a type of debt that you can see or touch directly, but it manifests in the behaviors and attitudes that encourage other forms of debt to accumulate. It’s the mindset that says, “We don’t have time to refactor, just ship it,” or the attitude that sees documentation as a nice-to-have rather than a necessity. It’s that unspoken understanding that cutting corners is acceptable as long as you make the deadline, even if it means paying a steep price later.
A culture that prioritizes speed at all costs will inevitably accumulate more debt than one that balances quick wins with long-term sustainability. Changing this isn’t as simple as putting a “Quality Matters” poster in the breakroom; it requires shifting the organization’s mindset. The goal is to foster a culture that values continuous improvement and encourages developers to address debt incrementally, rather than letting it pile up until it becomes a crisis.
Before declaring technical bankruptcy
Technical debt is more than just poorly written code. When we zoom out, we see that system debt encompasses a range of issues that touch upon architecture, processes, knowledge sharing, and even organizational culture. The different types of debt are interconnected, each influencing the other in subtle and not-so-subtle ways.
To manage system debt effectively, managers, architects and teams need to recognize that it’s not just about paying down code quality debt. It’s about creating a sustainable approach to system development that keeps the whole system healthy. This means regular audits, updating design and vocabulary to reflect current realities, documenting changes, and fostering a culture that doesn’t accept debt as a given, but as something that should be actively managed.
The next time someone says “technical debt,” think of it as a cue to discuss the deeper system debt issues that might be lurking beneath the surface. And if you do find yourself facing an abundance of debt, remember: the sooner you start paying it down, the less likely it’ll be to haunt you in the middle of the night like an intermittent error that corrupts your index.
Footnotes
[1] SURPRISE!
[2] No, I wouldn't want to work for that company either but in this example we are. Sucks to be us for the next paragraph.
[3] Business nostalgia is real, and no one wants to admit their data model is living in the past.
[4] TODO: Write joke here
[5] Technically, the duct tape has a dependency problem.
[6] If you find yourself saying “That’s just how we do it here,” you may have a bad case of organizational debt.
[7] This is also known as the Trash Fire stage of the system lifecycle. If your documentation file is titled “README_IF_YOU_DARE,” you're in trouble.