The microservices hype cycle
Every startup founder has heard the pitch: break your monolith into microservices and watch your engineering velocity soar. Netflix did it. Amazon did it. So should you, right?
Not necessarily. Microservices solve real problems — but only if you actually have those problems. For most early-stage companies, a well-structured monolith is faster to build, easier to debug, and cheaper to run.
The real cost of going distributed
Microservices aren't free. Each service you extract brings operational overhead that compounds fast:
Observability: Distributed tracing, log aggregation, and metrics correlation across services require tools like Jaeger, Datadog, or Grafana — plus someone who knows how to use them.
Networking: Service discovery, load balancing, retry logic, circuit breakers, and timeout configuration. One misconfigured timeout can cascade across your entire system.
Deployment: Each service needs its own CI/CD pipeline, container registry, health checks, and rollback strategy. That's not one pipeline — it's dozens.
Data consistency: Distributed transactions are hard. Eventual consistency is harder to reason about. Saga patterns add complexity most teams underestimate.
When a monolith wins
A modular monolith — one codebase with clear internal boundaries — gives you most of the organizational benefits of microservices without the operational tax. You get:
Single deployment pipeline
Simple local development
Straightforward debugging with stack traces that don't span network boundaries
ACID transactions across your entire domain
If your team is under 20 engineers and you're not handling wildly different scaling requirements across features, a monolith is almost certainly the right call.
When to actually split
Microservices make sense when you have genuine forcing functions:
Team boundaries: Multiple teams stepping on each other's code, unable to deploy independently.
Independent scaling: One feature needs 50x the compute of everything else.
Technology diversity: A specific problem domain genuinely requires a different language or runtime.
Deployment independence: You need to ship one feature without risking the stability of unrelated features.
The pragmatic path
Start with a modular monolith. Enforce clear module boundaries. Use well-defined internal interfaces. When a real forcing function appears — not a hypothetical one — extract that specific module into a service. This is the strangler fig pattern, and it works because you're making decisions based on evidence, not architecture astronautics.
The best architecture is the one your team can actually operate. Don't build Netflix infrastructure for a product that hasn't found product-market fit.
Follow me to keep in touch
Where I share my creative journey, design experiments, and industry thoughts.




