If software feels slower even as hardware improves, this explains why. The issue is not effort or quality. It is accumulation driven by incentives. Here’s the pattern, why it made sense, and how teams can reverse it.
Part 1: Why software slows down
The Accumulation Problem No One Is Talking About
Everyone experiences this. Engineers, product managers, executives, and users all agree that something feels off. Software keeps getting slower and harder to use, even as hardware improves.
This is not a story about lazy developers or indifference. It is about how software becomes fragile as it is repeatedly asked to do new things ,while never being released from the obligation to continue doing everything it has done before.
This article explains the mechanism behind that pattern, names the principle that drives it, and how teams can reverse it.
The Wrong Explanations
Most explanations for declining software quality fall into familiar blame stories: Developers don’t write code as clean or concise as they can. Companies don’t care about users. This is the price of progress. Hardware will eventually catch up.
These explanations feel intuitive. They match experiences and require no system-level reasoning. They also assign responsibility to individuals or motives. They fail to explain is structure.
Why These Explanations Fail
Software does not decay the way physical objects do. It accumulates.
Each layer exists for a valid reason at the moment it is added. Problems arise, not because teams act irresponsibly, rather as the layers continue to interact long after the context that justified them has disappeared.
What looks like poor quality work after the fact is the result of people protecting the system from immediate risk, using the limited information they had, and without knowing how the system would evolve or how long those choices need to hold.
The system - the environment in which software decisions are made - consistently punishes removal more than addition. That system is the combination of technical, organizational, economic, and human forces that shape decisions. Software slows down because this environment makes addition feel safe and removal feel dangerous.
Why Accumulation Is Rational and Dangerous
This pattern repeats across the teams and years: A team encounters a problem and solves it in the moment. They add to what the software already does, and what users and other systems expect it to do. This feels safer than removing existing elements and system behaviors.
The understanding of why things are the way they are decays as people move on. Old decisions become “maybe necessary.” Eventually no one knows why something exists, only that removing it might break something.
This is not organizational failure. It is minimizing the risk under uncertainty.
Accumulation stabilizes individual decisions in the short term. It destabilizes the system in the long term.
The Medical Analogy
Imagine a patient who has seen many doctors over several decades. Each doctor prescribes something that helps at the time. Years later the patient is taking many medications. No single doctor knows which are still necessary, how they interact, or what would happen if one were removed.
Adding a new medication feels safer than removing an old one. Over time the patient feels worse, not because any doctor made a bad decision, rather because the system accumulated obligations without an equally safe way to release them.
Software evolves the same way.
Two Forms of Stability That Are Often Confused
There are two forms of stability at play.
Decision stability is local and short-term. From an individual decision-maker’s perspective, accumulation feels safe here. It minimizes blame and risk.
System stability is global and long-term. From this perspective, accumulation is destabilizing. Interactions multiply, performance degrades, and complexity compounds.
The conflict between these two forms of stability is where software slowdowns originate.
The Accumulation Asymmetry Principle
To make this pattern discussable, it needs a name.
The Accumulation Asymmetry Principle states that in complex systems under uncertainty, adding new elements is consistently safer for decision-makers than removing existing ones, even when accumulation degrades long-term system coherence and performance.
This behavior is rational and defensible. Accumulation is not a mistake. It is the dominant survival strategy.
Part 2: Why removal is hard than addition
If accumulation is rational, the real question is why removal stays so hard.
The Accumulation Loop
A problem appears. A solution is added because it carries low immediate risk. The problem appears solved - for now.
Context and teams change. The original purpose becomes unclear. Removal feels risky. A new solution is added instead. System complexity increases. Interactions multiply. Performance and clarity decline.
Nothing breaks at once. The system simply becomes harder to change.
This pattern did not emerge by accident. It was reinforced by development practices that were rational in their original context.
Where “Release Early, Release Often” Came From
The idea of incremental release did not emerge from carelessness or a desire to ship broken software. It emerged from a very specific historical context and solved a very real problem at the time.
The phrase most often associated with the principle comes from Eric S. Raymond’s 1997 essay The Cathedral and the Bazaar. In it, Raymond contrasted two development models. The “cathedral” model emphasized long periods of internal development, heavy upfront testing, and infrequent releases. The “bazaar” model emphasized frequent releases, visible work, and rapid feedback from users. Raymond summarized the approach simply: release early, release often, and listen to your users.
The point was not to ship low-quality work. It was to reduce the risk of hidden failure. In an environment where users were technically sophisticated, code was visible, and feedback was fast, bugs tended to surface quickly rather than accumulate silently. The model treated the user base as a broad testing resource, rather than relying solely on internal testing.
Two forces helped spread this approach. The first was Linux. Linus Torvalds and the early Linux community demonstrated that frequent releases with known flaws could work when users were capable, motivated, and willing to participate in improvements. Problems were exposed publicly. Fixes arrived incrementally. The system improved through visible iteration rather than guarded perfection.
The second force was the shift from boxed software to networked services. In the early 2000s, deployment became cheap. Updates could be pushed without manufacturing costs. Rollback became possible. Software could change continuously rather than in discrete product cycles. Incremental releases stopped being a technical philosophy and became an economic advantage.
Agile practices did not invent this approach. They normalized it. Shipping imperfect versions, prioritizing feedback over completeness, and optimizing for learning speed became accepted by default. The model worked best when users behaved like collaborators, failures were reversible, systems were shallow, and change carried limited downstream risk.
Those conditions mattered more than the slogan.
Why Incremental Release Became a Trap
The philosophy of “releasing early and often” was pragmatic for its time. It worked when users acted as collaborators, systems were less complex, and feedback arrived quickly. Over time, systems grew interdependent. Users stopped being testers. Rollbacks became costly and impractical. Feedback slowed.
The practice remains even though the conditions that made it effective no longer exist.
How Software Can Get Fast Again
Software does not improve because people write cleaner code or work longer hours. Software improves when the decision environment changes.
Removal must be made safe and routine. Teams need deletion budgets, explicit sunset dates, and visible deprecation pipelines. People understand a system when it is clear who is responsible for each part. There needs to be records explaining why things exist - capturing the reason a decision was made at the moment it was made, in a form future people can find it, with accountability that survives team turnovers. Someone must remain responsible for deciding whether decisions should still stand. Speed must be treated as a product requirement. When speed is optional, it loses every roadmap decision.
The Mosquito Load Principle
Not all degradation comes from major failures. Large bugs break systems in isolated, noticeable events. Small issues wear systems down all the time. When teams only fix problems that are loud and reproducible, the quiet swarm becomes the user experience. Systems improve when leaders create room to notice, prioritize, and remove these small burdens over time.
This pattern is reinforced by how most teams prioritize and measure bugs.
Why “Hotspot-First” Fixes Miss the Mosquitoes
Most engineering teams rely on a well-known practice: find the top few bottlenecks and fix those first. Profile the system. Identify the slowest paths. Address the five biggest problems, rather than spreading effort across everything.
This approach is valid when a small number of causes explain most of the pain. It works well for clear performance regressions, major outages, and a single hot path that dominates load. When those bottlenecks are causal, hotspot-first fixes can deliver gains. The problem users experience when they hear “that only happens to you” comes from a different category of issue.
What Is Actually Happening
Most bug triage systems are biased toward problems that are loud, countable, and easy to reproduce. Teams tend to prioritize issues based on how many reports they receive, whether the problem can be reproduced, whether it blocks a release, or whether an important customer complains.
This creates a predictable blind spot. Many small issues are under-reported, difficult to reproduce on demand, and spread thinly across a user base. Each one looks rare in isolation, even when thousands of users experience a different version of the same annoyance. From the outside, the response sounds dismissive. From the inside, the dashboards simply do not show a clear signal.
When a user is told “we cannot reproduce it,” what often means is “our measurement systems are not designed to see this class of problem.”
How Small Issues Accumulate Into System Drag
Each minor issue often results in a localized workaround. A conditional branch is added. A fallback is introduced. A timeout is extended. State is handled differently in one edge case.
None of these changes are alarming on their own. Over time, they accumulate into more control paths, more implicit assumptions, and more hidden interactions. The system becomes harder to reason about and slower to change, even if no single issue ever rises high enough to appear in a top-five list.
Fixing the largest bottlenecks does not reduce this load. Removing one large obstacle does not stop a swarm.
How Hotspot-First Can Train the Wrong Behavior
When teams focus exclusively on what ranks highest, they unintentionally train themselves to ignore long-tail pain. Low-frequency issues, quality-of-life regressions, intermittent failures, and small inconsistencies fall through the cracks.
Users notice this. Once people feel their experience is routinely dismissed as isolated or unimportant, they stop reporting problems. As reports decline, the data appears to confirm the original assumption. The blind spot deepens, and trust erodes quietly.
From the system’s perspective, things look stable. From the user’s perspective, the software feels increasingly fragile.
The Correction: Keep Hotspot-First and Add a Mosquito Program
Hotspot-first work should not be abandoned. It should be paired with a deliberate mechanism for the long tail.
Teams still need to identify and fix the largest, most visible bottlenecks. Those failures matter, and ignoring them would be irresponsible. At the same time, a system that only responds to what ranks highest in dashboards will systematically miss the class of issues that degrade experience day to day.
A mosquito program begins by reserving explicit capacity for small fixes that are not tied to major features or headline outages. This is not cleanup work done “if there is time.” It is time that exists by design. The goal is not to hunt individual tickets, rather to reduce friction that touches many users indirectly through shared paths, states, or assumptions.
This requires tracking bug density rather than raw bug counts. Individual reports often look rare and unrelated. When grouped by underlying subsystem, state transition, or interaction point, they reveal patterns that would otherwise remain invisible. A thousand scattered annoyances can become a single, addressable problem once they are seen as a cluster rather than a list.
Many of the issues users describe as “only happens to me” fall into this category. They are difficult to reproduce on demand and therefore easy to dismiss. The correct response is not debate, but measurement. When a problem cannot be reproduced reliably, it needs better instrumentation. That might include structured error events, privacy-safe state snapshots, or timing data around critical flows. Once these signals exist, uncertainty shifts from argument to observation.
Preventing reintroduction matters as much as removal. A mosquito program adds small, targeted regression tests around the flows that fail repeatedly. These are not comprehensive test suites. They focus on transitions that are historically fragile, such as degraded network conditions, concurrency edges, or partial state recovery. The aim is to protect hard-won clarity, not to achieve theoretical coverage.
Finally, problems with unknown causes should be treated as a first-class category. Instead of closing tickets that cannot be reproduced, teams track them explicitly. The success metric is a reduction in unknowns over time, not the speed with which issues are dismissed. When uncertainty is acknowledged rather than ignored, understanding can grow.
Systems improve when leaders make space for both modes of work. Large failures must be addressed. The quiet swarm must also be reduced. Speed returns not by heroics, but by steadily shrinking the accumulation of small burdens that otherwise become the system.
Part 3: How systems get fast again
Once the problem is understood, the solution is not harder work, but different structure.
How Systems Can Get Faster Again
Software gets faster again when the system relearns how to remove, not just add, and when performance is treated as a first-class constraint with explicit budgets.
Most teams already know what needs attention. The failure is rarely awareness. It is structural. Teams lack a safe way to see diffuse problems, make room for them, and remove accumulated behavior without breaking trust or outcomes. Speed returns when this loop is deliberately redesigned.
A useful framing is simple: measure, allocate, and remove.
Measure What Users Actually Experience
Most performance and quality issues are not concentrated in a single failure. They are distributed across journeys, states, and edge conditions. When teams only measure what is loud, reproducible, or blocking, they systematically miss what users experience most often.
What needs to be measured instead is friction density, rather than isolated severity. This includes how many small interruptions occur during a typical user journey, not just whether one catastrophic event occurred. It includes clustering related symptoms across devices, networks, locales, or accounts, rather than counting raw tickets. It includes tracking problems with unknown causes, rather than treating unresolved issues as noise. It also includes performance variance rather than averages, since the slowest segment of users often defines perceived speed.
When a user is told “that only happens to you,” the problem is rarely the user. The system is blind. This is not an engineering failure. It is a sensing failure.
Allocate Capacity for Quality and Removal
If quality work has to compete directly with feature delivery, it will always lose. The result is rational short-term progress that produces long-term drag.
High-functioning systems do something different. They reserve explicit, recurring capacity for addressing small, widespread issues. They treat unknowns as legitimate work rather than distractions. They protect time for simplification and correction that is not tied to shipping something new.
This capacity is not heroic cleanup. It is structural. It covers long-tail bug reduction, performance regressions, state inconsistencies, and edge-case reliability. Without protected allocation, teams will always fix the biggest visible problems first, while the quiet accumulation becomes the system itself.
Make Removal Safer Than Addition
Systems slow down not because people refuse to delete things, rather because removal carries asymmetric risk. Adding behavior feels safe. Removing behavior feels irreversible. When something breaks, the cost of being wrong about removal is immediate and personal.
Leaders can rebalance this asymmetry by making removal a supported act. This includes normalizing deprecation paths where behavior is first warned, then measured, and finally removed. It includes requiring sunset plans for major additions, not as bureaucracy, but as an acknowledgment that obligations should expire unless reaffirmed. It includes rewarding simplification outcomes, not just delivery metrics. It also includes making it acceptable to say, clearly and publicly, “this no longer belongs here.”
What stabilizes individual decisions often destabilizes the system. Speed returns when the environment makes subtraction as legitimate as addition.
What This Means for AI
AI is often presented as the solution to software complexity. The reality is more precise. AI can simplify structure. It cannot decide what no longer matters.
That distinction is critical.
In principle, AI could be given a million lines of code and asked to simplify the system. In practice, this only works when simplification is constrained by explicit intent. AI can refactor, reorganize, and reduce redundancy. It cannot safely decide which behavior should disappear unless humans tell it exactly what to remove.
Removal is a decision problem, not a code problem.
Why “Just Give It the Code” Fails
Even a highly capable model has a fundamental blind spot. Code does not fully encode intent.
AI can see how functions call one another, where logic is duplicated, which paths appear unused, where complexity concentrates, and where conditionals look suspicious. It can identify dead-looking code and suggest simplifications. What it cannot know is which behavior is relied on externally, which seemingly unused path protects a rare and critical case, which workaround exists because of a business promise, or which edge case defines user trust.
That information lives in people’s heads, institutional memory, contracts, habits, and expectations. It does not live in the code.
If an AI system is asked to remove what is “no longer needed,” the effort has already failed. “Needed” is not a syntactic property. It is a meaning judgment.
The Critical Division of Labor
AI is good at simplifying structure. Humans are required to authorize removal of meaning.
AI can clean the room. Only humans can decide what can be thrown away.
This is not a limitation of current models. It is a boundary imposed by how software functions as a social and economic system. Behavior becomes obligation the moment someone relies on it. Deciding when that obligation can end is a human responsibility.
Where AI Actually Shines
AI becomes powerful when paired with explicit intent. When humans decide what should go away, AI can do the mechanical work of making that decision real across a large and complex codebase.
Examples of effective prompts look like this:
“This feature is deprecated. Remove all code paths that support it.”
“Users no longer need offline mode. Identify and simplify related logic.”
“This API will be removed next quarter. Collapse fallbacks and clean up.”
“Assume feature X never existed. What becomes simpler?”
In each case, humans decide the boundary. AI executes the simplification safely and thoroughly. The labor shifts from fragile manual refactoring to guided structural change.
That is the correct division of work.
Why This Matters for Software Quality
The accumulation problem exists because removal is risky, intent is unclear, and decision-makers avoid guessing. AI does not eliminate that risk. What AI does eliminate is mechanical effort, fear of touching large codebases, time cost, and the difficulty of cascading changes.
AI lowers the cost of acting on decisions. It does not replace the decisions themselves.
Used well, AI makes simplification cheaper, faster, and less error-prone once intent is established. Used poorly, it accelerates accumulation by making addition easier than ever.
Without clarity, AI makes it easier to add more behavior, not to remove what no longer matters.
Stability-First and Incremental Release Reframed
This is not nostalgia. It is a question of where uncertainty is placed.
Incremental release asks users to absorb instability so teams can learn faster. Stability-first development asks teams to absorb complexity so users do not have to. Both approaches are rational responses to uncertainty. They simply place the cost in different locations.
Incremental release optimizes for speed of learning. It works best when feedback is fast, rollback is easy, and users tolerate rough edges. Stability-first development optimizes for trust. It works when leadership is willing to invest in coherence early, accept slower visible progress, and treat release cadence as a design decision rather than a default.
The most successful systems do not live at either extreme. They choose deliberately. They decide which uncertainty should be carried internally and which can safely be exposed. That choice is rarely explicit, yet users feel it immediately. The real question is not which approach is better in theory. It is which one your users are silently asking for.
Stability-first systems often deliver higher long-term satisfaction even when they appear slower or less flashy. Competitors may seem faster in the short term. The payoff arrives through reliability, predictability, and trust that compounds over time. This approach is not impractical. It is strategic.
This reframes the problem away from tools and methodologies and toward leadership design. What do you want optimized in your system: speed of learning or trust in outcomes? Where do you want uncertainty absorbed: by users or by the organization?
AI does not decide whether a system simplifies or bloats. It amplifies whatever the leadership model already rewards.
What This Means for Careers
Modern systems are too large for any individual to fully understand. That changes what “valuable” means.
The most valuable people are not the fastest coders. They are not simply the ones who write the cleanest, most concise code either. They are the ones who can reason under uncertainty, see interaction effects, decide what no longer matters, and make removal safe for others. This is not a technical skill. It is a thinking skill.
The Uncomfortable Truth About the Job Market
Modern software systems are now too large, too layered, and too shaped by history for any single person to fully grasp. This changes who is valuable, who is at risk, and what kind of work actually matters. This shift is not about age or talent. It is about a person’s relationship to system memory and decision authority.
Early-Career Developers
New developers inherit systems whose original constraints they did not experience. They did not see the failures that shaped current tradeoffs, yet they are asked to move quickly inside structures they cannot safely reason about. Even with excellent comments and clean code, they lack historical intent, architectural context, and knowledge of what cannot be removed.
This makes them strong at local optimization and vulnerable when asked to make global changes. When regressions occur, the causes are often structural, yet the blame lands locally.
The opportunity is real. Early-career developers who learn to ask why something exists, what would break if it were removed, and who depends on a given behavior will outgrow peers quickly. They move from implementers to thinkers. That shift compounds.
Senior Developers and Long-Tenured Engineers
Veteran engineers often hold something far more valuable than fluency with the latest tools. They carry system memory. They know which code looks simple and is dangerous, which workarounds exist for a reason, and which failures were expensive enough to never repeat.
This knowledge is rarely documented and rarely rewarded. It creates a quiet trap. When these engineers leave, fragility spikes. When they stay, they risk becoming bottlenecks.
Their value shifts over time from writing code to authorizing change, from building features to preventing collapse. Many organizations fail to recognize this role, even as they depend on it.
Team Leads and Engineering Managers
Team leaders sit at the fault line. They are accountable for delivery and stability, often without authority to remove anything. They are pressured to onboard quickly, rotate people frequently, and rely on “best practices” as substitutes for judgment.
When things go wrong, leaders often mistake speed for health.
The leaders who succeed create explicit ownership of subsystems, protect time for simplification, and make it acceptable to say “we do not fully understand this yet.” They manage decision environments, not just people.
Product Leaders and Executives
As systems mature, feature decisions matter less than removal decisions. Roadmap control matters less than constraint awareness. Strategy shifts toward deciding what the system should stop supporting.
Common assumptions fail here. Code being present does not mean it is understood. Comments do not make behavior safe. Silence from users does not mean the system is healthy.
Effective product leadership requires slowing things down without panic, resisting flashy comparisons, and valuing trust over novelty. AI does not change this responsibility. It accelerates whatever the organization already rewards.
The Core Insight
For the developer, team lead, or product leader reading this, the job is no longer just to build software. The job is to participate responsibly in a long-lived system.
For developers, this means reasoning about interactions rather than only code, treating deletion as a first-class skill, and asking for context before making changes.
For team leaders, it means protecting system memory, rewarding simplification, and making removal safe.
For product leaders, it means deciding where instability lives, accepting slower optics in exchange for stronger trust, and understanding that tools amplify culture.
The most valuable people going forward will not be the fastest coders or the loudest shippers. They will be the ones who can see the system, reason under uncertainty, decide what no longer matters, and create conditions where others can act safely.
They will be the ones who can say, clearly and credibly, “Here is what we should stop doing, and why.”
That is not a technical skill. It is a thinking skill.
Final Note
Software does not slow down because people stop caring. It slows down because systems reward addition and punish removal.
Every pattern described here is rational in isolation. Each decision was defensible at the time it was made. The problem is not effort, talent, or intent. It is that the environment surrounding those decisions steadily made accumulation safer than subtraction.
Speed returns when leadership changes incentives rather than asking teams to work harder or write cleaner code. It returns when removal becomes a supported act rather than a personal risk. It returns when uncertainty is absorbed deliberately rather than pushed outward by default.
This is not a tooling problem or a talent problem. It is a decision problem. Systems speed up when leaders make it safe to remove what no longer matters.
This line of thinking also informs my work with leadership teams through First Ascent Thinking.
FOOTNOTE: Attribution and Prior Work
The Accumulation Asymmetry Principle is a synthesis rather than a standalone invention. The underlying dynamics it describes have been observed across multiple domains, particularly in software evolution, systems theory, and organizational decision-making.
In software engineering, researchers such as Meir Lehman documented that long-lived systems naturally grow in complexity over time unless active effort is made to reduce it (often referred to as Lehman’s Laws of Software Evolution). Systems theorist John Gall similarly observed that complex systems tend to emerge through incremental growth rather than deliberate design, making later simplification difficult.
Related ideas also appear in G. K. Chesterton’s “Chesterton’s Fence,” which cautions against removing structures without understanding their original purpose—a principle that helps explain why removal carries perceived risk.
What is often missing from these frameworks is an explicit explanation of why accumulation persists: the asymmetry in perceived risk between adding new elements and removing existing ones under uncertainty. The Accumulation Asymmetry Principle names this decision-level dynamic to make it easier to recognize, discuss, and reason about across contexts including software, medicine, and institutions