Skill: quochungto/bookforge-microservice-granularity-optimizer (version 1.0.0)

--- name: microservice-granularity-optimizer description: > Right-size microservice boundaries using granularity disintegrators (forces to split: service scope, code volatility, scalability, fault tolerance, security, extensibility) and integrators (forces to combine: database transactions, workflow/choreography coupling, shared code, data relationships). Includes choreography vs orchestration selection and the saga pattern for distributed transactions. Use this skill whenever the user is splitting a monolith into microservices, deciding how fine-grained services should be, experiencing too many inter-service calls or latency from over-splitting, dealing with distributed transaction problems across microservices, choosing between choreography and orchestration for service communication, implementing the saga pattern, debugging a distributed monolith, or evaluating whether services should be merged or split further -- even if they don't use the exact phrase "microservice granularity." version: 1.0.0 homepage: https://github.com/bookforge-ai/bookforge-skills/tree/main/books/fundamentals-of-software-architecture/skills/microservice-granularity-optimizer metadata: {"openclaw":{"emoji":"📚","homepage":"https://github.com/bookforge-ai/bookforge-skills"}} status: draft depends-on: - component-identifier source-books: - id: fundamentals-of-software-architecture title: "Fundamentals of Software Architecture" authors: ["Mark Richards", "Neal Ford"] chapters: [17] tags: [software-architecture, architecture, microservices, granularity, bounded-context, disintegrators, integrators, choreography, orchestration, saga, distributed-transactions] execution: tier: 2 mode: hybrid inputs: - type: none description: "System description with current or proposed service boundaries, inter-service communication patterns, and transaction requirements -- the skill guides the granularity optimization process" tools-required: [Read, Write] tools-optional: [Grep, Glob] mcps-required: [] environment: "Any agent environment. If a codebase exists, can analyze current service structure." --- # Microservice Granularity Optimizer ## When to Use You need to determine the right size for microservice boundaries, evaluate whether existing services should be split or merged, or select communication patterns (choreography vs orchestration) for inter-service coordination. The most common mistake in microservices is making services too small -- as Martin Fowler noted, "microservice" is a label, not a description. Typical situations: - Splitting a monolith -- "we want to decompose into microservices, but how small should each service be?" - Over-splitting diagnosis -- "we split too fine and now every request requires 5+ inter-service calls" - Distributed transaction pain -- "we need atomic operations across services but SAGA is killing us" - Communication design -- "should our services use choreography or orchestration?" - Granularity evaluation -- "we have 30 microservices for a system that could be 8 -- did we over-decompose?" - Merge vs split decision -- "these two services always change together and share data -- should we merge them?" Before starting, verify: - Has microservices been confirmed as the architecture style? If the user hasn't decided yet, consider using `architecture-style-selector` first. - Are components identified? If not, use `component-identifier` to establish initial service candidates. - If the user has existing microservices and is troubleshooting granularity, proceed directly. ## Context & Input Gathering ### Input Sufficiency Check This skill optimizes microservice granularity. You can proceed with partial information, but certain inputs directly determine the quality of the recommendation. ### Required Context (must have -- ask if missing) - **Current or proposed service boundaries:** What services exist (or are planned) and what does each one do? -> Check prompt for: service names, service responsibilities, API descriptions, domain descriptions -> If missing, ask: "What are your current (or proposed) microservices and what does each one handle?" - **Inter-service communication pain points:** Which services call each other frequently? Where is latency or complexity highest? -> Check prompt for: mentions of "too many calls," latency, coupling, distributed transactions, data consistency -> If missing, ask: "Which services communicate with each other most frequently, and are there pain points (latency, failed transactions, tight coupling)?" ### Important Context (strongly recommended -- ask if easy to obtain) - **Transaction requirements:** Which operations must be atomic across service boundaries? -> Check prompt for: ACID mentions, consistency requirements, "must be atomic" language, order/payment/inventory workflows -> If missing, ask: "Are there business operations that need to be all-or-nothing across multiple services? For example, does placing an order need to atomically update inventory and charge payment?" - **Scalability differences:** Do different parts of the system need to scale independently? -> Check prompt for: traffic patterns, peak load descriptions, "X gets 100x more traffic than Y" -> If missing and relevant, ask: "Do any parts of your system need to scale independently? For example, does search need to handle 100x more traffic than checkout?" ### Observable Context (gather from environment) - **Existing service structure:** If a codebase exists, scan for service boundaries -> Look for: Docker/Kubernetes configs, API gateway routes, service directories, inter-service client libraries -> Reveals: actual granularity, communication patterns, shared dependencies ### Default Assumptions - If communication pattern unknown -> assume choreography-first (aligns with microservices philosophy) - If transaction requirements unknown -> assume most operations are eventually consistent, flag any that look like they need atomicity - If team size unknown -> assume moderate (can handle 5-15 services) ### Sufficiency Threshold ``` SUFFICIENT: service boundaries (current or proposed) + communication pain points + transaction requirements are known PROCEED WITH DEFAULTS: service boundaries are known, pain points and transactions unclear MUST ASK: service boundaries are missing entirely ``` ## Process ### Step 1: Map Current Service Boundaries **ACTION:** Document each service's scope, responsibilities, and data ownership. **WHY:** You cannot optimize granularity without understanding the current state. Each microservice should model a bounded context -- a domain or workflow that includes everything necessary to operate: classes, subcomponents, and database schemas. The bounded context concept from domain-driven design is the philosophical foundation of microservices. Services that share databases, classes, or schemas are not truly bounded and will suffer from coupling that defeats the purpose of microservices. **For each service, document:** 1. Name and domain purpose 2. Key entities and data it owns 3. Which other services it calls (and why) 4. Which other services call it (and why) 5. Database(s) it uses -- shared or dedicated **IF** services share a database -> flag as coupling risk (violates data isolation principle) **IF** multiple services need the same entity class (e.g., Address) -> this is expected; microservices prefer duplication over coupling ### Step 2: Apply Granularity Disintegrators **ACTION:** Evaluate each service against the six disintegrator forces. Each force that applies pushes toward splitting the service into smaller ones. **WHY:** Disintegrators are the forces that justify making services smaller. Without a structured evaluation, architects split services based on gut feeling, which usually leads to either over-splitting (too many tiny services) or under-splitting (hidden monolith). Each disintegrator has a specific, testable reason for splitting -- if none apply, the service is the right size. **The six disintegrators:** 1. **Service scope and function** -- Is the service doing too many unrelated things? -> Test: Can you describe the service's purpose in one sentence without using "and"? -> If the service handles "order management AND inventory tracking AND shipping," it may be doing too much. -> Split when: the service contains multiple distinct business domains that could operate independently. 2. **Code volatility** -- Do different parts of the service change at very different rates? -> Test: Over the last 6 months, did some components change weekly while others haven't changed in months? -> Split when: a frequently-changing component is locked into a service with stable components, forcing unnecessary redeployments. 3. **Scalability** -- Do different parts need different scaling profiles? -> Test: Does one component need 10 instances while another needs only 1? -> Split when: scaling the service up also scales components that don't need it, wasting resources. 4. **Fault tolerance** -- Should a failure in one part NOT bring down another part? -> Test: If the recommendation engine fails, should order processing still work? -> Split when: a non-critical component's failure takes down a critical component. 5. **Security** -- Do different parts require different security levels or access controls? -> Test: Does one component handle PCI/PII data while another handles public data? -> Split when: the entire service must run at the highest security level because one component requires it. 6. **Extensibility** -- Is one part of the service likely to grow in directions that don't affect the rest? -> Test: Are new features being added to one component while others remain stable? -> Split when: extension points are concentrated in one area and coupling to the rest slows development. **Score each service:** For each disintegrator, mark whether it applies (YES/NO) with specific evidence. A service with 3+ disintegrators applying is a strong candidate for splitting. ### Step 3: Apply Granularity Integrators **ACTION:** Evaluate whether services that seem like they should be separate actually need to stay together (or be merged). **WHY:** Integrators are the counter-forces to disintegrators -- they are reasons NOT to split (or reasons to merge services that were split too aggressively). The most common microservices mistake is ignoring integrators: splitting services that need ACID transactions, that always change together, or that share critical code. The result is a distributed monolith -- all the complexity of microservices with none of the benefits. **The four integrators:** 1. **Database transactions** -- Do these services need ACID transactions between them? -> Test: Must operations across these services be all-or-nothing? If payment fails, must the order be rolled back atomically? -> Merge when: you find yourself building SAGA patterns for operations that were trivial database transactions before splitting. The best advice for distributed transactions is: DON'T. Fix the granularity instead. -> **Critical rule:** "Don't do transactions in microservices -- fix granularity instead!" Transaction boundaries are one of the strongest indicators of incorrect granularity. 2. **Workflow and choreography** -- Do these services require extensive back-and-forth communication? -> Test: Does completing one business operation require 4+ synchronous calls between services? -> Merge when: the inter-service communication overhead exceeds the benefit of separation. If Service A cannot do anything useful without calling Service B, they may belong together. 3. **Shared code** -- Do these services share significant business logic (not just utilities)? -> Test: Is the same business rule implemented in multiple services? When the rule changes, do multiple services need updating? -> Merge when: shared code represents shared business logic that changes together. (Shared infrastructure code like logging is fine to duplicate -- it's shared domain logic that indicates coupling.) 4. **Data relationships** -- Do these services constantly need each other's data? -> Test: Does Service A frequently query Service B just to get reference data it needs for every operation? -> Merge when: the data dependency is so frequent that every request to A triggers a call to B, effectively creating a runtime monolith. **For each pair of closely-related services:** Evaluate all four integrators. If 2+ integrators apply strongly, the services should likely be merged. ### Step 4: Resolve Conflicts and Decide **ACTION:** When disintegrators say "split" but integrators say "keep together," make a judgment call based on the trade-offs. **WHY:** Almost every granularity decision involves tension between splitting forces and combining forces. There is no formula -- this is where architectural judgment matters. The key insight is that integrators generally win over disintegrators when they apply, because the cost of fighting integrators (distributed transactions, excessive communication, duplicated business logic) is usually higher than the cost of a slightly-too-large service. **Decision framework:** - **Strong disintegrators + weak integrators** -> Split the service - **Weak disintegrators + strong integrators** -> Keep together (or merge) - **Strong disintegrators + strong integrators** -> This is the hard case. Consider: - Can the transaction boundary be redesigned to avoid the ACID need? - Can an event-driven approach replace synchronous coupling? - Would the saga pattern be acceptable for this specific workflow? - Is the operational cost of SAGA worth the deployment/scaling independence? **IF** transaction integrator is the blocker -> strongly favor keeping services together. Distributed transactions are the #1 source of microservices complexity. **IF** choreography integrator is the blocker -> consider whether orchestration could reduce the coupling enough to justify the split. ### Step 5: Select Communication Pattern **ACTION:** For each inter-service communication path, choose between choreography and orchestration. **WHY:** Choreography (broker-style, no central coordinator) and orchestration (mediator-style, central coordinator) represent fundamentally different trade-offs. Choreography preserves the decoupled philosophy of microservices and is the natural default. Orchestration creates coupling but simplifies complex multi-step workflows. The choice directly affects how well the architecture handles errors, maintains decoupling, and manages workflow complexity. **Choreography (default for microservices):** - Each service calls other services as needed, no central coordinator - Resembles the broker pattern in event-driven architecture - Preserves bounded context philosophy -- each service is autonomous - Trade-off: error handling and coordination are distributed across services - Best for: simple workflows, high decoupling needs, services that can operate independently - Risk: complex workflows become "front controller" patterns where one service becomes an accidental mediator **Orchestration:** - A dedicated mediator service coordinates the workflow across other services - Creates coupling through the mediator, but centralizes coordination logic - Trade-off: coupling through mediator vs. distributed complexity without one - Best for: complex multi-step business processes (e.g., "place order" involving payment, inventory, shipping) - Risk: mediator becomes a bottleneck or single point of failure **Decision criteria:** | Factor | Choreography | Orchestration | |--------|:---:|:---:| | Workflow complexity | Simple (2-3 services) | Complex (4+ services) | | Error handling | Distributed, each service handles its own | Centralized in mediator | | Decoupling | Maximum | Moderate (mediator creates coupling) | | Visibility | Low (tracing across services needed) | High (mediator has full view) | | Performance | Fewer bottlenecks | Mediator can bottleneck | | Domain isomorphism | Natural fit for microservices | Better for structured workflows | ### Step 6: Design Saga Pattern (if needed) **ACTION:** For any remaining cross-service transactions that cannot be eliminated by adjusting granularity, design the saga (compensating transaction) pattern. **WHY:** Even with optimal granularity, some distributed transactions are unavoidable -- for example, when two services genuinely need different architecture characteristics (one needs extreme scalability, the other needs strict security isolation) yet must participate in a business transaction. The saga pattern coordinates these transactions through a do/undo mechanism: each service operation has a compensating "undo" operation. A mediator service tracks the transaction state and triggers compensating actions if any step fails. This is significantly more complex than ACID transactions and should be used sparingly. **For each saga:** 1. List the participating services and their operations 2. Define the "do" operation for each service 3. Define the "undo" (compensating) operation for each service 4. Choose: choreographed saga (each service triggers the next) or orchestrated saga (mediator coordinates) 5. Define the pending state management (how do you track which steps completed?) 6. Define error handling: what happens if the undo operation itself fails? **Critical warnings:** - A few transactions across services is sometimes necessary; if it's the dominant feature of the architecture, mistakes were made - If you find yourself designing SAGAs for most of your workflows, your services are too granular -- go back to Step 2-4 and merge services - The undo operations are often significantly more complex than the do operations - Asynchronous SAGAs with contingent requests create race conditions that are extremely difficult to debug ### Step 7: Validate and Score **ACTION:** Validate the final granularity against microservices architecture characteristic ratings and check for anti-patterns. **WHY:** Every architecture style has known strengths and weaknesses. Validating against the ratings ensures you are leveraging the architecture's strengths (scalability, elasticity, evolutionary, modularity) and not fighting its weaknesses (performance, cost, simplicity). Checking for anti-patterns catches the most common design mistakes. **Microservices architecture ratings:** | Characteristic | Rating | Notes | |---------------|:------:|-------| | Deployability | 4 | Small, independent deployment units | | Elasticity | 5 | Fine-grained scaling per service | | Evolutionary | 5 | High decoupling enables incremental change | | Fault tolerance | 4 | Independent services fail independently | | Modularity | 5 | Each service is a bounded context | | Overall cost | 1 | Expensive: infrastructure, orchestration, monitoring | | Performance | 2 | Network calls replace method calls | | Reliability | 4 | Redundancy via service discovery | | Scalability | 5 | Each service scales independently | | Simplicity | 1 | Most complex distributed architecture | | Testability | 4 | Small test scope per service | **Anti-pattern checks:** - **Distributed monolith:** Services share databases, deploy together, or can't function independently. You have all the complexity of microservices with none of the benefits. - **Over-granular services:** Every API call requires 3+ inter-service hops. Latency is unacceptable. Most workflows need SAGAs. Services can't do anything useful alone. - **Entity trap:** Services modeled after database entities (UserService, OrderService, ProductService) rather than business capabilities/workflows. - **Shared database:** Multiple services read/write the same database tables, creating hidden coupling through schema changes. - **Front controller:** One "choreographed" service has become an accidental orchestrator, handling coordination for most workflows while also maintaining its own domain logic. - **Transaction spaghetti:** More than 30% of workflows require SAGA patterns -- indicates granularity is wrong. ## Inputs - Current or proposed service boundaries with responsibilities - Inter-service communication patterns and pain points - Transaction requirements (which operations must be atomic) - Scalability and fault tolerance differences between services - Existing codebase structure (if migrating from monolith) ## Outputs ### Granularity Optimization Report ```markdown # Microservice Granularity Report: {System Name} ## Current State **Services:** {count} **Key pain points:** {latency, transactions, coupling, etc.} ## Disintegrator/Integrator Analysis ### Service: {ServiceName} **Current scope:** {what it does} | Disintegrator | Applies? | Evidence | |--------------|:--------:|----------| | Service scope/function | {Y/N} | {evidence} | | Code volatility | {Y/N} | {evidence} | | Scalability | {Y/N} | {evidence} | | Fault tolerance | {Y/N} | {evidence} | | Security | {Y/N} | {evidence} | | Extensibility | {Y/N} | {evidence} | | **Disintegrator score** | **{count}/6** | | ### Service Pair: {ServiceA} + {ServiceB} | Integrator | Applies? | Evidence | |-----------|:--------:|----------| | Database transactions | {Y/N} | {evidence} | | Workflow coupling | {Y/N} | {evidence} | | Shared code | {Y/N} | {evidence} | | Data relationships | {Y/N} | {evidence} | | **Integrator score** | **{count}/4** | | **Decision:** {split / merge / keep as-is} **Reasoning:** {why} ## Recommended Service Boundaries | # | Service | Domain | Owns Data | Scales to | |---|---------|--------|-----------|:---------:| | 1 | {name} | {domain} | {entities} | {instances} | ## Communication Design | Workflow | Services involved | Pattern | Reasoning | |----------|------------------|---------|-----------| | {workflow} | {services} | Choreography / Orchestration | {why} | ## Saga Patterns (if any) ### Saga: {WorkflowName} | Step | Service | Do operation | Undo operation | |:----:|---------|-------------|----------------| | 1 | {service} | {do} | {undo} | | 2 | {service} | {do} | {undo} | **Coordination:** {choreographed / orchestrated} **Pending state:** {how tracked} ## Anti-Pattern Check - [ ] No shared databases between services - [ ] No distributed monolith (services deploy independently) - [ ] Not over-granular (<30% of workflows need SAGA) - [ ] No entity trap (services model workflows, not entities) - [ ] No accidental front controllers - [ ] Each service can function with limited degradation if others fail ## Characteristic Fit | Characteristic | Rating | Meets needs? | |---------------|:------:|:------------:| | Deployability | 4 | {Yes/No} | | Elasticity | 5 | {Yes/No} | | ... | ... | ... | ``` ## Key Principles - **"Microservice" is a label, not a description** -- The originators chose the name to contrast with "gigantic services" (SOA), not to prescribe size. Many developers treat "micro" as a commandment and create services that are too fine-grained. The purpose of service boundaries is to capture a domain or workflow, and those boundaries might be large for some parts of the system. - **Don't do transactions in microservices -- fix granularity instead** -- This is the single most important guideline. Architects who build microservices and then find themselves wiring transactions across service boundaries have almost certainly made their services too granular. Transaction boundaries are one of the strongest indicators of incorrect granularity. Merge the services that transact together. - **Bounded context is the architectural unit** -- Each microservice should model a complete bounded context: its own classes, subcomponents, and database schemas. Nothing is shared with other services. Duplication (e.g., an Address class in multiple services) is preferred over coupling. This is the opposite of traditional enterprise thinking where reuse was paramount. - **Data isolation is non-negotiable** -- Each service must own its data exclusively. No shared databases, no shared schemas, no shared tables. When services need each other's data, they communicate through well-defined APIs or events, never through direct database access. Shared databases are integration points that create hidden coupling. - **Choreography is the natural default** -- Because microservices favors decoupling, choreography (no central coordinator) is the natural fit. Orchestration should only be introduced for complex multi-step workflows where distributed error handling would be too complex. Even then, the orchestrator should be a thin coordination service, not a place for business logic. - **Integrators generally win over disintegrators** -- When splitting forces conflict with combining forces, the combining forces usually carry more weight. The cost of fighting integrators (SAGA complexity, excessive communication, duplicated business logic) almost always exceeds the cost of a slightly-too-large service. - **Iterate on granularity** -- Architects rarely discover the correct granularity, data dependencies, and communication styles on their first pass. Expect to iterate. Start with slightly larger services and split only when a specific disintegrator provides clear justification. ## Examples **Scenario: Over-split order processing system** Trigger: "We split our Order service into OrderCreation, OrderValidation, OrderPricing, OrderFulfillment, and OrderNotification. Now placing a single order requires 5 synchronous calls in sequence, latency tripled, and we need distributed transactions between OrderCreation and OrderPricing. How do we fix this?" Process: Applied disintegrator analysis to each sub-service. Only OrderNotification had independent scalability needs (disintegrator: scalability). All others shared the same code volatility, security level, and fault tolerance requirements. Applied integrator analysis: OrderCreation + OrderPricing had strong database transaction integrator (pricing must be atomic with order creation). OrderCreation + OrderValidation + OrderFulfillment had strong workflow coupling integrator (always called in sequence, never independently). Recommendation: merge OrderCreation, OrderValidation, OrderPricing, and OrderFulfillment back into a single OrderService. Keep OrderNotification separate (different scalability profile, can be async, fault tolerant to delays). Output: **Reduced from 5 services to 2 (OrderService + NotificationService).** Eliminated 4 synchronous inter-service calls per order. Eliminated distributed transaction between creation and pricing (now a single ACID transaction). OrderNotification communicates via async events (choreography). Latency dropped by ~60%. **Scenario: Monolith decomposition with mixed granularity needs** Trigger: "We have a monolithic e-commerce application. We want to move to microservices. The system handles: product catalog, search, user accounts, shopping cart, order processing, payment, inventory management, shipping, reviews, and analytics." Process: Applied disintegrators systematically. Product Catalog and Search have different scalability needs (search gets 100x more traffic) -- split. Payment has unique security requirements (PCI compliance) -- split. Analytics has different code volatility (changes daily vs monthly for core) -- split. Reviews and Ratings are extensible independently -- split. Applied integrators: Order Processing + Payment have a strong transaction integrator (payment must be atomic with order), but the security disintegrator for Payment is stronger -- keep separate, use orchestrated saga. Shopping Cart + Order Processing have weak integrator (cart is pre-order, separate lifecycle). Inventory + Shipping have moderate data relationship integrator but different scalability needs. Output: **8 services:** ProductCatalog, Search, UserAccounts, ShoppingCart, OrderProcessing, Payment, InventoryShipping (merged due to data integrator), ReviewsRatings, Analytics. One saga pattern for Order-Payment. Choreography for most communication; orchestration for the order placement workflow (OrderProcessing orchestrates Payment and InventoryShipping). **Scenario: Distributed transaction redesign** Trigger: "We're designing a new e-commerce platform with microservices. When a customer places an order, we need to: reserve inventory, charge payment, and create a shipment. If payment fails after inventory is reserved, we need to release it. How do we handle this?" Process: First evaluated whether these truly need to be separate services (integrator analysis). Inventory and Shipping have different scalability needs (inventory checks happen at browse-time too, not just checkout). Payment has PCI security isolation requirements. These disintegrators justify keeping them separate despite the transaction integrator. Designed an orchestrated saga: OrderService acts as the saga mediator. Step 1: Reserve inventory (do: reserve, undo: release). Step 2: Charge payment (do: charge, undo: refund). Step 3: Create shipment (do: create, undo: cancel). If Step 2 fails, OrderService calls inventory.release(). Each service enters "pending" state until the saga completes. Chose orchestration over choreography because the error handling for compensating transactions is too complex to distribute. Output: **Orchestrated saga with 3 participants.** OrderService mediates. Each service implements do/undo operations. Pending state tracked in OrderService database. Explicit error handling: if undo itself fails, alert + manual resolution queue. Warning noted: if more than ~30% of workflows need sagas, the granularity should be reconsidered. ## References - For detailed disintegrator/integrator decision matrices and trade-off tables, see [references/disintegrators-integrators.md](references/disintegrators-integrators.md) - For identifying initial service candidates, use `component-identifier` - For choosing between microservices and service-based architecture, use `architecture-style-selector` - For documenting granularity decisions, use [REDACTED_SECRET] ## License This skill is licensed under [CC-BY-SA-4.0](https://creativecommons.org/licenses/by-sa/4.0/). Source: [BookForge](https://github.com/bookforge-ai/bookforge-skills) — Fundamentals of Software Architecture by Mark Richards, Neal Ford. ## Related BookForge Skills Install related skills from ClawhHub: - `clawhub install bookforge-component-identifier` Or install the full book set from GitHub: [bookforge-skills](https://github.com/bookforge-ai/bookforge-skills)

