AnyLearn
All lessons
AIintermediate

Why ML Systems Rot

A trained model is a small box inside a large system, and the system is what decays. This lesson covers the failure modes that are specific to machine learning: why changing one feature moves every weight, why hidden consumers break silently, and why data dependencies cost more than code dependencies.

Updated · AI-authored, review-gated · how lessons are made

Not signed in: your progress and quiz score won't be saved.
Progress1 / 9

The model is the small part

In 2015 D. Sculley and nine co-authors at Google published Hidden Technical Debt in Machine Learning Systems at NIPS. Its most quoted observation is that the machine learning code is only a small fraction of a real-world system.

Around the box that trains a model sit configuration, data collection, feature extraction, data verification, resource management, process management, serving infrastructure, analysis tools and monitoring. Every one of those is ordinary engineering. Together they dwarf the model.

The paper's argument is not that this surrounding infrastructure is badly built. It is that machine learning erodes the abstraction boundaries software engineering depends on, so the usual techniques for keeping a large system maintainable work less well here. MLOps is the practice that grew up around exactly that problem.

Full lesson text

All 9 steps on one page, for reading, reference, and search.

Show

1. The model is the small part

In 2015 D. Sculley and nine co-authors at Google published Hidden Technical Debt in Machine Learning Systems at NIPS. Its most quoted observation is that the machine learning code is only a small fraction of a real-world system.

Around the box that trains a model sit configuration, data collection, feature extraction, data verification, resource management, process management, serving infrastructure, analysis tools and monitoring. Every one of those is ordinary engineering. Together they dwarf the model.

The paper's argument is not that this surrounding infrastructure is badly built. It is that machine learning erodes the abstraction boundaries software engineering depends on, so the usual techniques for keeping a large system maintainable work less well here. MLOps is the practice that grew up around exactly that problem.

2. CACE: changing anything changes everything

The paper gives the effect a name: CACE, for Changing Anything Changes Everything.

A model learns weights jointly. Feed it features x1x_1 through xnx_n and it finds a setting that works for that exact set. Now add a feature, remove one, or let one feature's distribution drift. The optimiser rebalances, and the learned importance of every other feature moves with it.

This is not a bug to be fixed. It is what joint optimisation means. But it destroys the property engineers rely on most: that you can reason about a component in isolation. There is no subset of an ML system you can change while holding the rest still, which is why a one-line change to a feature definition can require re-validating the whole model.

3. Entanglement and correction cascades

CACE has two named consequences in the paper.

Entanglement is the direct one: changing the learning algorithm changes which input signals it needs, which in turn forces changes to the infrastructure feeding it. The blast radius of a modelling decision reaches into systems the modeller does not own.

Correction cascades are the sneakier one. You have model A. It is nearly right for a new problem, so rather than retrain, someone learns a small model B that corrects A's output. Then C corrects B. Each layer is cheap and locally sensible. Collectively they create a stack where improving A can make the end-to-end result worse, because B and C were fitted to A's specific errors. Unpicking the stack later costs far more than training the right model once.

4. The blast radius of one change

One feature edit does not stay local. It moves every weight, which moves the output, which reaches anything downstream that was fitted to the old behaviour.

flowchart LR
A["Change one feature"] --> B["Every learned weight moves"]
B --> C["Model output shifts"]
C --> D["Corrector model now mis-fitted"]
C --> E["Undeclared consumer breaks"]
D --> F["Correction cascade"]
E --> G["Failure with no owner"]

5. Undeclared consumers

A model writes predictions to a table, a topic or a file. Nothing stops another team reading them.

The paper calls these undeclared consumers, and they are the ML equivalent of what software engineering calls visibility debt. Because there is no record of who depends on a given output, there is no way to know what you break when you change it. Worse, a consumer can feed the prediction back into a system that eventually produces your training data, creating a hidden feedback loop where the model influences its own future inputs.

The fix is access control and declared interfaces, not diligence. If reading a model's output requires requesting it, the dependency graph exists. If the output sits in an open table, the graph is unknowable by construction.

6. Glue code and pipeline jungles

Two system-level anti-patterns from the paper show up in almost every ML codebase.

Glue code is the supporting code written to get data into and out of a general-purpose package. Using an off-the-shelf library is cheap up front, and the glue that adapts your data to its expectations is where the mass ends up. The paper's suggested remedy is to wrap the black box in a common API so components stay swappable rather than letting the package's shape leak everywhere.

Pipeline jungles are what data preparation becomes when it grows by accretion: scrapes, joins and intermediate files added one at a time, each sensible on the day. Detecting an error in the resulting graph is hard, and recovering from one is harder. The paper is blunt that the fix is redesign, not more incremental additions.

