$npx -y skills add proyecto26/system-design-skills --skill service-decompositionThis skill should be used when the user asks "monolith vs microservices", how to "split into services", set "service boundaries", find the right "service granularity", design an "API gateway / BFF", do "service discovery" or add a "service mesh", or worries that services are "too
| 1 | # Service Decomposition |
| 2 | |
| 3 | Decide how to carve a system into deployable services — or whether to — and how |
| 4 | those services find and call each other. This is the "application layer" of a |
| 5 | design: it sits between the edge (`dns`/`load-balancing`/`content-delivery`) and |
| 6 | the data tier. Getting the *granularity* wrong is one of the most expensive |
| 7 | mistakes in distributed systems, in both directions. |
| 8 | |
| 9 | > The trap cuts both ways. One giant service can't scale teams or components |
| 10 | > independently; a swarm of tiny ones drowns you in network hops, partial |
| 11 | > failures, and undebuggable cross-service traces. The skill is finding the |
| 12 | > sweet spot for *this* system at *this* size — not maximizing service count. |
| 13 | |
| 14 | ## When to reach for this |
| 15 | A second service is on the table; teams need to deploy independently; one part has |
| 16 | a wildly different scaling profile than the rest; or an existing system is "too |
| 17 | chatty" / hard to change. Also when someone proposes "microservices" by default. |
| 18 | |
| 19 | ## When NOT to |
| 20 | A new product / small team / unproven domain — start with a **monolith** (or a |
| 21 | modular monolith) and split later when a real seam and a real reason appear. |
| 22 | Splitting prematurely buys distributed-systems cost (network failure, eventual |
| 23 | consistency, ops) to solve a problem you don't have yet (YAGNI, GUIDE #7). Don't |
| 24 | add a gateway/mesh/discovery layer before you have services that need them. |
| 25 | |
| 26 | ## Clarify first |
| 27 | - **Team & deploy independence** — must parts ship on separate cadences/owners? |
| 28 | - **Differential scale** — does one component need 100× the others' resources? |
| 29 | - **Coupling** — which parts change together (belong together) vs evolve apart? |
| 30 | - **Latency budget** — how many in-process calls would become network hops? |
| 31 | - **Consistency across the seam** — can the split tolerate eventual consistency |
| 32 | between services? (→ `consistency-coordination`) |
| 33 | |
| 34 | ## The options |
| 35 | - **Monolith** — one deployable. Use when: new/small, fast iteration, strong |
| 36 | cross-module transactions, one team. |
| 37 | - **Modular monolith** — one deployable, enforced internal module boundaries. |
| 38 | Use when: you want clean seams *without* network cost yet — the best default |
| 39 | for "we might split later." |
| 40 | - **Microservices** — many small deployables split by business capability / |
| 41 | bounded context. Use when: independent deploy/scale/ownership genuinely pays |
| 42 | for the distributed-systems tax. |
| 43 | - **Comms style** — decide only whether a given seam is **synchronous** (REST/gRPC, |
| 44 | request/response, simple but couples availability) or **asynchronous** (decoupled |
| 45 | but eventually consistent). This block decides *sync-or-async per seam*; it does |
| 46 | **not** own the async mechanics — once a seam is async, **invoke |
| 47 | `messaging-streaming`** for the delivery guarantees, ordering, backpressure, and |
| 48 | DLQ semantics that make it safe. Don't pick async from the one-line "no immediate |
| 49 | answer needed" rule without opening those failure modes. Most systems are a mix. |
| 50 | - **Edge of the service tier** — an **API gateway / BFF** (one front door: |
| 51 | auth, routing, rate limiting, aggregation) vs direct exposure. |
| 52 | - **Finding each other** — **service discovery** (registry: DNS-based, or |
| 53 | etcd/Consul/ZooKeeper) and optionally a **service mesh** (sidecars for mTLS, |
| 54 | retries, traffic shaping) vs library-level clients. |
| 55 | |
| 56 | ## Trade-offs |
| 57 | |
| 58 | | Option | What it solves | What it worsens | Change it when | |
| 59 | |---|---|---|---| |
| 60 | | Monolith | Simplicity; in-process calls; easy transactions/debugging | Couples deploy/scale; one team bottleneck; blast radius | Teams/scale profiles diverge → modular monolith → split a seam | |
| 61 | | Modular monolith | Clean boundaries, no network cost, split-later optionality | Still one deploy; discipline required to keep modules clean | A module needs independent deploy/scale → extract it to a service | |
| 62 | | Microservices | Independent deploy/scale/ownership per capability | Network failure, eventual consistency, distributed debugging, ops | Coordination/latency cost exceeds the independence benefit → merge | |
| 63 | | Sync comms | Simple mental model, immediate result | Availability couples (caller fails if callee does); latency stacks | A call doesn't need an immediate answer → async (`messaging-streaming`) | |
| 64 | | API gateway / BFF | One front door for auth/routing/rate-limit/aggregation | A new tier + potential SPOF/bottleneck; can become a mini-monolith | It accretes business logic → push logic back into services |