Monoliths, Microservices & Service Discovery
Intermediate · 18 min read · High-Level Design, Services & Communication
When to split, service boundaries, discovery, API gateways and service meshes.
How you split a system into deployable units shapes almost everything else: how teams work, how failures spread, how data stays consistent, and how fast you can ship.
Three architectures
One deployable application containing all features, usually with one database.
Drawing service boundaries
Bad boundaries are worse than no boundaries — a distributed monolith where every change touches five services and they must deploy together.
Database per service
Each service owns its schema; other services access that data only through its API or events.
Service discovery
In dynamic environments, instances come and go with auto-scaling and deploys. Callers need current addresses.
API gateway and backend-for-frontend
An API gateway is the single entry point for external clients:
Service mesh
As service counts grow, every service needs retries, timeouts, mTLS, metrics and traffic shifting. A service mesh (Istio, Linkerd, Consul Connect) moves this into infrastructure:
Communication styles between services
A useful rule: synchronous for queries on the critical path, asynchronous for propagating state changes. Avoid long synchronous chains (A → B → C → D) — they multiply latency and failure probability. See Availability & Fault Tolerance.
Migrating from a monolith: the strangler fig
Don't rewrite from scratch. Put a routing layer in front of the monolith, extract one capability at a time into a service, route its traffic to the new service, and repeat until the monolith shrinks away (or what's left is fine as it is).
Interview questions
- When would you choose a monolith over microservices?
- Why shouldn't two services share a database?
- What does a service mesh give you, and when is it not worth it?
Practice
Write your answer before opening the suggested one. Anything you mark "Partly" or "Missed it" comes back in your review deck.
Further reading
Key takeaways
- Monoliths are simplest; modular monoliths add strong internal boundaries; microservices add independent deployment and scaling at a high operational cost.
- Draw boundaries around business capabilities, and give each service ownership of its data.
- Use service discovery (registry or platform DNS), an API gateway (or BFF) at the edge, and a service mesh only when the service count justifies it.
- Prefer synchronous calls for critical-path queries and events for state propagation; avoid long call chains.
- Migrate incrementally with the strangler fig pattern.
Previous: Message Queues & Event Streaming · Next: Event-Driven Architecture, CQRS & Event Sourcing