path: meta/value-contributions/microservice-granularity-optimizer.json
content: {
  "skill_name": "microservice-granularity-optimizer",
  "version": 1,
  "source_book": "fundamentals-of-software-architecture",
  "source_chapters": [17],
  "value_contributions": [
    {
      "id": "VC-1",
      "category": "framework",
      "name": "Disintegrator/Integrator Analysis",
      "description": "Provides a structured 6-disintegrator + 4-integrator framework for evaluating whether services should be split or merged, replacing gut-feel decisions with evidence-based analysis.",
      "without_skill_behavior": "Architects split services based on entity names or arbitrary size rules ('each service should be <500 LOC'). No systematic evaluation of splitting vs. combining forces.",
      "with_skill_behavior": "Each service is evaluated against 6 disintegrators (scope, volatility, scalability, fault tolerance, security, extensibility) and each service pair against 4 integrators (transactions, workflow coupling, shared code, data relationships). Decisions are evidence-based with clear thresholds.",
      "measurable_impact": "Prevents over-splitting (reduces 15+ service architectures to 5-8 right-sized services) and under-splitting (identifies monolithic services that should be decomposed)."
    },
    {
      "id": "VC-2",
      "category": "anti-pattern-prevention",
      "name": "Transaction Boundary Detection",
      "description": "Identifies distributed transaction anti-patterns early by applying the rule 'Don't do transactions in microservices -- fix granularity instead.' Services that need ACID transactions between them are flagged for merging.",
      "without_skill_behavior": "Architects split services and then discover they need distributed transactions. They implement SAGA patterns for operations that should be simple ACID transactions, adding massive complexity.",
      "with_skill_behavior": "Transaction requirements are evaluated as the strongest integrator before splitting. Services that transact together are kept together. SAGAs are used only when genuinely necessary (different security/scalability requirements force separation).",
      "measurable_impact": "Eliminates unnecessary SAGA implementations. In testing, without-skill outputs proposed SAGAs for workflows that with-skill outputs handled as single-service ACID transactions."
    },
    {
      "id": "VC-3",
      "category": "decision-framework",
      "name": "Choreography vs. Orchestration Selection",
      "description": "Provides structured criteria for choosing between choreography (broker-style, decoupled) and orchestration (mediator-style, coordinated) for each inter-service workflow, based on workflow complexity, error handling needs, and decoupling priority.",
      "without_skill_behavior": "Architects default to one pattern for all workflows (usually orchestration via API gateway), or mix patterns inconsistently without reasoning about trade-offs.",
      "with_skill_behavior": "Each workflow is evaluated: simple 2-3 service interactions use choreography (preserves decoupling), complex 4+ service workflows with compensating transactions use orchestration (centralizes error handling). The front controller anti-pattern is detected and corrected.",
      "measurable_impact": "Produces architectures with appropriate communication patterns per workflow rather than one-size-fits-all, reducing unnecessary coupling while managing complexity."
    },
    {
      "id": "VC-4",
      "category": "anti-pattern-prevention",
      "name": "Distributed Monolith Detection",
      "description": "Detects the distributed monolith anti-pattern: services that share databases, deploy together, or cannot function independently -- giving all the complexity of microservices with none of the benefits.",
      "without_skill_behavior": "Architects create services that share databases or have tight runtime coupling, resulting in coordinated deployments and cascading failures. The architecture is a monolith with network hops added.",
      "with_skill_behavior": "Data isolation is enforced as non-negotiable. Each service owns its data exclusively. Shared database dependencies are flagged. Services are validated for independent deployability and fault isolation.",
      "measurable_impact": "Prevents the most common and costly microservices anti-pattern. Ensures the architecture actually delivers on the promised benefits of microservices."
    },
    {
      "id": "VC-5",
      "category": "framework",
      "name": "Saga Pattern Design with Compensating Transactions",
      "description": "When distributed transactions are genuinely unavoidable, provides a structured approach to designing saga patterns with do/undo operations, pending state management, and error handling for failed compensations.",
      "without_skill_behavior": "SAGAs are designed ad-hoc, often missing compensating operations for edge cases, lacking pending state management, and having no plan for when undo operations themselves fail.",
      "with_skill_behavior": "Each saga is designed with explicit do/undo operations per service, a coordination choice (choreographed vs orchestrated), pending state tracking, and error escalation for failed compensations. Includes the critical warning: if >30% of workflows need sagas, the granularity is wrong.",
      "measurable_impact": "Produces complete, production-ready saga designs rather than hand-wavy 'use saga pattern' recommendations."
    },
    {
      "id": "VC-6",
      "category": "quality-validation",
      "name": "Microservices Characteristic Ratings Validation",
      "description": "Validates the final architecture against the known microservices characteristic ratings (Deploy=4, Elast=5, Evol=5, FaultTol=4, Mod=5, Cost=1, Perf=2, Rel=4, Scale=5, Simple=1, Test=4) to ensure the design leverages strengths and doesn't fight weaknesses.",
      "without_skill_behavior": "No validation against architectural style ratings. Architectures may attempt to optimize for characteristics where microservices is structurally weak (e.g., performance, simplicity, cost).",
      "with_skill_behavior": "Design is scored against all 11 characteristics. If the system needs high performance (rating: 2 stars) or simplicity (1 star), the architect is warned that microservices structurally cannot deliver this and should consider alternative styles.",
      "measurable_impact": "Prevents selection of microservices for systems where its structural weaknesses conflict with requirements."
    }
  ]
}


