Machine Learning pathway increased my salary by 40%
Microservices Architecture for the Enterprise
Bounded contexts, domain-driven design, and the patterns (API gateway, service mesh, saga, CQRS) that make microservices work at enterprise scale — and the organisational prerequisites that decide success.
Overview
Microservices architecture structures an application as a set of small, independent services, each owned by a team, deployed and scaled independently, and communicating via lightweight protocols. Done well, it unlocks agility and scale that monoliths cannot. Done poorly, it produces a distributed monolith — all the complexity of microservices with none of the benefits.
The decision to adopt microservices is not primarily technical; it is organisational. Microservices succeed when teams are organised around domains and given the autonomy to ship independently; they fail when imposed on teams organised by technology layer with centralised release coordination. Conway's Law is not optional — it is the strongest predictor of microservices outcomes.
This page covers the principles, the domain-driven decomposition that defines boundaries, the enterprise patterns (API gateway, service mesh, saga, CQRS, event sourcing), the trade-offs, and the organisational prerequisites that decide whether microservices deliver their promise.
What Microservices Are — and Are Not
The defining property of a microservice is independence: it can be deployed, scaled, and failed without coordinating with other services. Everything else — size, technology, protocol — is secondary. A 'microservice' that cannot deploy without coordinating with three others is not a microservice; it is a distributed component.
Microservices are not 'small services'. A service that does one thing well but shares a database with five other services is a tightly coupled distributed monolith. The independence must extend to data: each service owns its data and exposes it only through its API. Shared databases are the most common silent killer of microservice architectures.
The decision is a trade, not an upgrade. Microservices add operational complexity (distributed systems concerns: network failure, partial failure, eventual consistency, observability) in exchange for agility and scale. An enterprise that cannot absorb the operational complexity should not make the trade — a well-structured modular monolith is often the better answer.
If a service cannot be deployed, scaled, and failed independently of others, it is not a microservice regardless of its size. The test is independence, not lines of code.
Domain-Driven Design and Bounded Contexts
The right way to decompose into microservices is by business domain, using Domain-Driven Design (DDD). DDD's bounded context — a boundary within which a domain model is consistent — is the natural unit of a microservice. Each bounded context has its own ubiquitous language, its own model, and its own data.
Decomposing by domain (order management, inventory, billing) rather than by technical layer (UI, business logic, data) produces services that align with business capabilities and can evolve independently. Decomposing by layer produces 'services' that are coupled to every other layer and cannot change independently — the distributed monolith.
Getting bounded contexts right is the single highest-leverage decision in a microservices architecture. Boundaries that cut across domain semantics force every change to coordinate across services; boundaries that align with domain semantics let services evolve independently. This is why EA's capability map is such a powerful input to microservice decomposition.
Decomposition by Domain vs by Layer
| Approach | Boundary Basis | Coupling | Outcome |
|---|---|---|---|
| By domain (DDD) | Business capability / bounded context | Low — independent evolution | True microservices |
| By layer | Technical responsibility | High — every change crosses services | Distributed monolith |
| By entity | One service per entity | High — entities reference each other | Chatty, coupled services |
| By use case | One service per use case | Medium — use cases overlap | Duplication and drift |
Enterprise Microservices Patterns
Several patterns recur in enterprise microservices architectures. The API gateway provides a single entry point for clients, handling routing, authentication, rate-limiting, and sometimes aggregation. The service mesh handles service-to-service communication, observability, and policy (mTLS, retries, circuit breaking) without application code changes.
For cross-service transactions, the saga pattern coordinates a sequence of local transactions with compensating actions on failure — because distributed transactions (two-phase commit) do not scale. For read-heavy services with complex queries, CQRS (Command Query Responsibility Segregation) separates the write model from read models, often materialised from events.
Event sourcing — persisting state as a sequence of immutable events — pairs naturally with CQRS and provides an audit log and the ability to rebuild state. These patterns are powerful but each adds complexity; the architect applies them where the problem justifies them, not universally. A system where every service uses event sourcing and CQRS is over-engineered; one where none are used may be under-engineered.
Core Enterprise Microservices Patterns
| Pattern | Solves | Trade-off |
|---|---|---|
| API Gateway | Client entry, cross-cutting concerns | Single point / bottleneck if mismanaged |
| Service Mesh | Service-to-service comms, policy, observability | Operational complexity |
| Saga | Distributed transactions across services | Compensation logic complexity |
| CQRS | Complex reads vs writes | Read model synchronisation |
| Event Sourcing | Audit log, state rebuild | Event schema evolution complexity |
| Database per Service | Data ownership independence | Cross-service queries harder |
Data Ownership and the Shared-Database Trap
The most common and most damaging anti-pattern in microservices is the shared database. When multiple services read and write the same database, they are coupled at the data layer: a schema change by one breaks others, and the database becomes a monolith that the service decomposition only pretends to split.
The principle is database-per-service: each service owns its data and exposes it only through its API. Other services that need the data call the API or consume events. This enforces the bounded context at the data layer and is what makes service independence real.
The objection is performance and query convenience — cross-service joins are impossible without a shared database. The answer is CQRS and materialised views: replicate the needed data into read models via events, accepting eventual consistency. This is more work, but it preserves the independence that is the entire point of microservices.
Operational Complexity and Observability
Microservices move complexity from the application to the operational layer. A single failed request may traverse five services; finding which one failed requires distributed tracing, not log grep. Observability — metrics, logs, and especially distributed traces — is not optional in microservices; it is the precondition for operating them.
Resilience patterns must be designed in: timeouts, retries with backoff, circuit breakers, and bulkheads prevent a single failing service from cascading. Without these, a microservices architecture is brittle in a way a monolith is not — partial failures propagate where a monolith fails atomically.
The platform investment required to operate microservices (service mesh, observability, automated deployment, contract testing) is substantial. An enterprise that underinvests in the platform gets the complexity of microservices without the tooling to manage it — the worst of both worlds. This is why platform engineering and microservices adoption are inseparable.
Conway's Law and Team Topologies
Conway's Law — 'any organisation that designs a system will produce a design whose structure copies the organisation's communication structure' — is the strongest predictor of microservices outcomes. A team structure organised by technology layer (a UI team, a back-end team, a DBA team) will produce a layered architecture regardless of intent; a structure organised by domain will produce domain-aligned services.
The implication is that microservices adoption is an organisational change as much as a technical one. Team Topologies (stream-aligned, platform, enabling, and complicated-subsystem teams) provides a vocabulary for organising teams to produce the architecture you want. Adopting microservices without reorganising teams produces a distributed monolith operated by a layered organisation.
The healthy pattern is to design team boundaries and service boundaries together, so each service has a team that owns it end-to-end. A service owned by multiple teams is owned by no one; a team owning multiple services is fine if each is independently deployable, but watch for cognitive overload.
Trending Facts & 2026 Outlook
Service mesh adoption continues to grow, but many enterprises adopt managed meshes to avoid the operational burden of self-operating one.
There is a notable counter-trend toward modular monoliths for small-to-medium systems, recognising that microservices' operational tax is not always justified.
Platform engineering and internal developer platforms have become inseparable from microservices adoption, providing the paved road (deployment, observability, service mesh) that makes microservices operable.
Event-driven microservices and event sourcing are expanding in regulated industries where immutable audit logs are valuable.
AI is being layered onto microservices architectures as a shared platform capability called via APIs, preserving the independence and governance of individual services.
Best Practices
Decompose by Domain
Use DDD bounded contexts to define service boundaries aligned to business capabilities. Never decompose by technical layer.
Enforce Database-per-Service
Each service owns its data and exposes it via API. Shared databases create a distributed monolith regardless of service count.
Invest in the Platform First
Observability, deployment automation, service mesh, and contract testing must precede widespread microservices adoption. The platform is a precondition, not an afterthought.
Design Resilience In
Timeouts, retries with backoff, circuit breakers, and bulkheads prevent cascade failures. A microservices architecture without these is brittle.
Apply Patterns Where Justified
Saga, CQRS, and event sourcing are powerful but complex. Use them where the problem justifies, not universally.
Align Teams and Services
Design team and service boundaries together. A service owned by one team end-to-end, aligned to a domain, is the unit that delivers microservices' promise.
Key Takeaways
- The defining property of a microservice is independence — deploy, scale, and fail separately — not size.
- Decompose by business domain using DDD bounded contexts, aligned to the EA capability map, never by technical layer.
- Database-per-service is non-negotiable; shared databases create the distributed monolith regardless of service count.
- Enterprise patterns — API gateway, service mesh, saga, CQRS, event sourcing — are applied where justified, not universally.
- Observability (especially distributed tracing) and resilience patterns are preconditions, not add-ons, for operating microservices.
- Conway's Law decides outcomes: team boundaries and service boundaries must be designed together, organised by domain.
Continue learning
Related topics and courses to explore next
