All writing
AI Deployment

The Real Cost of Technical Debt in ML Systems

ML technical debt is quiet. The system runs. The metrics look green. And somewhere underneath, the foundation has shifted in ways nobody is measuring.

Software technical debt announces itself. You can see it in the codebase — the TODOs, the commented-out blocks, the functions named handleSpecialCase2. You can measure it with static analysis. You can point at it in a sprint planning meeting and say, "this is going to slow us down." It's visible, which means it's manageable.

ML technical debt is different. It's quiet. The system runs. The metrics look green. The dashboard says accuracy is 94%. And somewhere underneath, the foundation has shifted in ways that nobody is measuring because nobody defined what to measure.

I've watched this happen. Not once — repeatedly. And the pattern is always the same: the debt accumulates silently, the system degrades gradually, and by the time someone notices, the fix isn't a refactor. It's a rebuild.

The debt you can't grep for

In a traditional software system, debt lives in the code. In an ML system, debt lives in the space between the code and the world. The code can be clean, well-tested, properly abstracted — and the system can still be carrying massive debt because the assumptions it was built on no longer hold.

Training data is the most common source. A model trained on data from 2023 encodes the patterns of 2023 — the customer behavior, the market conditions, the product mix, the seasonality. If those patterns shifted in 2024 and nobody retrained, the model is now making predictions based on a world that no longer exists. The code and the model haven't changed. The world changed, and the system didn't.

Feature engineering is the second source. Someone made a set of decisions about which features to include, how to encode them, what interactions to capture. Those decisions encoded assumptions: that this categorical variable has these possible values, that this numerical feature falls in this range, that these two features are independent. When the assumptions stop holding — a new product category appears, a numerical value exceeds the expected range, two features become correlated — the model doesn't throw an error. It just gets worse, in ways that are hard to detect and harder to attribute.

The dashboard problem

Here's where it gets insidious. Most ML systems have monitoring. There's a dashboard. It shows accuracy, precision, recall, maybe some business metrics. The numbers look fine.

The numbers look fine because the dashboard is measuring against a benchmark that was set when the model launched. The evaluation dataset was sampled from the same distribution as the training data. The threshold for "acceptable performance" was calibrated against that distribution. If the production distribution has drifted, the benchmark is no longer meaningful — but the dashboard doesn't know that. It's comparing today's predictions against yesterday's standards.

I watched a model run for seven months with dashboard metrics that never dipped below the acceptable threshold. The model was used for prioritization in an operational process. Over those seven months, the team noticed that the process felt less efficient — more manual overrides, more escalations, more cases where the model's recommendations didn't match what experienced operators would choose. But the dashboard was green, so the model wasn't the suspect.

When someone finally did a deep-dive, the production data distribution had shifted meaningfully from the training distribution. The model's real-world performance had degraded by roughly 15 points on the metric that mattered. The dashboard didn't catch it because the dashboard wasn't measuring what mattered — it was measuring what was easy to measure at launch.

Nobody was wrong. The dashboard was built correctly. The metrics were computed correctly. The thresholds were set reasonably. The problem was that nobody had defined what "the model has degraded" means in terms that survive a distribution shift. The monitoring watched the model's outputs. Nobody was watching the model's inputs.

The compounding effect

Software tech debt is roughly linear. Each shortcut adds a roughly predictable amount of friction. ML tech debt compounds.

A model with stale training data produces slightly worse predictions. Those predictions feed into a downstream process that adjusts its behavior. The adjusted behavior generates new data that's now influenced by the model's drift. If that data feeds back into the training pipeline — even indirectly — the next retraining cycle learns from data that was shaped by the model's degraded performance. The drift compounds.

Feature engineering debt compounds differently. A feature that worked well at launch stops being predictive. The model compensates by leaning harder on other features. Those features become overweighted. If one of them also degrades, the model's performance drops non-linearly. You don't get a gradual decline. You get a period of apparently stable performance followed by a cliff.

Evaluation debt is the worst because it's meta-level. If your evaluation methodology is stale — stale test sets, stale metrics, stale thresholds — you lose the ability to detect the other forms of debt. You're flying without instruments. Everything looks fine until it very suddenly doesn't.

What "maintaining" an ML system actually means

Most organizations treat ML maintenance like software maintenance: fix bugs, update dependencies, keep the infrastructure running. That's necessary but not sufficient. ML maintenance includes a category of work that software doesn't have: keeping the model's relationship to reality current.

That means someone has to monitor input distributions, not just system metrics. Someone has to define what "drift" means for this specific model and this specific use case — not in the abstract, but with concrete thresholds tied to business impact. Someone has to own the retraining cadence and have the authority to say "this model needs to be retrained" even when the dashboard is green.

Most importantly, someone has to maintain the evaluation methodology itself. Test sets need refreshing. Metrics need re-validating against business outcomes. Thresholds need recalibrating. The question "is this model still good?" is only useful if the definition of "good" is still current.

The organizational gap

The reason ML tech debt accumulates isn't technical. It's organizational. In most companies, the team that builds the model is not the team that operates it. The data scientists who understand the model's assumptions hand it to an engineering team that knows how to keep services running but doesn't know what the model is sensitive to. The operational team monitors uptime, latency, and error rates. Nobody monitors whether the feature distributions have shifted, whether the training data is still representative, or whether the evaluation metrics still reflect production conditions.

This is a gap that doesn't have an obvious owner. It doesn't belong cleanly to infrastructure, data science, or product. It's the intersection of all three — and in most organizations, intersections don't have headcount.

The teams that manage ML tech debt well don't treat it as a technical problem. They treat it as a lifecycle problem. The model isn't "done" when it deploys. It's done when it's retired. Everything between deployment and retirement is maintenance — and the maintenance plan needs to be as deliberate as the development plan.

The alternative is what I've seen too many times: a model that works brilliantly at launch, degrades silently for months, loses stakeholder trust, and gets replaced by a spreadsheet. Not because the model was bad. Because nobody defined what it would look like when the model stopped being good.