DEV Community

Cover image for Why Simple is Winning Again.
Ram Bikkina
Ram Bikkina

Posted on

Why Simple is Winning Again.

If you work in backend engineering, you know the drill. For the last ten years, the answer to every scaling problem was "Microservices."

The idea was seductive. Break your big, scary application into tiny, independent pieces. Each piece does one thing well. They talk to each other over the network. If the "Payments" service crashes, the "Browse" service keeps working.
It sounded like the perfect architecture. We all wanted to be like Netflix.

But recently, the industry woke up with a massive hangover. We realized that for many of us, microservices didn't solve our problems. They just replaced them with different, harder problems.

Now, the pendulum is swinging back. Not to the bad old days, but to something smarter.

The Old Enemy: The Spaghetti Monolith

To understand why we left monoliths in the first place, we have to remember what they used to look like.

Before microservices, we built what I call "Spaghetti Monoliths." This was one giant codebase where everything was tangled together.

The code for processing orders would directly reach into the database tables for user profiles. The shipping logic was mixed in with the billing logic.

It was a nightmare.

If you changed one line of code in the "User" section, you might accidentally break the "Checkout" flow. You couldn't be sure. Deployments were scary. You had to deploy the entire massive beast at once, crossed your fingers, and hoped nothing broke.

We ran away from this mess and embraced microservices.

The Turning Point: Amazon Prime Video

The moment everyone really started questioning microservices happened in 2023. The Amazon Prime Video engineering team published a blog post that shocked everyone.

They had a specific service used for monitoring audio and video quality. It was built using a modern, distributed microservices architecture (using AWS serverless functions). It was supposed to be scalable and cutting-edge.

Instead, it was expensive and slow.

Because the service was broken into so many tiny pieces, the components spent most of their time just talking to each other across the network. They were paying a fortune for data transfer between these small services.

So, they did the unthinkable. They merged all those microservices back into a single monolithic application.

The results were staggering. They reduced their infrastructure costs by 90%.

Because everything was now in one process, there was no network lag between components. It got faster. It got cheaper. It was easier to manage.

Amazon proved that sometimes, "modern" architecture is just over-engineering.

Microservice vs Modular Monolith

The New Hero: The Modular Monolith

So, are we going back to the Spaghetti Monolith? No way.

We are moving toward the Modular Monolith.

Think of it as the best of both worlds. You still have one single codebase. You deploy it as one unit. You have one database.

But inside that code, you draw strict lines.

You create distinct modules, like "Billing," "Inventory," and "Users."

Crucially, the "Billing" module is not allowed to directly touch the "Inventory" module's code or data tables. If "Billing" needs information from "Inventory," it must ask nicely through a clean, internal code interface.

It’s like having microservices, but instead of talking over a slow, expensive network connection, they talk via super-fast, in-memory function calls.

What It Looks Like in Code

Here is a very simplified example using Python (FastAPI).

In a spaghetti monolith, everything would be in one 5,000-line file.

In a modular monolith, your main file just acts as glue holding distinct, organized sections together.

You would have a folder structure like this:

/src
  /modules
    /users (contains router.py, service.py, models.py for users only)
    /payments (contains payment logic only)
    /products (contains product logic only)
  main.py

Enter fullscreen mode Exit fullscreen mode

Here is how simple the main.py looks. It doesn't know how payments work; it just knows where the payment module lives.

from fastapi import FastAPI

# We import the routers from our distinct, separated modules.
# These modules do not directly touch each other's internal code.
from src.modules.users import user_router
from src.modules.payments import payment_router
from src.modules.products import product_router

app = FastAPI()

# The main app just mounts these pre-built modules.
# This is one single deployable application.

app.include_router(user_router.router, prefix="/users", tags=["Users"])
app.include_router(payment_router.router, prefix="/payments", tags=["Payments"])
app.include_router(product_router.router, prefix="/products", tags=["Products"])

@app.get("/")
async def root():
    return {"message": "The modular monolith is running smoothly."}

Enter fullscreen mode Exit fullscreen mode

Why does this work?

If you need to debug a payment issue, you know exactly which folder to look in. If the "Payments" module gets too big in two years, it is already organized with clean boundaries. You can easily "snip" it out and turn just that one part into a microservice later.

Pros and Cons Quick View

Feature Microservices Modular Monolith
Complexity High. Lots of moving parts. Medium. Just needs discipline.
Performance Slower due to network calls. Very fast internal calls.
Cost Higher infrastructure overhead. Lower. You pay for compute, not chatter.
Debugging Hard. Tracing requests across services is painful. Easy. It's all in one place.
Team Scaling Good for 500+ developers. Good for small to mid-size teams.

When To Choose What

The industry has realized we were using microservices to solve organizational problems, not technical ones.

Choose a Modular Monolith if:

  • You are a startup building an MVP. Speed is everything.
  • You have a small to medium-sized engineering team (under 50-100 people).
  • Your domain is not yet fully defined. Monoliths are easier to refactor than distributed systems.

Choose Microservices if:

  • You are Google, Netflix, or Uber.
  • You have 50 distinct teams that keep stepping on each other's toes in the same codebase.
  • You have one specific feature (like video transcoding) that needs vastly different hardware resources than the rest of the app.

The Takeaway

Don't use microservices just because it's trendy. Complexity is the enemy of speed.

Start with a clean, well-organized modular monolith. It will serve you well for a long time. If you eventually hit massive scale, you’ll be ready to split it up. But don't pay the microservice tax until you actually need to.

Part of the journey is the end… until the next new chapter :::: Tathāstu.


I’m Ram Bikkina, and I turn complex backend trends into simple, layman-friendly guides. Stalk my profile for more articles.

Top comments (0)