The Pendulum of Overcorrection

The Pendulum of Overcorrection

The Pendulum of Overcorrection

Your no-BS weekly brief on software engineering.
Join 100,000+ developers

Never Again.

Waterfall slowed us down, so we sprinted to Agile. Full-page reloads frustrated us, so we pushed everything to the client. Microservices promised scalability, so we broke apart monoliths—sometimes for good reasons, other times just because "monolith" became a dirty word.

In tech, we don’t just solve problems—we react to them. And in that reaction, we often go too far. Some shifts are necessary evolutions, but others? They’re just overcorrections.

Overcorrection is easy. Who hasn't thought that a complete rewrite of an app would be easier than a tedious refactoring?

The hardest part isn't change—it’s balance.


The Overcorrection Reflex

We don’t just course-correct—we often overcorrect. And it’s not just a tech thing—it’s human nature, shaping decisions both big and small.

I once had dinner with a Chief Security Officer for my employer, a deeply reflective guy who told me something I’ve never forgotten—even decades later.

Growing up, when we went out to eat, my parents told me to order from the menu right-to-left. That is... look at the price first, then pick the cheapest thing I could tolerate. I told myself, when I grow up, I will never do that again.

Then, with a grin, he ordered a 25-year-old scotch.

He wasn’t just making a statement—he was reacting against his past. And that’s exactly what we do in tech.

We don’t just fix problems. We routinely reject the entire system that caused them. Instead of refining, we overcompensate.

Waterfall wasn’t necessarily the enemy—slow iteration was. Monoliths weren’t the problem—poor modularity was. But rather than improving, we swing to extremes.

And the result? Some shifts were necessary evolutions, while others created new constraints and inefficiencies. You don't necessarily know which is which until you take one step forward and then sometimes, two steps back.


Living through the Cycle

Web development has been a cycle of solving one problem while introducing another. Let’s look at key moments where we traded one pain point for another—and how we’re finding balance today.

Configuration you say? 🤨

Before frameworks like Ruby on Rails, just setting up a project was littered with configuration steps to get to a running application.

This prompted the creation of Ruby on Rails. It emerged to cut through the tedious configuration, favoring convention over configuration to make web development faster and more intuitive.

Full-page loads -- how 1995 😒

For startups, this dominated the scene from the mid-aughts to the early 2010s. By this time, frustration with full-page reloads led to an industry-wide push toward client-heavy JavaScript frameworks—Backbone.js, Vue.js, React—each offloading more work to the client.

The goal was fast, interactive applications, but the tradeoff was complexity, performance struggles, and ever-growing JavaScript bundles.

Back in the SSR ♫

Now, we’re adjusting again—not as an overcorrection, but as an evolution. SSR is making a comeback, refined by edge computing, frameworks like Astro and Next.js, and progressive hydration.

Rails 8 with Hotwire and the growing popularity of technologies like HTMX, reflect this shift—blending server-driven updates with seamless client-side interactions.

This is how progress should work—not by always trashing the old way, but by learning from it.

People are now asking the question — can we get the benefit of a client-heavy Javascript framework without the complexity that it typically entails? For a lot of folks, the answer is yes.


The Workaround That Became the Problem

Not every shift involves a groundbreaking change in technology or philosophy. Sometimes, it's the choices we make in our architecture that are informed by our experiences or perceived constraints.

I once leveraged Elasticsearch for a project—not because we truly needed what it offered, but because the DBA who controlled every database change was frustrating to work with. I'd spend sprints working through a new feature only to have to rework it to accommodate his changes to the data model. Enough, I said — I'll use whatever he wanted and work with Elasticsearch to get the data I cared about.

It worked—but it also introduced more infrastructure, more moving parts, and another layer of complexity.

Looking back, my workaround didn’t eliminate the real issue—it just shifted the burden elsewhere. And in tech, workarounds tend to become architecture.

The same thing happens at the architecture level. Microservices aren’t wrong, but they’re sometimes adopted as a workaround for team structure rather than a real technical need.

Before we embrace change, we need to ask: Am I solving the real problem, or just finding a new way to avoid it?


So How Do I Tell the Difference?

Not every shift in tech is an overcorrection—some are real improvements. The challenge is knowing when a change is necessary and when it's just reactionary.

Here are some key questions to ask before embracing the next big shift:

1. Is This Solving the Root Problem or Just the Symptoms?

  • Overcorrection: Reacts to pain points without addressing the underlying cause
  • Evolution: Fixes the core issue while keeping what already works.
  • Example: Moving from monoliths to microservices won’t fix bad code organization—it just distributes it across services.

Am I fixing the real issue, or just responding to frustration?

2. Is It a Complete Rejection or an Iteration?

  • Overcorrection: Throws out the entire previous model instead of refining it.
  • Evolution: Takes what worked and builds on it.
  • Example: Rails 8 doesn’t reject JavaScript—it balances it with tools like Stimulus.

Am I improving what came before, or just discarding it?

3. Does This Change Add More Complexity Than It Removes?

  • Overcorrection: Creates more problems than it solves, often through added complexity.
  • Evolution: Simplifies or enhances without unnecessary baggage.
  • Example: Early SPAs introduced interactivity but also massive bundles, hydration issues, and maintainability problems.

Does this make my system easier to maintain, or just different?

4. Are We Adopting This Because It’s Better—Or Because It’s Trendy?

  • Overcorrection: Often driven by hype or fear of missing out.
  • Evolution: Comes from careful evaluation of tradeoffs.
  • Example: Many teams migrated to microservices because Netflix and Google did, not because they actually needed them.

Would I still make this change if nobody else was?


Knowing When to Refine—And When to Revolt

The best engineers—and the best teams—don’t just chase trends. They refine ideas. Sometimes, progress demands a revolution. Other times, it means evolving what came before. The key is knowing which moment you’re in.

The best ideas aren’t blindly accepted—they’re tested, debated, and refined. Clinging to an outdated approach is just as limiting as jumping on trends for the sake of change.

True progress isn’t about following the latest shift or resisting it—it’s about knowing when to rethink, when to refine, and when to stay the course.