Microservices Anti‑Patterns
1) Distributed Monolith
What: Many “services” but tightly coupled (shared releases, schemas, libraries).
Why: Changes ripple across services; no independent deploys.
Better: Independent deployability as a gate; per‑service DB; contract tests; semantic versioning.
2) Shared Database
What: Multiple services read/write the same DB/tables.
Why: Hidden coupling, unsafe joins, brittle migrations.
Better: Database‑per‑service, expose data via APIs/events; use read projections if you need joins.
3) Nano‑Services (Over‑fragmentation)
What: Too many tiny services (one method = one service).
Why: Chatty calls, high ops cost, complex debugging.
Better: Size by bounded context/capability; merge services until cohesion > coupling.
4) Chatty, Synchronous Chains
What: Long request chains (A→B→C→D) for one user call.
Why: Latency amplification; cascading failures.
Better: Coarse‑grained APIs, aggregation at BFF/gateway, async messaging for non‑critical work, cache.
5) Dual Writes Without a Saga
What: Service updates two stores in one request with no coordination.
Why: Partial writes, data drift.
Better: Saga pattern (orchestration/choreography), outbox + CDC, idempotent handlers.
6) 2PC Across Services
What: Distributed XA/2‑phase commit for cross‑service ACID.
Why: Fragile, slow, vendor lock‑in.
Better: Eventual consistency with Sagas; compensating actions; user‑visible states.
7) Wrong Service Boundaries
What: Split by technical layers (controllers vs DAOs) instead of domain.
Why: High cross‑service chatter, unclear ownership.
Better: Decompose by business capability/subdomain; use DDD and anti‑corruption layers.
8) God Service / Central Orchestrator for Everything
What: One service coordinates most flows.
Why: Becomes a bottleneck and single point of failure.
Better: Balance orchestration vs choreography; push logic to owning services; enforce boundaries.
9) Shared “Core” Libraries for Domain Logic
What: Multiple services depend on the same internal domain jar.
Why: Tight coupling; version pinning across fleet.
Better: Share only pure utilities; share domain via API/Events, not code.
10) Bypassing the Gateway
What: Clients call random services directly.
Why: Leaky topology, inconsistent auth/rate limits, breaking changes hit clients.
Better: API gateway/BFF, consistent auth, throttling, routing, schema/contract governance.
11) No Resilience (Retries/Timeouts/Circuit Breakers)
What: Blind HTTP calls with default timeouts.
Why: Cascading outages, resource exhaustion.
Better: Timeouts, bounded retries with jitter, circuit breakers, bulkheads, fallbacks.
12) Snowflake Deployments
What: Manual deploys and hand‑crafted servers.
Why: Drift, irreproducible incidents, slow recovery.
Better: CI/CD, immutable images, IaC (Terraform), blue‑green/rolling canaries.
13) Missing Observability
What: Logs only; no correlation, metrics, or traces.
Why: Slow MTTR; guessing during incidents.
Better: Structured logs + trace IDs, OpenTelemetry traces, RED/Golden metrics, SLOs/alerts.
14) Environment Parity Gaps
What: Dev/stage/prod differ (ports, configs, data).
Why: “Works on my machine” bugs.
Better: Containerized dev; prod‑like dependencies locally; config via env/secret managers.
15) Centralized Team Owning Every Service
What: Platform team changes app code; feature teams blocked.
Why: Bottlenecks, slow delivery.
Better: You build it, you run it; clear ownership, paved roads from a platform team.
16) Overusing Events for Simple CRUD
What: Everything becomes async/event‑sourced.
Why: Hidden flows, hard debugging, eventual‑consistency surprises.
Better: Use events where they add value; keep simple CRUD synchronous behind clear APIs.
17) Fat DTOs / Leaky Contracts
What: Expose internal models directly.
Why: Breaks clients on change; over‑fetch/under‑fetch.
Better: Versioned, purpose‑built contracts; GraphQL/BFFs for client shaping.
18) No Idempotency
What: Retries create duplicates or corrupt state.
Why: At‑least‑once delivery becomes dangerous.
Better: Idempotency keys, upserts, natural/business keys, dedupe guards.
19) Single Store for All Workloads
What: One DB forced to serve OLTP + analytics + search.
Why: Contention, bad performance.
Better: Polyglot persistence with projections; CQRS where justified.
20) Premature Microservices
What: Split too early without domain clarity.
Why: Complexity before benefits.
Better: Start as a modular monolith; extract services when boundaries are stable.
Quick checklist to stay sane
- Independent deploys? ✅
- Per‑service data ownership? ✅
- Contracts & versioning? ✅
- Resilience + observability baked in? ✅
- CI/CD + IaC + environment parity? ✅
Want this as a one‑page PDF/playbook for your team? I can whip that up.