Microservices
Decomposing a system into small, independently deployable services with clear ownership boundaries.
Overview
Microservices is an architectural style where a system is composed of small, independently deployable services, each owning its own data and business capability. Services communicate over the network (HTTP, gRPC, or messaging). The pattern enables independent scaling, deployment, and technology choices per service, at the cost of significant operational complexity.
Origin
The term was coined at a 2011 software architecture workshop. James Lewis and Martin Fowler's 2014 article "Microservices" and Sam Newman's book "Building Microservices" (2015) established the pattern and its trade-offs. Netflix, Amazon, and Uber's public engineering blogs influenced widespread adoption.
Examples
Service communication via HTTP with resilience
class UserServiceClient {
constructor({ baseUrl, timeout = 5000, retries = 3 }) {
this.baseUrl = baseUrl
this.timeout = timeout
this.retries = retries
}
async getUser(id) {
for (let attempt = 1; attempt <= this.retries; attempt++) {
try {
const res = await fetch(`${this.baseUrl}/users/${id}`, {
signal: AbortSignal.timeout(this.timeout),
headers: { 'X-Trace-Id': context.traceId }
})
if (!res.ok) throw new ServiceError(res.status, await res.text())
return res.json()
} catch (err) {
if (attempt === this.retries || err instanceof ServiceError) throw err
await sleep(200 * attempt) // exponential backoff
}
}
}
}Use Cases
- 01Large teams where independent deployment per service enables parallel delivery without coordination overhead
- 02Services with very different scaling requirements (one needs 100 instances; another needs 2)
- 03Polyglot environments where different services benefit from different languages or databases
- 04Critical components that must be isolated so failures do not take down the whole system
When Not to Use
- //Small teams: the operational overhead (service discovery, distributed tracing, deployment pipelines per service) consumes engineering time that should go toward product
- //Early-stage products where the domain is not yet understood, premature decomposition creates the wrong services
- //When the latency cost of network calls between services is unacceptable for the workload
Technical Notes
- Service boundaries should follow domain boundaries (bounded contexts), not technical layers
- Data ownership is the hardest rule: each service owns its data exclusively. Cross-service joins require API calls or event-driven denormalisation
- Distributed transactions across services require Saga (see below), two-phase commit across services is fragile and should be avoided
- Observability (structured logs, distributed tracing, metrics) is not optional in microservices, you cannot debug what you cannot observe
More in Architecture