path: references/disintegrators-integrators.md
content: # Granularity Disintegrators and Integrators -- Deep Reference

> Source: Chapter 17, Fundamentals of Software Architecture (Richards & Ford)
> Read this file when you need detailed trade-off analysis for specific disintegrator/integrator combinations.

## Disintegrators (Forces Pushing Toward Smaller Services)

Disintegrators are reasons to break a service into smaller pieces. Each has a specific test and threshold. A service should only be split when at least one disintegrator clearly applies with concrete evidence.

### 1. Service Scope and Function

**What it tests:** Is the service responsible for too many unrelated business capabilities?

**How to evaluate:**
- Can you describe the service in one sentence without "and"?
- Does the service span multiple bounded contexts?
- Would different teams naturally own different parts of this service?

**Split threshold:** The service handles 3+ distinct business capabilities that could operate independently.

**Example:**
- BAD (too broad): "CustomerService handles registration, preferences, authentication, notification settings, and analytics tracking"
- GOOD (split): CustomerProfile (registration, preferences), AuthService (authentication), NotificationService (settings + delivery), AnalyticsService (tracking)

**Counter-check with integrators:** Before splitting, verify that the proposed sub-services don't have strong transaction or workflow integrators between them.

### 2. Code Volatility

**What it tests:** Do different parts of the service change at significantly different rates?

