Some problems come back no matter how well you fix them. The queue backs up again a month later. The team's velocity recovers and then sags. The service that was rewritten for reliability starts paging just as often as the old one. When a fix does not hold, the usual conclusion is that it was not executed well enough. The more useful conclusion is that you fixed an event in a system whose structure produces that event, and structure wins.
Donella Meadows' Thinking in Systems is the shortest good introduction to this way of seeing, and almost everything in it maps directly onto software organizations — which are, after all, systems of people, code, and incentives interacting over time.
Stocks and flows
A stock is an accumulation: the number of items in a queue, unresolved bugs in the backlog, technical debt, cash, trust. A flow is a rate that changes it: arrivals and departures, bugs created and bugs fixed. The critical property is that stocks change slowly and buffer the system, which is why the effect of a change is almost never immediate and why intuition fails so reliably here.
Two rules follow. First, a stock only shrinks when the outflow exceeds the inflow — hiring two more engineers does nothing for a backlog whose inflow rises with headcount. Second, stocks create delays, and delays create oscillation: by the time you see the effect of your action, you have usually already over-corrected. Anyone who has watched an autoscaler thrash, or a team swing between "ship faster" and "stop everything and fix quality", has watched a delay produce oscillation.
Feedback loops
- Balancing loops seek a target and resist change. A thermostat, a circuit breaker, an autoscaler, a code review process, a rate limiter — all of them push the system back toward some setpoint. They are what makes a system stable, and also what makes it stubborn.
- Reinforcing loops amplify. Compound interest, viral growth, and — less pleasantly — the loop where a shaky codebase slows delivery, which increases pressure, which produces shortcuts, which makes the codebase shakier. Reinforcing loops are behind every exponential curve, good and bad.
- Most interesting behaviour comes from several loops interacting, with one dominating at a time. Systems change character when dominance shifts — which is exactly what an outage feels like from the inside.
A retry storm is the canonical engineering example: a dependency slows, clients retry, the extra load slows it further, more retries follow. The reinforcing loop was always there; it only became dominant when latency crossed the retry threshold. Nothing about the code changed at the moment things fell apart. The loop's dominance did.
Archetypes you will recognize
- Fixes that fail — the fix relieves the symptom and strengthens the cause. Adding capacity to absorb a bad query buys you a bigger bill and a query nobody ever profiles.
- Shifting the burden — a workaround becomes permanent and the capability to solve the real problem atrophies. Every heroic on-call engineer who quietly restarts the service each morning is holding up a system that would otherwise be fixed.
- Limits to growth — a reinforcing loop runs into a constraint it did not have before. Onboarding more users is trivial until the shared database is the ceiling.
- Tragedy of the commons — a shared resource with no feedback to individual users. Staging environments, the CI queue, and the on-call rotation all degrade this way.
- Escalation — each side responds to the other, and the loop has no natural stop. Two teams adding defensive timeouts and retries against each other until neither can explain the system's behaviour.
- Drift to low performance — the standard quietly follows the actual result. Alert thresholds get raised, the flaky test gets retried, and "normal" moves down a notch each quarter.
Leverage points
Meadows' most quoted contribution is a ranking of where to intervene in a system, from the weak to the powerful. Adjusting parameters — thresholds, sprint length, team size, timeout values — is the weakest and the most popular, because it is the easiest. Stronger interventions change the size of buffers and the structure of stocks and flows. Stronger still: changing the length of delays, the strength of balancing loops, the gain on reinforcing loops. Above those sit information flows — who gets to see what, and how quickly.
Missing feedback is one of the most common causes of system malfunction — and adding it back is usually cheap.
That one is enormously actionable in engineering. Developers who never see production metrics write code that is hard to operate. A team that is not on call for its own service optimizes for shipping, not for reliability. Deploy pipelines that take forty minutes hide the connection between a change and its consequence. In every case, the fix is not more discipline — it is a shorter, more visible feedback loop. Above information flows sit rules and incentives, then the ability of the system to restructure itself, and at the top, the goals and the paradigm everyone is operating from. Anyone who has watched a team measured on story points optimize for story points has seen the top of the list beat the bottom of it.
Practising it
- 01When something breaks, ask what structure made this event likely — not who made the mistake. Events are the visible layer; patterns, structure, and mental models are underneath.
- 02Draw the loops. Two boxes and an arrow that closes back on itself explains more in an incident review than three pages of timeline.
- 03Look for the delay. If action and consequence are separated in time, expect over-correction and design for it.
- 04Check whether your metric is the goal or a proxy for it. The system will optimize whatever you actually measure, including at the expense of what you meant.
- 05Prefer interventions that change information flow and structure over interventions that change a number.
- 06Expect policy resistance: if a change is fought by the system rather than by people, some balancing loop is defending a goal you have not identified yet.
The habit this builds is patience with complex problems — a willingness to sit with a system long enough to see its shape before acting on it. That is an unglamorous skill, and it is most of what separates an engineer who fixes incidents from one whose systems stop having them.