AgentStack
SKILL verified MIT Self-run

Service Decomposition

skill-proyecto26-system-design-skills-service-decomposition · by proyecto26

This 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 chatty" / "too fine-grained". It gives the recipe for carving a system into services (or deciding not to) and wiring h…

No reviews yet
0 installs
19 views
0.0% view→install

Install

$ agentstack add skill-proyecto26-system-design-skills-service-decomposition

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Service Decomposition? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Service Decomposition

Decide how to carve a system into deployable services — or whether to — and how those services find and call each other. This is the "application layer" of a design: it sits between the edge (dns/load-balancing/content-delivery) and the data tier. Getting the granularity wrong is one of the most expensive mistakes in distributed systems, in both directions.

> The trap cuts both ways. One giant service can't scale teams or components > independently; a swarm of tiny ones drowns you in network hops, partial > failures, and undebuggable cross-service traces. The skill is finding the > sweet spot for this system at this size — not maximizing service count.

When to reach for this

A second service is on the table; teams need to deploy independently; one part has a wildly different scaling profile than the rest; or an existing system is "too chatty" / hard to change. Also when someone proposes "microservices" by default.

When NOT to

A new product / small team / unproven domain — start with a monolith (or a modular monolith) and split later when a real seam and a real reason appear. Splitting prematurely buys distributed-systems cost (network failure, eventual consistency, ops) to solve a problem you don't have yet (YAGNI, GUIDE #7). Don't add a gateway/mesh/discovery layer before you have services that need them.

Clarify first

  • Team & deploy independence — must parts ship on separate cadences/owners?
  • Differential scale — does one component need 100× the others' resources?
  • Coupling — which parts change together (belong together) vs evolve apart?
  • Latency budget — how many in-process calls would become network hops?
  • Consistency across the seam — can the split tolerate eventual consistency

between services? (→ consistency-coordination)

The options

  • Monolith — one deployable. Use when: new/small, fast iteration, strong

cross-module transactions, one team.

  • Modular monolith — one deployable, enforced internal module boundaries.

Use when: you want clean seams without network cost yet — the best default for "we might split later."

  • Microservices — many small deployables split by business capability /

bounded context. Use when: independent deploy/scale/ownership genuinely pays for the distributed-systems tax.

  • Comms style — decide only whether a given seam is synchronous (REST/gRPC,

request/response, simple but couples availability) or asynchronous (decoupled but eventually consistent). This block decides sync-or-async per seam; it does not own the async mechanics — once a seam is async, invoke messaging-streaming for the delivery guarantees, ordering, backpressure, and DLQ semantics that make it safe. Don't pick async from the one-line "no immediate answer needed" rule without opening those failure modes. Most systems are a mix.

  • Edge of the service tier — an API gateway / BFF (one front door:

auth, routing, rate limiting, aggregation) vs direct exposure.

  • Finding each otherservice discovery (registry: DNS-based, or

etcd/Consul/ZooKeeper) and optionally a service mesh (sidecars for mTLS, retries, traffic shaping) vs library-level clients.

Trade-offs

| Option | What it solves | What it worsens | Change it when | |---|---|---|---| | 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 | | 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 | | Microservices | Independent deploy/scale/ownership per capability | Network failure, eventual consistency, distributed debugging, ops | Coordination/latency cost exceeds the independence benefit → merge | | 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) | | 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 | | Service mesh | Uniform mTLS/retries/observability without app changes | Real operational + latency overhead (sidecars) | A handful of services → a library/gateway is enough |

Behavior under stress

  • Chatty services / fan-out: one user request becomes N synchronous internal

calls; tail latency compounds and a single slow dependency stalls the chain. Mitigate: coarser boundaries, batching, async where an answer isn't needed now, and circuit breakers (→ resilience-failure).

  • Distributed-transaction pain: a write spanning services can't be one ACID

transaction. Mitigate: saga / outbox, or keep the data in one service so the transaction stays local (→ consistency-coordination).

  • Retry storms across the mesh: naive retries amplify an overload into a