**How to evaluate:**
- Look at git history: which directories/packages change most frequently?
- Over 6 months, does one component change weekly while another hasn't changed?
- Do deployments of stable components happen only because an unrelated component changed?

**Split threshold:** One component changes 5x+ more frequently than another, causing unnecessary redeployments of stable code.

**Example:**
- A ReportingService contains both report generation (stable, changes quarterly) and report template management (volatile, changes weekly for new template types). Split: ReportEngine (stable) + ReportTemplates (volatile).

**Counter-check:** If the volatile and stable components share significant business logic (shared code integrator), splitting may force you to maintain that logic in two places.

### 3. Scalability

**What it tests:** Do different parts of the service need different numbers of instances or different resource profiles?

**How to evaluate:**
- Does one component need 10 instances while another needs 1?
- Does one component need GPUs while another needs only CPU?
- Do traffic patterns differ (one spikes during events, another is steady)?

**Split threshold:** One component needs 3x+ more instances or fundamentally different resources than another component in the same service.

**Example:**
- A ProductService handles both product catalog browsing (high traffic, needs 20 instances) and product data import (low traffic, needs 1 instance, runs nightly). Split: ProductCatalog (scales horizontally) + ProductImport (single instance, batch).

**Counter-check:** If both components read/write the same database tables, splitting creates data coupling that may negate the scaling benefit.

