tadata
Back to home

Microservices Patterns and Anti-Patterns

#microservices#architecture#api#distributed-systems

Microservices promise independent deployability, team autonomy, and technology flexibility. They also deliver distributed systems complexity, network unreliability, and operational overhead. Knowing which patterns to apply -- and which anti-patterns to avoid -- separates successful implementations from distributed monoliths.

Decomposition Strategies

How you split a monolith matters more than whether you split it.

StrategyApproachWhen to Use
By business capabilityAlign services to business domains (orders, payments, inventory)Stable domain boundaries
By subdomain (DDD)Use Domain-Driven Design bounded contextsComplex domains with clear separations
Strangler figGradually extract services from a monolithIncremental migration
By teamOne service per team (inverse Conway's Law)Organizational alignment

Inter-Service Communication

PatternProtocolUse CaseTrade-off
Synchronous RESTHTTP/JSONSimple CRUD operationsTight coupling, cascade failures
Synchronous gRPCHTTP/2 + ProtobufHigh-performance internal APIsSchema management, less human-readable
Async messagingAMQP, KafkaEvent-driven workflowsEventual consistency, harder debugging
Async request-replyCorrelation IDs over queuesLong-running operationsComplexity in tracking requests

The Saga Pattern for Distributed Transactions

Traditional ACID transactions do not span services. The saga pattern coordinates multi-service operations:

Choreography-based saga:

  • Each service publishes events and listens for events from others
  • No central coordinator
  • Simple for 2-3 services, complex for more

Orchestration-based saga:

  • A central orchestrator directs the workflow
  • Each service exposes a compensating action for rollback
  • Easier to understand, but the orchestrator is a single point of logic
AspectChoreographyOrchestration
CouplingLooseMedium (to orchestrator)
VisibilityHard to trace full flowClear workflow definition
Complexity at scaleGrows exponentiallyGrows linearly
Best forSimple workflowsComplex multi-step processes

Service Mesh

A service mesh handles cross-cutting concerns at the infrastructure layer:

  • Traffic management -- routing, load balancing, canary deployments
  • Security -- mutual TLS, authorization policies
  • Observability -- distributed tracing, metrics, access logs
  • Resilience -- retries, circuit breakers, timeouts

Popular options: Istio (feature-rich, complex), Linkerd (lightweight, simpler), Consul Connect (HashiCorp ecosystem).

Critical Anti-Patterns

Anti-PatternSymptomFix
Distributed monolithServices must be deployed togetherEnforce API contracts, reduce shared databases
Shared databaseMultiple services write to the same tablesDatabase per service, events for sync
Chatty servicesHundreds of inter-service calls per requestAggregate APIs, BFF pattern
Nano-servicesServices too small to justify overheadMerge related services
God serviceOne service handles too much logicDecompose by bounded context
Sync chainA calls B calls C calls D synchronouslyAsync messaging, event-driven

When Monolith Is Better

Microservices are not always the answer:

  • Small team (< 10 engineers) -- operational overhead outweighs benefits
  • Early-stage product -- domain boundaries are not yet clear
  • Simple domain -- CRUD applications do not need distributed complexity
  • Low scale -- if a single server handles the load, do not distribute it
  • Tight latency requirements -- every network hop adds latency

A well-structured modular monolith can deliver most of the organizational benefits of microservices without the distributed systems tax.

Resources