The paradox of reasonable decisions
Almost no team builds up technical debt through negligence. They build it up by making decisions that are reasonable at the moment they're made. There's a deadline, an incomplete picture, legitimate pressure. The simplest solution works. They go with it.
The problem isn't that decision. The problem is that the same logic applies to the next one, and the one after that, and the one after that again. Each of these decisions is defensible taken on its own. Their cumulative effect isn't, but nobody is responsible for watching that cumulative effect. Software systems aren't short of signals — the CI pipeline, static analysis tools, the production failure rate all provide continuous feedback. What they lack is a mechanism that automatically converts the aggregate cost of debt into a number management can understand. The cumulative cost of local decisions stays invisible until it's too late.
Understanding how debt accumulates isn't about assigning blame for past decisions. It's about working out where to introduce the feedback mechanisms that are currently missing, before the cost becomes unsustainable.
Three patterns of accumulation
Debt doesn't build up evenly. In our experience, it tends to build up in three recurring ways — not categories from the literature, but patterns we see time and again in the teams we work with. Recognising them matters because each one calls for a different response.
The first pattern is speed compression. A team has to ship to a tight deadline — it might be a demo, a contract, a market window. The technical shortcut is rational: you skip the refactoring that would otherwise be needed, you duplicate logic that should be extracted, you bypass an abstraction that slows things down but keeps the system maintainable. The immediate result is correct. The cost is deferred. If the compression repeats every two or three sprints, that deferred cost keeps piling up without ever being paid off, because there's always an urgent reason not to deal with it now.
The second pattern is growth fossilisation. An architecture gets designed at a specific point in the organisation's growth, to meet the constraints of that moment. Six developers, one product, three clients. The architecture is right for that context. The trouble is that the context changes — twenty developers, four products, a hundred clients — but the architecture stays the same. Not because anyone decided not to update it; simply because nobody was ever given an explicit mandate to do so, and the system kept working well enough that it never justified urgent intervention. Fossilisation is the most expensive kind of debt because it's the most invisible: the system works, but every change needs a workaround nobody expected.
The third pattern is turnover sedimentation. Every developer who joins a team inherits decisions made by others, in circumstances they weren't around for. The original reasons for those decisions sit in people's memory, not in the code. When those people leave — and they always leave eventually — the reasons go with them. Whoever arrives next works on a system that has a history but no record of that history. Later decisions get layered on top of earlier ones without anyone understanding them. The debt stratifies.
Structural misalignment: the people who build it up aren't the people who pay for it
There's an organisational mechanism that makes all three patterns worse: the people who make the decisions that create debt aren't the same people who pay for it, and often not even at the same point in time.
The team that takes the shortcut to hit the March deadline probably won't be the one doing the maintenance two years later. The managers who prioritised features over refactoring won't see the drop in productivity that decision caused until it's too late to trace it back to that specific choice. The developer who introduced the circular dependency may well have left the project by the time that dependency blocks a critical integration.
This misalignment isn't a moral failing of organisations. It's a natural consequence of how responsibility and incentives get distributed over time. Incentive systems optimise for short-term goals; the costs of technical debt show up in the medium to long term. Until there's a mechanism that makes future costs visible in the present, the incentive structure will always tilt towards accumulation.
The answer isn't to blame whoever built up the debt. It's to create mechanisms that make future costs visible before they materialise.
The psychology of invisibility
Alongside the organisational mechanism, there's a psychological one that makes debt hard to see even for people inside the system.
Debt builds up in small increments. No single commit turns a healthy system into an unsustainable one. The transition happens gradually, through hundreds of changes, each one marginally worse but not alarming on its own. The human brain is wired to spot sudden change, not slow drift. The same mechanism that makes it hard to notice you've put on ten kilos in a year makes it hard to notice that cycle time has doubled in twelve months.
Then there's the problem of local context. Every developer has deep visibility into their own corner of the system and only partial visibility into the rest. The debt that slows delivery often isn't in the area a developer spends most of their time in; it sits at the intersections, in the dependencies between modules, in the boundaries where responsibility is ambiguous. Nobody sees the whole system: the CTO sees its high-level structure, developers see specific parts. Systemic debt lives in the spaces in between.
Finally, there's the normalisation effect. When average cycle time has always been three weeks, three weeks becomes the normal reference point. Nobody asks whether it could be one. When every release needs a day of manual coordination, that becomes the normal process. Deviations from the norm are visible; the norm itself stops being questioned. Technical debt that has settled over the years stops being perceived as debt at all: it's simply "how things work here".
The early warning signs that usually get ignored
Debt sends out signals before it becomes a serious problem. The trouble is that those signals are almost always read as local, temporary issues, not as symptoms of systemic build-up.
The first sign is variance in estimates. Not the occasional wrong estimate, which is normal, but a systematic widening of the gap between estimate and actual, sprint after sprint. When a team consistently underestimates by 40–60%, there's almost always a structural reason: the system is less predictable than it looks from the outside, because hidden dependencies multiply the side effects of every change. This gets read as an estimation problem, but it's actually a complexity problem.
The second sign is knowledge silos. When only one or two people genuinely understand a part of the system, that part is at risk. Siloed knowledge is both an effect of debt — the most complex areas take years to understand, so few people ever really do — and a cause of further build-up, because anyone who doesn't know the area can't safely touch it. New developers take months before they can contribute independently: not because they're less capable, but because the system is harder to read.
The third sign is asymmetry in code review. When certain modules get a cursory review because "it's best not to touch that part too much", the debt is already entrenched. Superficial reviews don't protect the system; they only slow the build-up without stopping it. A team that has stopped doing thorough reviews in certain areas has already implicitly accepted that those areas are out of control.
From the speed of accumulation to the speed of impact
Not all accumulated debt has the same impact. Some debt marginally slows down peripheral areas; some blocks the core of the system. The difference between the two depends on how often that area of the code needs to change and how many dependencies run through it.
A legacy module that does one thing, has been stable for years and isn't on the critical path of growth can stay as it is indefinitely without the debt ever becoming urgent. The same level of complexity in a module that has to change every sprint, that every new feature runs through, and that ten other modules depend on, is already an operational blocker today.
The right question for assessing urgency isn't "how much debt do we have in that area?" but "how often do we need to change that area, and how much does each change cost compared with what it should cost?" The gap between the actual cost and the expected cost is the number that measures the impact of debt on that specific area. Calculating it for every critical area of the system is the first step towards managing debt rather than guessing at it.
It's worth spelling out a distinction that changes how you judge how urgently to act: technical debt doesn't have fixed costs. It's paid at the point of change; it doesn't exist in the abstract. A system with high debt but a low frequency of change carries latent debt — present but silent, with no immediate operational impact. Debt becomes active every time the team has to work in that area: that's where the real cost shows up. Not every system with high debt needs immediate attention, but every system with high debt that changes often does. The gap described above isn't just a metric: it's the tool for telling apart the areas where debt is already active from those where it's still dormant.
What to do in practice
Three actions for anyone who wants to start making the build-up visible before it becomes unsustainable.
- Measure the cycle time trend over the last six months: not the average, the trend. A cycle time that grows quarter on quarter without a matching increase in feature complexity is the most reliable sign of build-up in progress. If you don't have historical data, ask the team: "how long did this type of change take six months ago?" Collective memory is less precise than instrumented data, but it's better than nothing as a starting point.
- Map the areas of localised knowledge: which parts of the system have knowledge concentrated in one or two people? Those are the high-risk areas, regardless of code quality. Siloed knowledge is both a symptom of debt and a risk multiplier: when that person isn't available, that part of the system becomes opaque to everyone else.
- Set up a regular review of the cumulative effect: not a code review, which assesses individual changes. A dedicated session, every two or three months, to look at how the metrics have moved over time and ask where the gap between estimate and actual has widened. The organisations that manage debt well aren't the ones that avoid every shortcut; they're the ones that stop periodically to work out where they've ended up.
The QMates perspective
The pattern we see most often isn't a team that has stopped working well. It's a team that worked well in a given context, and that context changed without the system changing with it. The architecture is still the one designed two years ago; the organisation has tripled in size. Bounded contexts defined for one product now serve three different products. Release processes designed for a team of six are run by twenty people using the same manual procedures.
When we come into an organisation, the first thing we measure isn't code quality. We measure misalignment: between how the system is structured and how the business works today, between how the teams are organised and how the code distributes responsibility, between the speed the system used to allow and the speed the organisation now needs. The technical debt that matters isn't ugly code; it's the gap between the system you have and the one you need to keep growing at your current pace.
This is the second article in the series, and it has set out the mechanism behind the build-up. The third looks at the concrete signals that let you spot where debt has already started slowing delivery, before it becomes an emergency.