### 4. Fault Tolerance

**What it tests:** Should a failure in one part of the service NOT affect another part?

**How to evaluate:**
- If Component A fails, must Component B keep working?
- Are there different availability SLAs for different parts?
- Does a non-critical feature bring down a critical one when it fails?

**Split threshold:** A non-critical component's failure has caused (or could cause) downtime in a critical component.

**Example:**
- An OrderService handles both order placement (critical, must be 99.99% available) and order recommendations (nice-to-have, can degrade). If the recommendation engine has a memory leak, it shouldn't crash order placement. Split: OrderProcessing (critical) + OrderRecommendations (degradable).

**Counter-check:** If order processing needs recommendation data to function (data relationship integrator), the split may not achieve true fault isolation.

### 5. Security

**What it tests:** Do different parts require different security levels, access controls, or compliance boundaries?

**How to evaluate:**
- Does one component handle PCI/PII/HIPAA data while another handles public data?
- Do different components need different network zones or encryption levels?
- Would a security audit scope be smaller if the component were isolated?

**Split threshold:** The entire service must run at the highest security level because one component requires it, forcing unnecessary security overhead on other components.

**Example:**
- A UserService handles both user profiles (moderate security) and payment methods (PCI DSS scope). Keeping them together puts the entire service in PCI scope. Split: UserProfile (standard security) + PaymentMethods (PCI-isolated).

