Back to blog

Evolution over Revolution: A Pragmatic Approach

February 28, 202610 min read

The allure of the revolutionary rewrite is real — and so are the wreckage and missed deadlines it tends to leave behind. This article examines why an evolutionary approach to software development produces more durable outcomes, what history teaches us about the costs of chasing revolution, and how pragmatic teams can balance incremental progress with the occasional bold move when it's truly warranted.

The Pull Toward Revolution

There's a particular moment in most software projects — usually somewhere around the third or fourth time you've worked around the same design flaw — when revolutionary thinking starts to feel like the only reasonable option. The existing system isn't just imperfect; it's fundamentally imperfect, and another patch feels dishonest. Surely the right answer is to tear it down and build something better.

That impulse isn't wrong, exactly. But it's worth examining carefully before acting on it.

Revolutionary endeavors in software tend to carry consequences that look similar regardless of context: shattered timelines, frustrated stakeholders, a months-long freeze on the features the business actually needs, and — if things go poorly enough — a team that's lost trust with the people who depend on them. The promise was a fresh start. What often arrives is a longer detour back to where the system already was, minus the institutional knowledge that accumulated along the way.

Evolutionary progress — small, deliberate, compound improvements — rarely generates the kind of excitement that a complete rewrite does. But it has a much better track record.

The Illusion of the Clean Slate

When you're deep in legacy code, the appeal of starting fresh is partly aesthetic. A clean repository, modern patterns, no accumulated cruft. But what that framing misses is that the problems embedded in the existing system aren't usually architectural accidents. They're the scar tissue of decisions that made sense at the time — integration constraints, organizational priorities, edge cases that weren't obvious until they were encountered in production.

A rewrite doesn't transfer that knowledge automatically. It typically discards it. Which means teams spend months rebuilding not just the system but the understanding of why the system works the way it does — often arriving at something that looks cleaner but behaves in subtly worse ways until it has accumulated the same lived-in complexity it was meant to replace.

This isn't an argument against significant change. It's an argument for being honest about what "revolution" actually costs, versus what "evolution" can accomplish given the same calendar time.

What History Keeps Demonstrating

Duke Nukem Forever: The Perils of Perpetual Restart

Few software projects illustrate the costs of revolutionary thinking as vividly as Duke Nukem Forever. Scott Miller, founder of Apogee (the company behind 3D Realms), has been candid about what went wrong. The development of DNF stretched across more than a decade. The problem wasn't a shortage of ambition — it was the repeated decision to restart rather than ship.

Each time new 3D technology emerged, the team rebooted to incorporate it rather than shipping on what existed. There was no clear development roadmap. The team was chronically understaffed — by Miller's own account, at least 50% below what the project required. Every reboot reset the clock and discarded work that had already been done.

When the game finally shipped in 2011, it was a disappointment. The gameplay couldn't match expectations that had been building for fourteen years. The company had been sold. The resources consumed by the project far exceeded anything it returned.

The lesson isn't that you should never update your technology choices. It's that "let's reboot to use the better approach" — repeated, without a clear exit condition — is a path to nowhere. At some point, shipping something real is worth more than shipping something perfect.

Betamax vs. VHS: Evolutionary Fit Beats Technical Superiority

The format war between Sony's Betamax and JVC's VHS is a useful counterpoint to the assumption that the best technical solution wins. Betamax launched first and offered superior video quality. On a pure technical comparison, it was the stronger product.

VHS won anyway.

JVC focused on practical concerns: longer recording times, lower manufacturing costs, and licensing flexibility that encouraged wider distribution. These weren't glamorous advantages. They were evolutionary improvements aimed at what consumers actually needed — recording a full football game, finding tapes at the local video store, affording the hardware.

Betamax lost not because it was bad, but because the evolutionary improvements that mattered to users were happening on the other side. Being technically superior isn't worth much if the competition is better aligned with what people need in practice.

A Personal Lesson in Revolutionary Overreach

Early in my career, I had what felt like a genuinely good idea — a new way to visualize summary data that I was convinced would be a significant improvement over what we'd built. I spent an entire night designing and implementing it. By morning I had a screenshot that looked impressive. I was proud of it.

The customer was not impressed. Their concern wasn't whether the idea was good. It was: how do we train our staff on this? What happens to the months of work already built around the existing interface? How does this integrate with the rest of the system?

I had optimized for what I thought was elegant and ignored the practical reality the customer was living in. The revolutionary redesign — regardless of its merits — introduced costs the project couldn't absorb at that point.

Taking an evolutionary approach afterward meant making incremental improvements to what existed, building on the foundation already in place, and responding to feedback rather than substituting my own judgment for the user's actual experience. The results were more durable, and the relationship with the customer remained intact.

The Case for Pragmatic Evolution

Evolutionary progress in software isn't about avoiding change. It's about being disciplined and honest about the pace and nature of change that a given project can sustain.

