Microservices

12 min read · Updated 2026-04-25

Amazon Prime Video moved part of their video monitoring system back to a monolith in 2023 to reduce latency and operational complexity. Segment did the same with their event pipeline. Even Istio — the tool literally designed for managing microservices — consolidated several control-plane services to reduce operational burden.

These weren’t failures of microservices. They were signs of engineering maturity. After a decade of adoption, the industry has learned when microservices make sense and when they don’t.

Anatomy of a Microservice

A microservice is a small, autonomous service that does one thing well. “Small” is about scope, not lines of code. The defining characteristics:

Business-capability aligned
Each service maps to a specific business capability or domain. Auth service handles auth. Payments service handles payments. Not "database service" or "UI service."
Owns its data
Each service has its own database and is the source of truth for its domain. No other service reaches into another's data store.
Independent deployment
Teams deploy without coordinating with other teams. This autonomy is what unlocks fast iteration.
Tech independence
Different services can use different languages, frameworks, databases. Recommendation service in Python; payments in Java; UI in TypeScript.

The Benefits

Promised
What microservices give you
Independent scaling, team autonomy, fault isolation, technology flexibility, fine-grained deployment cadence.
Cost
What you take on in return
Distributed systems complexity (latency, partial failure, eventual consistency), operational overhead (dozens of pipelines, observability), debugging archaeology, data consistency challenges.

Independent scaling lets you allocate resources where you need them — scale video processing during peak hours while keeping baseline capacity for user profiles.

Team autonomy lets organizations move faster by reducing coordination cost and letting teams pick their own stacks and deployment cadence.

Fault isolation means a failure in one service doesn’t necessarily take down the whole system. The recommendation engine can struggle while users still browse, search, and check out.

The Real Costs

The complexity is what teams routinely underestimate.

The common pain points:

Anti-patterns to Avoid

Step 01
Shared database
Two services using one DB lose the independence that makes microservices valuable. Schema changes need coordination; you're coupled at the data layer.
Step 02
Distributed monolith
Services so tightly coupled they must deploy together. All complexity, no benefit. If changing one service requires changes in five others, this is what you have.
Step 03
Premature decomposition
Going microservices on day one usually produces wrong service boundaries. Better: start with a well-structured monolith, extract services as domain boundaries become clear.

Communication: The Nervous System

In a monolith, method calls are cheap and reliable. In microservices, communication becomes a primary design concern. How services talk to each other determines latency, reliability, and failure modes.

Synchronous
REST, gRPC, GraphQL
Immediate feedback, simple to debug. Costs: tight coupling, latency propagation, cascading failures along call chains.
Asynchronous
Events, queues, streams
Services decoupled in time. Resilient to downstream failures. Costs: eventual consistency, harder debugging, operational complexity of message infrastructure.

Most production systems mix patterns. We covered communication patterns in detail in the previous section.

Boundary Problem

The single most consequential decision in microservices architecture is where to put the boundaries. Get it right and you unlock fast independent teams. Get it wrong and you’ve built a distributed big ball of mud that’s harder to manage than the monolith you started with.

DDD as your guide

DDD’s bounded contexts map naturally onto service boundaries. A bounded context is a business area where specific terms, rules, and models apply consistently — exactly the right unit of decomposition.

In an e-commerce system, “Customer” means different things in different contexts:

Each becomes its own service with its own data model.

Practical heuristics

Step 01
Start with business capabilities
Not technical components. Think "Order Management Service," not "Database Service."
Step 02
Watch data ownership
If you find yourself saying "Order service needs to read from User database," you've found a boundary problem.
Step 03
Respect Conway's Law
Team boundaries shape service boundaries. Fighting Conway's Law usually fails.
Step 04
Mind transactional boundaries
Operations needing strong consistency tend to belong in the same service. If you frequently need distributed transactions, you might be slicing wrong.

Migrating: The Strangler Fig

Most organizations don’t start with microservices — they evolve toward them. The Strangler Fig pattern (named for the vine that gradually overtakes its host tree) is the systematic approach:

Step 01
Identify a bounded context
Pick one inside the monolith that can be cleanly extracted.
Step 02
Build the new service
Stand it up alongside the monolith. Wire it to the rest of the system.
Step 03
Route new functionality
New features go to the new service. Existing functionality stays in the monolith.
Step 04
Migrate existing functionality
Move existing capabilities from monolith to service incrementally.
Step 05
Remove the old code
When everything has migrated, delete the now-dead monolith code.
Step 06
Repeat
Pick the next bounded context and start over.

This reduces risk and lets you adjust as you go. Read-only services (search, recommendations) make easier first targets than transactional ones.

The Tech Stack That Made This Practical

Containers + Kubernetes
Service discovery, load balancing, health checks, rolling deploys. Declarative state model means you describe what you want, K8s maintains it.
Service mesh
Istio, Linkerd, Consul Connect. Retries, circuit breaking, mTLS, observability — at infrastructure level, not in app code.
Managed cloud services
Managed K8s, databases, message queues, serverless. Removed the operational floor that used to gate microservices adoption.
IaC + GitOps
Terraform, ArgoCD. Consistent, reproducible deployments across environments. Manual infrastructure management doesn't scale.
Distributed tracing
Jaeger, Zipkin, OpenTelemetry. The "three pillars" — metrics, logs, traces — become essential.
Independent CI/CD
Each service builds, tests, deploys independently. Canary releases and feature flags reduce deploy risk.

Testing Distributed Systems

Microservices break the classic test pyramid in interesting ways.

The other shift: testing in production stops being a slogan and becomes necessary. Synthetic monitoring, canary deploys, and feature flags let you validate behavior under real conditions. The philosophy is optimizing MTTR over MTBF — accept that some failures will happen and design for fast recovery.

The Pendulum Swings Back

After a decade, the most thoughtful teams have moved past the binary “monolith vs. microservices” question:

Modular monolith
Module-level discipline inside one deployable. Shopify, GitHub, Basecamp run massive systems on this. Often the right answer.
Macroservices
Bigger than microservices, smaller than monoliths. One "User Service" instead of three (auth, profiles, settings).
Serverless / FaaS
Many of the microservices benefits — independent deploy, autoscale, pay-per-use — without the container/orchestration overhead. Great for event-driven and infrequent workloads.
Micro-frontends
Microservices philosophy applied to UI. Module Federation, Single-SPA. Independent UI teams that match backend service ownership.

The best teams have stopped arguing monolith vs. microservices and build systems that mix patterns based on what each part of the product needs. Payment processing might be tightly integrated for predictable performance. Recommendations might be loosely coupled microservices for experimental flexibility. That’s not a compromise — that’s engineering judgment.

Recap