### 6. Extensibility

**What it tests:** Is one part of the service likely to grow significantly while other parts remain stable?

**How to evaluate:**
- Are new features concentrated in one component?
- Is one component's API surface growing while another is stable?
- Would adding new functionality to one component benefit from independent deployment?

**Split threshold:** One component is receiving 5x+ more feature requests than others, and the shared deployment pipeline slows down delivery.

---

## Integrators (Forces Pushing Toward Larger Services)

Integrators are reasons to keep services together (or merge services that were split). They represent costs that are incurred when services are separated. Integrators generally win over disintegrators when they apply strongly.

### 1. Database Transactions

**Strength: VERY HIGH** -- This is the most powerful integrator.

**What it tests:** Do operations across these services need ACID guarantees?

**How to evaluate:**
- Must Operation A and Operation B either both succeed or both fail?
- Would eventual consistency cause business-visible problems (double charges, phantom inventory, inconsistent records)?
- Are you building SAGA patterns for operations that were simple database transactions before splitting?

**Merge threshold:** If you need ACID transactions between two services, they almost certainly should be one service. "Don't do transactions in microservices -- fix granularity instead!"

**When to override:** Only when a strong disintegrator (usually security or extreme scalability difference) makes merging impractical AND the business can tolerate eventual consistency with compensating transactions.