cascade. Mitigate: backoff+jitter, budgets, circuit breakers (→ resilience-failure).

  • Debuggability collapse: with no correlation IDs/tracing, a failure that

crosses 6 services is invisible. Mitigate: distributed tracing + correlation IDs from day one (→ observability, distributed-logging).

  • Gateway/discovery as SPOF: if the front door or registry dies, everything

does. Mitigate: redundancy, client-side caching of discovery, health checks.

How to apply

  1. Clarify the drivers — independent deploy? differential scale? team

ownership? If none are real yet, stop: a (modular) monolith wins.

  1. Default to the simplest that fits — monolith → modular monolith →

extract the one seam that has a real reason — not "everything is a service".

  1. Cut boundaries by business capability / bounded context, so data and the

logic that owns it stay together (minimizes cross-service transactions).

  1. Choose comms per call — sync only when the caller needs an immediate

answer; async otherwise (→ messaging-streaming).

  1. Add the front door + discovery only when warranted — gateway/BFF for

auth/routing/aggregation; discovery/mesh when service count makes static wiring painful.

  1. Stress-test the seams — walk chattiness, cross-service transactions, retry

cascades, and tracing before committing.

Dos and don'ts

Do

  • Start with a monolith / modular monolith; split a seam only when a real driver appears.
  • Split by business capability so a service owns its data (keeps transactions local).
  • Give every cross-service call a correlation ID + tracing from the start.
  • Right-size: fewer, well-bounded services beat many tiny chatty ones.

Don't

  • Don't choose microservices by default or for résumé reasons (GUIDE #7).
  • Don't create a service whose write needs another service's data in the same transaction.
  • Don't let the API gateway accrete business logic into a hidden monolith.
  • Don't add a service mesh for a handful of services — the overhead outweighs it.

Numbers that matter

Each sync hop adds a same-datacenter round trip (~0.5 ms) plus the callee's own work. 10 serial hops is only ~5 ms of network — the real cost is the compounded p99/serialization/queueing/retry tail: each hop multiplies the chance of hitting a slow dependency, so end-to-end p99 degrades far faster than the mean. Size the call-graph depth and the per-hop p99 (not just the network) before splitting, with explicit p99 budgets. → back-of-the-envelope.

Interface sketch

A service boundary is a contract: the owned data (which service is the source of truth for each entity), the API it exposes (→ api-design), and the events it emits (→ messaging-streaming). Write down "who owns user records, who owns orders" before drawing service boxes — shared mutable data across a boundary is the #1 decomposition smell.

Choosing a provider

Default to the generic recipe above. If the user names a cloud, read references/providers/.md for the managed gateway / discovery / mesh mapping, limits, and trade-offs. If no file exists for that provider, the generic recipe is the answer.

Diagram

To visualize the service tier (gateway → services → their data, with sync vs async edges and trust boundaries), use the in-plugin architecture-diagram skill.

Related building blocks

  • api-designpairs with this: decomposition sets the boundaries, api-design defines each service's contract.
  • messaging-streamingpairs with this for async/event-driven comms between services (the alternative to sync coupling).
  • consistency-coordinationowns the cross-service consistency story (saga/2PC) and the coordination theory behind service discovery (leader election, etcd/Consul/ZooKeeper); link there, don't re-teach.
  • resilience-failuredepends on this: circuit breakers, timeouts, bulkheads keep a chatty mesh from cascading.
  • observability + distributed-loggingfeed into this: tracing + correlation IDs are what make a multi-service request debuggable.
  • scaling-evolutionfeeds into this: extracting a service is a scaling move on the "split a seam" rung.
  • system-design — the orchestrator.

References

  • references/deep-dive.md — bounded contexts & how to find seams, the strangler-fig migration from monolith, gateway vs BFF vs mesh, sync-vs-async decision detail, saga/outbox for cross-service writes, and the granularity anti-patterns (nano-services, distributed monolith, shared database).
  • references/providers/{generic,aws,azure,gcp}.md — gateway / service-discovery / mesh service mappings, limits, and pitfalls per environment.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.