7. Data dependencies cost more than code dependencies

Software engineering has good tools for code dependencies. A compiler and a linker will tell you what breaks. Nothing equivalent exists by default for data.

The paper's warning is about unstable and underutilised data dependencies. An unstable input is one whose meaning changes over time, often because it is itself the output of another model that someone else is improving. An underutilised input is one carrying so little weight that removing it would cost almost nothing, yet it stays because nobody knows it is safe to drop.

DependencyDetection toolFailure mode
CodeCompiler, linker, testsLoud, immediate
DataNone by defaultSilent, gradual

That table is the whole argument for data validation as a pipeline stage rather than an afterthought.

8. Five ways ML differs from software

Google's own MLOps guidance lists the practical differences that follow from all this.

  1. Team composition. The team includes data scientists or researchers who build models but may not be experienced software engineers.
  2. Development is experimental. You try different features, algorithms and parameter settings, and the job is to find what works, then reproduce it.
  3. Testing is more involved. Beyond unit and integration tests you need data validation, trained model quality evaluation, and model validation.
  4. Deployment is not one artifact. You are deploying a multi-step pipeline that retrains and redeploys, not a single prediction service.
  5. Production decays differently. Models fail from evolving data profiles rather than from bad code, so shipping without monitoring means failing without noticing.

Every practice in the rest of this path answers one of these five.

9. So what is MLOps

MLOps is DevOps applied to a system where the behaviour is learned from data rather than written down. That one difference is what generates the extra work.

A DevOps pipeline versions code. An MLOps pipeline has to version code, data and the trained model together, because reproducing a result requires all three. A DevOps test asserts on outputs. An MLOps test also has to assert on distributions, since the input can change while every line of code stays the same.

The rest of this path follows that thread: the maturity levels that describe how much of this is automated, the data and feature layer where skew is introduced, and the monitoring that decides when a model has stopped being worth serving.

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. What does the CACE principle state?
    • Cached features must be invalidated whenever the model is retrained
    • Changing anything changes everything, because a model learns its weights jointly
    • Continuous training always beats scheduled retraining on cost
    • Correction models should be applied before the base model, not after
  2. A team cannot retrain model A, so they train model B to correct A's output, then C to correct B. What has been created?
    • A pipeline jungle
    • An undeclared consumer
    • A correction cascade
    • Training-serving skew
  3. Why are undeclared consumers described as a form of visibility debt?
    • They consume compute that does not appear on the model's budget line
    • They read a model's output with no record of the dependency, so nobody knows what a change breaks
    • They are written in a different language from the training pipeline
    • They cannot be monitored because their predictions are not logged
  4. According to the paper, what is the recommended remedy for glue code around a general-purpose ML package?
    • Rewrite the package internals so it matches your data format
    • Move the glue into the training script so it stays in one file
    • Wrap the black box in a common API so components remain swappable
    • Avoid third-party packages and implement every algorithm in-house
  5. What makes data dependencies more dangerous than code dependencies?
    • They are usually larger in volume than the code
    • They change more often than code does in every system
    • They require more storage, so they cost more to version
    • There is no default tooling that detects them, so they fail silently and gradually

Related lessons

Math
intermediate

Gradients, Jacobians, and Hessians: Calculus in Many Dimensions

One derivative becomes three objects once a function has many inputs and many outputs. This lesson builds the gradient, the Jacobian and the Hessian, shows what each one actually tells you, and explains why curvature decides how many steps an optimiser needs and why nobody ever writes the Hessian down.

10 steps·~15 min
Math
intermediate

The Derivative Is a Local Linear Model

Machine learning uses the derivative as a search strategy, not a symbolic exercise. This lesson builds it as the best local linear approximation, derives the gradient descent update from it, and shows why estimating derivatives numerically loses half your digits and costs one function evaluation per parameter.

10 steps·~15 min
Programming
intermediate

Benchmarks That Hold Up, and Knowing When to Stop

A benchmark is an experiment, and most are badly designed enough to produce confident wrong answers. This lesson covers what a measurement must control to mean anything, the ways microbenchmarks lie including code the compiler deletes, how to catch regressions in continuous integration despite noisy machines, and how to recognise the point where optimising stops paying.

7 steps·~11 min
Programming
intermediate

Measure First: The Arithmetic That Decides What to Optimise

Most optimisation effort is spent on code that was never the problem, and the reason is that intuition about where time goes is reliably wrong. This lesson covers why guessing fails, the arithmetic that caps what any optimisation can buy, the difference between latency and throughput, and how to set a target that tells you when to stop.

7 steps·~11 min