**The saga alternative (last resort):**
If services genuinely cannot be merged despite transaction needs, implement the saga pattern:

| Aspect | Choreographed Saga | Orchestrated Saga |
|--------|-------------------|-------------------|
| Coordination | Each service triggers the next | Central mediator coordinates |
| Coupling | Lower | Higher (through mediator) |
| Error handling | Distributed across services | Centralized in mediator |
| Visibility | Low (requires distributed tracing) | High (mediator has full state) |
| Complexity | Higher for complex workflows | Higher for simple workflows |
| Best for | 2-3 service sagas | 4+ service sagas |

**Saga implementation pattern:**
```
For each service operation in the saga:
  1. Define the "do" operation (forward action)
  2. Define the "undo" operation (compensating action)
  3. Define the "pending" state (in-flight marker)

On success: all services commit, clear pending state
On failure at step N:
  1. Record failure
  2. Call undo on steps N-1, N-2, ..., 1 (reverse order)
  3. Report failure to caller
  4. If undo itself fails: alert + manual resolution queue
```

### 2. Workflow and Choreography Coupling

**Strength: HIGH**

**What it tests:** Do these services require extensive back-and-forth communication to complete business operations?

**How to evaluate:**
- Count the inter-service calls for common workflows. If a single business operation requires 4+ synchronous calls between two specific services, they are tightly coupled.
- Does Service A frequently wait for Service B's response before it can continue? (Synchronous dependency)
- If Service B is down, can Service A do anything useful?

