Software Is Not Flexible. It Hardens as It Grows
Software has a reputation for being forgiving, something that is easy to change, easy to fix, and easy to reshape once we finally understand the problem we were supposed to be solving. That reputation is not entirely wrong, but it only holds at very small scales and only for a short while.
We’ve been misled by the word soft.
Software has earned a strange reputation over the years. Not just for being powerful, but for being forgiving. Easy to bend. Easy to revise. Easy to clean up once the real requirements finally become clear. That belief doesn’t usually come from engineers. In most teams, it is reinforced by product timelines, business pressure, and the comfort of knowing that nothing ships in steel or concrete. Code feels negotiable. Mistakes feel reversible.
Early in a project, code behaves like Lego blocks. You snap things together, pull them apart, rebuild the castle into a spaceship, and nothing breaks in any visible way. If a decision turns out to be wrong, you patch around it and move on. Compared to steel, concrete, or wiring, software feels forgiving, almost indulgent of experimentation.
As a codebase grows, services multiply, more developers contribute code, and business logic keeps getting layered in, it starts to behave more like wet concrete. Early on, you can still push it around, move walls, redraw boundaries, and smooth over rough edges. But once the system is coordinating across services, holding persistent data, serving real users, and supporting revenue, it begins to set. From that point on, change no longer feels like editing. It feels like demolition.
Most teams don’t notice the moment this shift happens. They notice it later, when things that used to be easy start taking longer, and when small changes begin to carry an uncomfortable amount of risk.
The Lego mindset is part of how teams get there. It shows up as small technical shortcuts that feel harmless at the time, like a missed cache key in Redis that quietly sends traffic back to SQL Server, or a background job that bypasses the domain layer because it is “just internal.” If you stack bricks just because they fit, you don’t end up with flexibility. You end up with a structure that works right up until it doesn’t. One edge case, one traffic spike, or one new requirement later, the wobble starts.
Optimising for speed of assembly is not the same as optimising for survival under load.
Real engineering is about whether the internal bonds hold when the system is stressed, not about how fast you can put something together. The Lego approach optimises for getting to “done,” but it does very little to optimise for load, failure modes, or long-term change.
The Double Standard
Most systems don’t fall apart when they are failing. They fall apart right after they start working.
Once something is live and people depend on it, the definition of risk quietly shifts. Shipping fast still matters, but breaking things suddenly matters more. So teams start making small compromises to keep momentum going. They skip an abstraction to hit a deadline. They hardcode a path because it is faster than untangling the model. They promise themselves they will clean it up later, when things are calmer.
Remember, that calm never comes.
In every other discipline, scale brings more rigor, not less. Bridges do not loosen their standards as traffic increases. Aviation systems do not get more casual as routes expand. Software, somehow, is treated as the exception. We justify this because we can’t see the cracks. There is no sagging beam or visible fracture. Everything looks fine until it isn’t, so we tell ourselves the risk is abstract, manageable, and something we can deal with later.
We would never accept that logic anywhere else.
Imagine a pilot saying:
“We’re behind schedule. Let’s skip the pre-flight check. We’ll just push an engine patch mid-air if things start smoking.”
Or a surgeon saying:
“I’m skipping the hand-washing to save time. We can treat the sepsis during the next sprint.”
Or a civil engineer saying:
“The foundation is cracking, but the client needs the penthouse finished by Friday. We’ll refactor the basement once the building is full of people.”
In those fields, discipline is the price of entry. In software, we still talk about it as if it were a nice-to-have.
Once users depend on a behavior, a temporary hack quietly stops being temporary. It becomes an undocumented contract.
The Physics of Slowdown
Once those contracts exist, the system starts to change how it behaves.
This is where cohesion and coupling stop being abstract ideas and start showing up in daily work. Responsibilities that belong together end up scattered. A change in one place quietly reaches into others. Code stops reflecting intent and starts reflecting everything it has ever had to accommodate.
You see the effects long before anyone names the cause. Engineers hesitate before making small changes. Deployments get delayed, not because the change is large, but because nobody is confident about what else might be affected.
At first, this friction is easy to ignore. Then it compounds.
Features that once took days start taking weeks. Bug fixes trigger regressions. Releases stop feeling routine and start feeling dangerous. The Total Cost of Ownership does not rise gradually. It jumps.
When teams say they have slowed down, this is usually why. Not because engineers suddenly care too much about quality, but because the system has lost its ability to absorb change.
Other industries never had the luxury of pretending otherwise. A sloppy manufacturing supply chain can bankrupt a company in a quarter. A loose telecom protocol can take an entire network down. Poorly planned urban infrastructure costs lives.
In those fields, technical debt isn’t a metaphor. It’s a suicide note.
Software is the only place where we’ve convinced ourselves that the bill can be outrun indefinitely.
Knowing When to Step Back
The instinct to defer discipline usually comes from good intent, not ignorance. Lean Startup thinking pushed back, rightly, against over-engineering before product market fit. Many teams wasted time building futures that never arrived.
The problem begins when that mindset outlives its usefulness and teams fail to recognise the inflection point.
Once a product works, later rarely comes. Usage grows, data accumulates, teams expand, and the system quietly shifts from experiment to infrastructure. At that point, treating discipline as optional stops being pragmatic.
This is the moment where product and business leadership matters most. Speed does not come from ignoring technical limits. It comes from knowing when the system needs time, not features.
Slowing down here does not mean stopping. Refactoring and rebuilding are not aesthetic exercises. They are strategic interventions to restore the system’s ability to change. Sometimes that means untangling a dependency. Sometimes it means rebuilding a critical path.
The only sustainable approach is incremental change. Patterns like the Strangler Fig exist because hardened systems can’t be reset, only replaced piece by piece.
Knowing when to listen to these signals is what keeps speed, reliability, and trust intact as systems grow.