Monolith vs Microservices¶
1. Decision¶
Choose a Monolithic Architecture for early-stage products, small teams (<20 engineers), and unified domains requiring rapid feature iteration and single-database ACID transactions; choose Microservices for large engineering organizations (>50 engineers across independent domain teams), polyglot technology requirements, and systems requiring independent deployment autonomy and horizontal scale per domain.
2. 30-Second Answer¶
A Monolithic Architecture packages all domain capabilities into a single unified code repository, deployed as a single executable artifact backed by a primary database. It delivers rapid developer velocity, simple single-repo debugging, easy local testing, zero network serialization latency between modules, and straightforward ACID database transactions. However, it scales as a single unit, risks single-module memory leak crashes, and creates deployment bottlenecks as engineering teams grow. Microservices split domain capabilities into independent, autonomous, loosely coupled services communicating over the network (gRPC, REST, Kafka). Each microservice owns its data store, enabling team autonomy, independent scaling, and polyglot flexibility, but introduces distributed systems complexity (network latency, eventual consistency, distributed tracing, and complex CI/CD ops).
3. Decision Matrix¶
| Option | Best For | Avoid When | Latency | Scalability | Consistency | Operational Complexity |
|---|---|---|---|---|---|---|
| Monolithic Architecture | Startups, small teams (<20 devs), MVP validation, simple CRUD apps, complex multi-domain ACID transactions | Large cross-functional engineering orgs (100+ devs), domains requiring radical independent scaling | Sub-millisecond (In-process memory function calls between modules) | Scale-Up; Scale-Out identical monolith copies | Immediate ACID (Single relational DB) | Low |
| Microservices Architecture | Large engineering organizations (50+ devs), domain-driven team autonomy, independent deployment cycles | Small teams (<10 devs), early-stage products where domain boundaries are rapidly shifting | Low to Medium (Inter-service network hops: gRPC/REST) | Extremely High (Scale individual high-traffic services independently) | Eventual Consistency (Saga pattern across services) | High (Kubernetes, Service Mesh, Distributed Tracing, CI/CD) |
4. Selection Rules¶
| Requirement | Best Choice | Rationale / Example |
|---|---|---|
| Early-Stage MVP Startup (<10 Engineers) | Monolithic Architecture | Maximum developer velocity; focus on product-market fit without distributed ops overhead |
| Autonomous Deployment for 20 Engineering Teams | Microservices | Teams deploy their domain service independently 10x/day without blocking release queues |
| Independent Compute Scaling per Domain | Microservices | Scale high-CPU Video Encoding service horizontally without scaling low-traffic Account service |
| Strict ACID Multi-Domain Financial Transactions | Monolithic Architecture | Execute multi-table SQL transactions natively inside single relational database |
| Modular Monolith Transition Strategy | Modular Monolith | Enforce strict package boundaries in single repo before splitting into microservices |
5. Tradeoffs¶
- In-Process Call Speed vs Inter-Service Network Overhead
- Gain (Monolith): Function calls execute in nanoseconds inside local process memory.
- Lose (Monolith): Single module memory leak or infinite loop can crash the entire application process.
- ACID Transaction Simplicity vs Distributed Saga Eventual Consistency
- Gain (Monolith): Single SQL transaction commits updates across all domain tables atomically.
- Lose (Monolith): Bounded by single primary database write capacity limits.
- Single Repository Velocity vs Autonomous Team Deployments
- Gain (Microservices): Teams deploy microservices independently without coordinating global releases.
- Lose (Microservices): Managing 50+ CI/CD pipelines, API contracts, and version deprecations.
- Isolated Domain Failure vs Cascading System Outages
- Gain (Microservices): Recommendation service crash does not block core Payment service transactions.
- Lose (Microservices): Latency spikes in downstream services cause thread pool exhaustion upstream.
- Operational Infrastructure Cost
- Gain (Monolith): Run on a single EC2 instance / container with a single PostgreSQL database.
- Lose (Microservices): High infrastructure overhead running Kubernetes clusters, service meshes, and observability stacks.
6. Interview Counter Questions¶
- What is Martin Fowler's "Monolith First" strategy and why is it recommended for new projects?
- What is a Modular Monolith and how does it prevent the "Distributed Monolith" anti-pattern?
- How do you identify domain boundaries when splitting a monolith using Domain-Driven Design (DDD Bounded Contexts)?
- What is a Distributed Monolith and why is it the worst possible architecture?
- How do you migrate a monolithic application to microservices using the Strangler Fig Pattern?
- How does Database-per-Service rule impact data relationships previously managed by SQL foreign keys?
- What is Conway's Law and how does it dictate organizational microservice architecture?
- How do you maintain end-to-end Observability across 100 microservices (OpenTelemetry, Jaeger)?
- When is splitting a monolith into microservices an architectural mistake?
- How do API Gateways and Service Meshes support microservice management?
7. Gold Standard Answers¶
- Monolith First: Start with a well-structured monolith when domain boundaries are unclear. Only split into microservices when team size grows or specific scaling bottlenecks emerge, avoiding premature distributed complexity.
- A Modular Monolith keeps code in 1 repository, but strictly enforces module boundary interfaces (no cross-module private calls or DB access). It avoids network latency while preserving clean architectural boundaries.
- Use Domain-Driven Design (DDD) to map Bounded Contexts around business capabilities (e.g. Orders, Billing, Shipping). Entangling data structures belong in the same context; clear events mark context boundaries.
- A Distributed Monolith has microservices deployed separately, but tightly coupled via synchronous network calls and shared databases. It combines the slow performance of distributed networks with the release coupling of a monolith!
- Strangler Fig Pattern: Intercept traffic at the API Gateway layer. Gradually implement new microservices to replace monolithic routes piece-by-piece until the legacy monolith shrinks to zero and is decommissioned.
- Database-per-Service forbids microservices from accessing another service's DB directly. Replace SQL foreign keys with asynchronous events (Kafka CDC) or synchronous API lookups, managing consistency via Sagas.
- Conway's Law: Organizations design systems that mirror their communication structures. 20 independent engineering teams naturally produce ~20 autonomous microservices.
- Inject W3C
traceparentheaders across all HTTP/gRPC requests and Kafka events. Use OpenTelemetry SDKs to export spans to Jaeger/Zipkin for unified distributed tracing trees. - Splitting is a mistake when: team size is \(<15\) developers, domain boundaries are rapidly shifting, the team lacks Kubernetes/DevOps expertise, or the performance bottleneck is simply a missing SQL index.
- API Gateway handles North-South edge traffic (Auth, Rate Limiting, Route Forwarding). Service Mesh (Envoy/Istio) handles East-West internal traffic (mTLS encryption, retries, circuit breaking, distributed tracing).
8. Common Mistakes¶
- Migrating to microservices with a shared centralized database (violates Database-per-Service, creating a Distributed Monolith).
- Splitting a monolith into microservices with a team of 5 developers, spending 80% of time on DevOps and K8s configuration.
- Building microservices that communicate via deep synchronous call chains (A \(\rightarrow\) B \(\rightarrow\) C \(\rightarrow\) D), guaranteeing high failure rates.
- Splitting services by technical layers (UI service, Business logic service, DB service) instead of business domain capabilities.
- Failing to implement distributed tracing before launching 20+ microservices in production.
9. Keywords¶
Monolith, Microservices, Modular Monolith, Distributed Monolith, Monolith First, Strangler Fig Pattern, Domain-Driven Design (DDD), Bounded Context, Database-per-Service, Conway's Law, OpenTelemetry, Distributed Tracing, Service Mesh.
10. Cheat Sheet¶
- Core Rule: Start with a Monolith First! Migrate to Microservices ONLY when team size (>50 devs) or independent scaling demands it.
- Microservice Golden Rule: Database-per-Service! Microservices MUST NEVER query another service's database directly.
- Anti-Pattern: Avoid the Distributed Monolith (Microservices sharing 1 database or coupled synchronously).
- Migration Strategy: Use the Strangler Fig Pattern to replace monolithic routes incrementally via API Gateway routing.
- Architecture by Team: Monolith = 1-15 devs; Modular Monolith = 15-40 devs; Microservices = 50+ devs organized by DDD Bounded Contexts.
- Communication: North-South = API Gateway; East-West = Service Mesh (gRPC / mTLS) + Async Event Streams (Kafka).