**Merge threshold:** If Service A calls Service B on every request, and neither can function without the other, they are one service pretending to be two.

**The front controller anti-pattern:**
In choreography, one service often becomes the "first service called" for complex workflows. This service ends up coordinating other services while also maintaining its own domain logic, making it an accidental mediator. If a choreographed service is spending more than ~30% of its logic on coordination, consider either:
- Merging the coordinated services back together, OR
- Extracting the coordination into an explicit orchestrator service (removing it from the domain service)

### 3. Shared Code

**Strength: MODERATE**

**What it tests:** Do these services share significant business logic?

**How to evaluate:**
- Is the same business rule implemented in multiple services?
- When a business rule changes, how many services need updating?
- Is there a shared library containing business logic (not just utilities)?

**Important distinction:**
- **Shared infrastructure code** (logging, monitoring, circuit breakers) -> This is fine. Use the sidecar pattern. Don't merge services because they share operational concerns.
- **Shared business logic** (pricing rules, validation logic, domain calculations) -> This indicates the services may belong together. The shared business logic represents a single bounded context that was split across services.

**Merge threshold:** If changing a business rule requires coordinated updates to 3+ services, the rule likely belongs in a single service that owns that business logic.

### 4. Data Relationships

**Strength: MODERATE**

**What it tests:** Do these services constantly need each other's data?

**How to evaluate:**
- Does Service A frequently query Service B just to get reference data?
- Could Service A cache Service B's data, or does it always need the latest?
- What percentage of Service A's requests require data from Service B?

**Merge threshold:** If >50% of Service A's operations require real-time data from Service B, they have a data relationship that suggests they should be one service.

**Alternatives to merging:**
- **Data replication:** Service B publishes events when its data changes; Service A maintains a read-only copy. Works for reference data that doesn't change frequently.
- **Shared data service:** Extract the shared data into its own service that both consume. Works when the data is a clear domain concept (e.g., "configuration" used by many services).

---

## Disintegrator vs. Integrator Conflict Resolution

When both forces apply to the same service, use this priority framework:

| Conflict | Typical resolution |
|----------|-------------------|
| Scalability disintegrator + Transaction integrator | Keep together. Scale the combined service. Transactions trump scalability unless the scalability difference is extreme (100x+). |
| Security disintegrator + Transaction integrator | Split. Security isolation is hard to compromise. Use saga pattern for the transaction. Accept the complexity cost. |
| Code volatility disintegrator + Shared code integrator | Keep together. Deploy more frequently. The cost of maintaining shared business logic across services usually exceeds the cost of redeploying stable code. |
| Fault tolerance disintegrator + Workflow coupling integrator | Split, but use async communication. The faulting service can degrade gracefully while the critical service continues. Use circuit breakers. |
| Scope disintegrator + Data relationship integrator | Evaluate: can the data relationship be handled by replication or events? If yes, split. If the data must be real-time consistent, keep together. |

## Choreography vs. Orchestration Decision Matrix

| Decision factor | Favors Choreography | Favors Orchestration |
|----------------|:---:|:---:|
| Number of services in workflow | 2-3 | 4+ |
| Error handling complexity | Simple (retry/fail) | Complex (compensating transactions) |
| Workflow visibility needs | Low | High (audit trail, monitoring) |
| Decoupling priority | High | Moderate |
| Domain/architecture isomorphism | Microservices (natural fit) | Structured workflows (better fit) |
| Performance sensitivity | Higher (no mediator bottleneck) | Lower (mediator adds latency) |
| Team autonomy | Teams work independently | Teams coordinate through mediator contract |

**Default recommendation:** Start with choreography. Introduce orchestration only when choreography complexity becomes unmanageable (typically when a single workflow spans 4+ services with compensating transactions).

## The Sidecar Pattern and Service Mesh

**Problem:** Microservices duplicates infrastructure concerns (logging, monitoring, circuit breakers) across services. Each team implementing these independently leads to inconsistency.

**Solution:** The sidecar pattern extracts operational concerns into a separate component that deploys alongside each service. The sidecar handles logging, monitoring, circuit breakers, and other cross-cutting concerns. A shared infrastructure team maintains the sidecar; when they upgrade the monitoring tool, every service gets the upgrade automatically.

**Service mesh:** When all sidecars connect to a shared service plane, the result is a service mesh -- a consistent operational interface across all microservices. The service mesh provides:
- Unified logging and monitoring
- Consistent circuit breaker behavior
- Service discovery
- mTLS between services
- Traffic management and routing

**Key principle:** The sidecar pattern is the correct way to handle operational reuse in microservices. Domain logic is duplicated (each service has its own Address class). Operational logic is shared (via sidecar). This is the opposite of SOA, which tried to share everything.


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)