SPB Git

spb/ultra-sharp-agent-skills Public

Ultra-Sharp Agent Skills — a research-first skill-authoring system + 72 production-ready skills for AI agents.

Python 100%
4.4 KB · 116 lines markdown
Rendered Raw Blame History
1<!--2Author: Simon-Pierre Boucher3Contact: contact@spboucher.ai4-->56# Patterns — Architecting Service Boundaries78## Contents9- Split/don't-split decision table10- Modular monolith enforcement11- Saga with compensations (order placement)12- Local read model via events13- Strangler extraction plan14- Distributed-monolith smell test15- Gotchas1617## Split/don't-split decision table1819| Signal | Verdict |20|---|---|21| Module needs 10× the replicas of the rest | Split (scaling trigger) |22| Module ships weekly while the rest ships daily and blocks it | Split (cadence trigger) |23| Two teams keep merge-conflicting in one module | Split (ownership trigger) |24| "It would be cleaner as a service" | Don't split |25| Junior team, no platform/on-call maturity | Don't split yet |26| Module is called by everything, in-process, latency-sensitive | Don't split |2728## Modular monolith enforcement2930Enforce boundaries inside one deployable so extraction stays cheap:3132```33app/34├── billing/        # public API: billing/api.py only35├── catalog/36├── fulfillment/37└── shared/         # pure utilities only — no business logic38```3940- Each module exposes one façade (`billing/api.py`); cross-module imports of internals fail CI (import-linter / ArchUnit / eslint-boundaries).41- Each module gets its own schema/namespace in the database from day one — table ownership is then already settled when a split comes.4243## Saga with compensations (order placement)4445```46Step                    Compensation471. reserve inventory  → release reservation482. charge payment     → refund payment493. create shipment    → cancel shipment504. send confirmation  → (terminal; deliberately last — cannot be unsent)51```5253```python54SAGA = [55    (reserve_inventory, release_reservation),56    (charge_payment,    refund_payment),57    (create_shipment,   cancel_shipment),58    (send_confirmation, None),          # irreversible step goes last59]6061def run_saga(order):62    done = []63    for step, compensate in SAGA:64        try:65            step(order)66            done.append(compensate)67        except StepFailed:68            for comp in reversed(done):   # unwind in reverse order69                if comp:70                    comp(order)71            raise72```7374Orchestration (one coordinator, above) is the default — easier to trace and test.75Choreography (each service reacts to events) is the escape hatch when the76coordinator itself becomes a coupling point.7778## Local read model via events7980Instead of `fulfillment` calling `catalog` on every shipment:8182```83catalog  --publishes-->  product.updated {id, weight, dims}84fulfillment --consumes--> upserts into its own product_dimensions table85```8687Fulfillment reads locally (fast, survives catalog downtime); staleness is88bounded by event lag and must be acceptable for the use case — if it isn't,89the data wasn't yours to cache and the boundary may be wrong.9091## Strangler extraction plan92931. Freeze feature work in the monolith module being extracted.942. Stand up the new service; dual-write or replay events to fill its store.953. Route N% of read traffic via a routing layer flag; compare responses (shadow diff).964. Ramp N → 100 with the rollback switch live at every step.975. Cut writes over behind the same flag; verify; delete monolith code path within a sprint (a dormant duplicate path rots into rule-8 territory).9899## Distributed-monolith smell test100101Answer for each service; any "yes" means redraw:102103- Must it deploy in the same release train as another service?104- Does another service read or write its tables?105- Does one service's outage take it fully down (not degraded)?106- Do contract changes require synchronized PRs across repos?107108## Gotchas109110- **Entity-shaped services** (`user-service` that everyone calls for everything) recreate the shared database over HTTP; split by capability (identity vs profile vs preferences).111- **Shared libraries with business logic** are a hidden shared schema — a change forces lockstep upgrades. Keep shared libs to pure utilities.112- **Sagas are not ACID**: intermediate states are visible. Model them explicitly (`PENDING_PAYMENT`), don't pretend isolation.113- **Compensation ≠ undo**: refund is a new transaction, not an erasure — books must show both.114- **Event schemas are contracts too** — version them like APIs (rule 6), with consumers tolerant of unknown fields.115- **The routing flag is load-bearing** during strangler cuts; it needs tests and an owner like any production code.116