An evolutionary mindset means:

  • Building on existing foundations rather than discarding them reflexively
  • Treating each release as a learning opportunity, not just a delivery milestone
  • Prioritizing stability and maintainability alongside feature velocity
  • Recognizing that user behavior and market requirements will shift, and designing for that rather than assuming the current requirements are final

This approach tends to compound. Small improvements made consistently, over time, accumulate into systems that are significantly better than where they started — without the disruption cost that a revolutionary overhaul would have required.

The Book That Complicates This

It's worth acknowledging the counterargument directly, because it has real merit. Robert J. Kriegel and Louis Palter's If It Ain't Broke... Break It! makes a compelling case that complacency — the comfort of maintaining the status quo — is its own form of failure. The book argues that sometimes genuine progress requires the willingness to break what seems to be working.

That's not wrong. The danger of the evolutionary framing is that it can be used to rationalize avoidance — to keep patching something that needs to be rethought because change feels risky. There are moments when a system has accumulated so much technical debt, or when the underlying technology has shifted so fundamentally, that incremental improvement is no longer honest. At that point, a more significant intervention is warranted.

The distinction is between calculated disruption and reckless revolution. Calculated disruption means understanding what you're breaking, why, and what success looks like on the other side. Reckless revolution means starting over because the existing thing is frustrating, without a realistic plan for getting somewhere better.

Maintaining Business Agility Through Evolutionary Architecture

Production business applications operate in a context that pure technical reasoning tends to underestimate. The business depends on the application. The business is also changing — responding to market conditions, customer demands, and competitive pressure. A six-month development freeze while a team executes a complete re-architecture is rarely a cost the business can actually absorb.

The answer isn't to never make architectural changes. It's to structure those changes so they can happen incrementally, in parallel with ongoing operations.

This is where tools like Azure Front Door and traffic managers become genuinely useful. Rather than executing a monolith-to-microservices migration as a big-bang event, you can route a fraction of traffic to a new microservice while the existing monolithic API continues to serve the rest. The new component gets tested against real production traffic. Issues surface in a controlled way. The existing system remains available and functional.

Feature flags offer a similar capability at the application layer: develop new functionality, test it internally, gradually expose it to users as confidence grows. The rollout is controlled. The ability to roll back is preserved.

These aren't workarounds. They're mature engineering practices that reflect a clear-eyed understanding of how change actually needs to work in production environments. They let teams execute meaningful architectural evolution without forcing the business to hold its breath.

Electronic Data Systems had a phrase for this kind of forced evolution: building the plane while flying it. The EDS commercial that phrase came from captured something real — sometimes there's no option to land, redesign, and relaunch. You have to improve the system while it's running. That's not a failure condition. It's the normal state of things in production software.

When Revolution Is Actually the Answer

None of this is an argument that systems should never be replaced or that revolutionary change is always wrong. Sometimes the accumulated technical debt really is too severe. Sometimes the underlying platform has shifted so fundamentally that incremental migration isn't realistic. Sometimes a project has genuinely run its course and the right decision is to start something new.

The key is entering that decision with clear eyes: a realistic understanding of what the existing system contains, a genuine plan for what the new one will look like and how it will get there, and enough resources to actually execute. Duke Nukem Forever wasn't a failure because its developers chose to rebuild — it was a failure because they rebuilt repeatedly without a clear roadmap, without adequate staffing, and without a credible exit condition.

Revolution with a plan and adequate resources can work. Revolution as a response to frustration, without those foundations, tends to produce the same frustrations in a newer codebase.

A Useful Frame for Every Project Decision

The practical question, at any given decision point, is: what's the minimal change that moves us meaningfully forward?

Sometimes that minimal change is genuinely significant — a major refactor, a platform migration, a new architectural pattern introduced at scale. "Minimal" doesn't mean trivial; it means targeted. It means not taking on more disruption than the change actually requires.

Agile practices are designed around exactly this dynamic. Sprints create regular forcing functions for prioritization. Retrospectives surface what's working and what isn't before small problems compound into large ones. The continuous feedback loop keeps the team aligned with what users actually need rather than what developers think they should need.

The quote often attributed to Einstein — "insanity is doing the same thing over and over and expecting different results" — gets invoked to justify revolution. But the more useful reading of it might be about the same thing part: the constant pursuit of the next rewrite, expecting it to finally solve the problems that the last rewrite didn't. The evolutionary alternative is to change something, learn from the result, and change something else — building knowledge compound interest rather than spending it all on a single bet.

Conclusion

The software field has a persistent romance with fresh starts. The blank repository, the new framework, the architecture that won't have all the problems the last one had. That romance is understandable — working in complex, imperfect systems is genuinely hard — but it has a track record that deserves scrutiny.

The projects and products that have demonstrated staying power tend to share a different quality. They learned from their users. They iterated on what existed rather than discarding it at the first opportunity. They introduced significant changes deliberately, with a plan, rather than reactively. They treated stability as a feature rather than an obstacle.

Evolution isn't stagnation. It's compound progress applied with discipline. And compound progress, given enough time, tends to outperform revolution more often than the revolutionary impulse would ever want to admit.

Further Reading