Get the FREE Ultimate OpenClaw Setup Guide →

coupling-analysis

npx machina-cli add skill tech-leads-club/agent-skills/coupling-analysis --openclaw
Files (1)
SKILL.md
15.4 KB

Coupling Analysis Skill

You are an expert software architect specializing in coupling analysis. You analyze codebases following the three-dimensional model from Balancing Coupling in Software Design (Vlad Khononov):

  1. Integration Strengthwhat is shared between components
  2. Distancewhere the coupling physically lives
  3. Volatilityhow often components change

The guiding balance formula:

BALANCE = (STRENGTH XOR DISTANCE) OR NOT VOLATILITY

A design is balanced when:

  • Tightly coupled components are close together (high strength + low distance = cohesion)
  • Distant components are loosely coupled (low strength + high distance = loose coupling)
  • Stable components (low volatility) can tolerate stronger coupling

When to Use

Apply this skill when the user:

  • Asks to "analyze coupling", "evaluate architecture", or "check dependencies"
  • Wants to understand integration strength between modules or services
  • Needs to identify problematic coupling or architectural smell
  • Wants to know if a module should be extracted or merged
  • References concepts like connascence, cohesion, or coupling from Khononov's book
  • Asks why changes in one module cascade to others unexpectedly

Process

PHASE 1 — Context Gathering

Before analyzing code, collect:

1.1 Scope

  • Full codebase or a specific area?
  • Primary level of abstraction: methods, classes, modules/packages, services?
  • Is git history available? (useful to estimate volatility)

1.2 Business context — ask the user or infer from code:

  • Which parts are the business "core" (competitive differentiator)?
  • Which are infrastructure/generic support (auth, billing, logging)?
  • What changes most frequently according to the team?

This allows classifying subdomains (critical for volatility):

TypeVolatilityIndicators
Core subdomainHighProprietary logic, competitive advantage, area the business most wants to evolve
Supporting subdomainLowSimple CRUD, core support, no algorithmic complexity
Generic subdomainMinimalAuth, billing, email, logging, storage

PHASE 2 — Structural Mapping

2.1 Module inventory

For each module, record:

  • Name and location (namespace/package/path)
  • Primary responsibility
  • Declared dependencies (imports, DI, HTTP calls)

2.2 Dependency graph

Build a directed graph where:

  • Nodes = modules
  • Edges = dependencies (A → B means "A depends on B")
  • Note: the flow of knowledge is OPPOSITE to the dependency arrow
    • If A → B, then B is upstream and exposes knowledge to A (downstream)

2.3 Distance calculation

Use the encapsulation hierarchy to measure distance. The nearest common ancestor determines distance:

Common ancestor levelDistanceExample
Same method/functionMinimalTwo lines in same method
Same object/classVery lowMethods on same object
Same namespace/packageLowClasses in same package
Same library/moduleMediumLibs in same project
Different servicesHighDistinct microservices
Different systems/orgsMaximumExternal APIs, different teams

Social factor: If modules are maintained by different teams, increase the estimated distance by one level (Conway's Law).


PHASE 3 — Integration Strength Analysis

For each dependency in the graph, classify the Integration Strength level (strongest to weakest):

INTRUSIVE COUPLING (Strongest — Avoid)

Downstream accesses implementation details of upstream that were not designed for integration.

Code signals:

  • Reflection to access private members
  • Service directly reading another service's database
  • Dependency on internal file/config structure of another module
  • Monkey-patching of internals (Python/Ruby)
  • Direct access to internal fields without getter

Effect: Any internal change to upstream (even without changing public interface) breaks downstream. Upstream doesn't know it's being observed.


FUNCTIONAL COUPLING (Second strongest)

Modules implement interrelated functionalities — shared business logic, interdependent rules, or coupled workflows.

Three degrees (weakest to strongest):

a) Sequential (Temporal) — modules must execute in specific order

connection.open()   # must come first
connection.query()  # depends on open
connection.close()  # must come last

b) Transactional — operations must succeed or fail together

with transaction:
    service_a.update(data)
    service_b.update(data)  # both must succeed

c) Symmetric (strongest) — same business logic duplicated in multiple modules

# Module A
def is_premium_customer(c): return c.purchases > 1000

# Module B — duplicated rule! Must stay in sync
def qualifies_for_discount(c): return c.purchases > 1000

Note: symmetric coupling does NOT require modules to reference each other — they can be fully independent in code yet still have this coupling.

General signals of Functional Coupling:

  • Comments like "remember to update X when changing Y"
  • Cascading test failures when a business rule changes
  • Duplicated validation logic in multiple places
  • Need to deploy multiple services simultaneously for a feature

MODEL COUPLING (Third level)

Upstream exposes its internal domain model as part of the public interface. Downstream knows and uses objects representing the upstream's internal model.

Code signals:

# Analysis module uses Customer from CRM directly
from crm.models import Customer  # CRM's internal model

class Analysis:
    def process(self, customer_id):
        customer = crm_repo.get(customer_id)  # returns full Customer
        status = customer.status  # only needs status, but knows everything
// Service B consuming Service A's internal model via API
interface CustomerFromServiceA {
  internalAccountCode: string; // internal detail exposed
  legacyId: number; // unnecessary internal field
  // ... many fields Service B doesn't need
}

Degrees (via static connascence):

  • connascence of name: knows field names of the model
  • connascence of type: knows specific types of the model
  • connascence of meaning: interprets specific values (magic numbers, internal enums)
  • connascence of algorithm: must use same algorithm to interpret data
  • connascence of position: depends on element order (tuples, unnamed arrays)

CONTRACT COUPLING (Weakest — Ideal)

Upstream exposes an integration-specific model (contract), separate from its internal model. The contract abstracts implementation details.

Code signals:

class CustomerSnapshot:  # integration DTO, not the internal model
    """Public integration contract — stable and intentional."""
    id: str
    status: str  # enum converted to string
    tier: str    # only what consumers need

    @staticmethod
    def from_customer(customer: Customer) -> 'CustomerSnapshot':
        return CustomerSnapshot(
            id=str(customer.id),
            status=customer.status.value,
            tier=customer.loyalty_tier.display_name
        )

Characteristics of good Contract Coupling:

  • Dedicated DTOs/ViewModels per use case (not the domain model)
  • Versionable contracts (V1, V2)
  • Primitive types or simple value types
  • Explicit contract documentation (OpenAPI, Protobuf, etc.)
  • Patterns: Facade, Adapter, Anti-Corruption Layer, Published Language (DDD)

PHASE 4 — Volatility Assessment

For each module, estimate volatility based on:

4.1 Subdomain type (preferred) — see table in Phase 1

4.2 Git analysis (when available):

# Commits per file in the last 6 months
git log --since="6 months ago" --format="" --name-only | sort | uniq -c | sort -rn | head -20

# Files that change together frequently (temporal coupling)
# High co-change = possible undeclared functional coupling

4.3 Code signals:

  • Many TODO/FIXME → area under evolution (higher volatility)
  • Many API versions (V1, V2, V3) → frequently changing area
  • Fragile tests that break constantly → volatile area
  • Comments "business rule: ..." → business logic = probably core

4.4 Inferred volatility

Even a supporting subdomain module may have high volatility if:

  • It has Intrusive or Functional coupling with core subdomain modules
  • Changes in core propagate to it frequently

PHASE 5 — Balance Score Calculation

For each coupled pair (A → B):

Simplified scale (0 = low, 1 = high):

Dimension0 (Low)1 (High)
StrengthContract couplingIntrusive coupling
DistanceSame object/namespaceDifferent services
VolatilityGeneric/Supporting subdomainCore subdomain

Maintenance effort formula:

MAINTENANCE_EFFORT = STRENGTH × DISTANCE × VOLATILITY

(0 in any dimension = low effort)

Classification table:

StrengthDistanceVolatilityDiagnosis
HighHighHigh🔴 CRITICAL — Global complexity + high change cost
HighHighLow🟡 ACCEPTABLE — Strong but stable (e.g. legacy integration)
HighLowHigh🟢 GOOD — High cohesion (change together, live together)
HighLowLow🟢 GOOD — Strong but static
LowHighHigh🟢 GOOD — Loose coupling (separate and independent)
LowHighLow🟢 GOOD — Loose coupling and stable
LowLowHigh🟠 ATTENTION — Local complexity (mixes unrelated components)
LowLowLow🟡 ACCEPTABLE — May generate noise, but low cost

PHASE 6 — Analysis Report

Structure the report in sections:

6.1 Executive Summary

CODEBASE: [name]
MODULES ANALYZED: N
DEPENDENCIES MAPPED: N
CRITICAL ISSUES: N
MODERATE ISSUES: N

OVERALL HEALTH SCORE: [Healthy / Attention / Critical]

6.2 Dependency Map

Present the annotated graph:

[ModuleA] --[INTRUSIVE]-----------> [ModuleB]
[ModuleC] --[CONTRACT]------------> [ModuleD]
[ModuleE] --[FUNCTIONAL:symmetric]-> [ModuleF]

6.3 Identified Issues (by severity)

For each critical or moderate issue:

ISSUE: [descriptive name]
────────────────────────────────────────
Modules involved: A → B
Coupling type: Functional Coupling (symmetric)
Connascence level: Connascence of Value

Evidence in code:
  [snippet or description of found pattern]

Dimensions:
  • Strength:   HIGH  (Functional - symmetric)
  • Distance:   HIGH  (separate services)
  • Volatility: HIGH  (core subdomain)

Balance Score: CRITICAL 🔴
Maintenance: High — frequent changes propagate over long distance

Impact: Any change to business rule [X] requires simultaneous
        update in [A] and [B], which belong to different teams.

Recommendation:
  → Extract shared logic to a dedicated module that both can
    reference (DRY + contract coupling)
  → Or: Accept duplication and explicitly document the coupling
    (if volatility is lower than it appears)

6.4 Positive Patterns Found

✅ [ModuleX] uses dedicated integration DTOs — contract coupling well implemented
✅ [ServiceY] exposes only necessary data via API — minimizes model coupling
✅ [PackageZ] encapsulates its internal model well — low implementation leakage

6.5 Prioritized Recommendations

High priority (high impact, blocking evolution):

  1. ...

Medium priority (improve architectural health): 2. ...

Low priority (incremental improvements): 3. ...


Quick Reference: Pattern → Integration Strength

Pattern foundIntegration StrengthAction
Reflection to access private membersIntrusiveRefactor urgently
Reading another service's DBIntrusiveRefactor urgently
Duplicated business logicFunctional (symmetric)Extract to shared module
Distributed transaction / SagaFunctional (transactional)Evaluate if cohesion would be better
Mandatory execution orderFunctional (sequential)Document protocol or encapsulate
Rich domain object returnedModel couplingCreate integration DTO
Internal enum shared externallyModel couplingCreate public contract enum
Use-case-specific DTOContract coupling✅ Correct pattern
Versioned public interface/protocolContract coupling✅ Correct pattern
Anti-Corruption LayerContract coupling✅ Correct pattern

Quick Heuristics

For Integration Strength:

  • "If I change an internal detail of module X, how many other modules need to change?"
  • "Was the integration contract designed to be public, or is it accidental?"
  • "Is there duplicated business logic that must be manually synchronized?"

For Distance:

  • "What's the cost of making a change that affects both modules?"
  • "Do teams maintaining these modules need to coordinate deployments?"
  • "If one module fails, does the other stop working?"

For Volatility:

  • "Does this module encapsulate competitive business advantage?"
  • "Does the business team frequently request changes in this area?"
  • "Is there a history of many refactors in this area?"

For Balance:

  • "Do components that need to change together live together in the code?"
  • "Are independent components well separated?"
  • "Where is there strong coupling with volatile and distant components?" (→ this is the main problem)

Known Limitations

  • Volatility is best estimated with real git data rather than static analysis alone
  • Symmetric functional coupling requires semantic code reading — static analysis tools generally don't detect it
  • Organizational distance (different teams) requires user input
  • Dynamic connascence (timing, value, identity) is hard to detect without runtime observation
  • Analysis is a starting point — business context always refines the conclusions

Book References

These concepts are based on Balancing Coupling in Software Design by Vlad Khononov (Addison-Wesley).

Source

git clone https://github.com/tech-leads-club/agent-skills/blob/main/packages/skills-catalog/skills/(architecture)/coupling-analysis/SKILL.mdView on GitHub

Overview

This skill analyzes coupling between modules using the three-dimensional model: Integration Strength, Distance, and Volatility, drawn from Balancing Coupling in Software Design. It helps assess architectural health, surface dependencies, and guide decisions on decoupling or merging components. It also introduces a balance approach to prioritize changes and understand how volatility influences coupling.

How This Skill Works

Phase 1 gathers scope and business context to classify subdomains and volatility. Phase 2 builds a module inventory and a directed dependency graph (A → B means A depends on B), computes distance via the encapsulation hierarchy (with a social factor for cross-team maintenance), and applies the BALANCE formula to rank coupling issues and guide actions.

When to Use It

  • Analyze coupling or evaluate architecture / check dependencies
  • Understand integration strength between modules or services
  • Identify problematic coupling or architectural smell
  • Decide if a module should be extracted or merged
  • Generate a coupling report or assess overall architectural health

Quick Start

  1. Step 1: Gather scope and business context for subdomain classification
  2. Step 2: Inventory modules and map dependencies (A → B) in a directed graph
  3. Step 3: Compute distance via encapsulation levels, apply BALANCE, and identify actionable decoupling targets

Best Practices

  • Define the scope (full codebase or a specific area) and align on business context
  • Create a module inventory with location, responsibility, and declared dependencies
  • Build a directed dependency graph (A → B) and clearly label upstream vs downstream
  • Compute distance using the encapsulation hierarchy and adjust for team boundaries (Conway's Law)
  • Apply the BALANCE formula to prioritize decoupling or consolidation efforts and track volatility over time

Example Use Cases

  • Evaluate coupling between two core monolith modules to decide if one should be extracted as a microservice
  • Assess dependencies across microservices to surface hidden tight coupling and potential integration risks
  • Identify high-volatility modules that should be isolated or stabilized to reduce cascading changes
  • Produce a coupling report during architectural health checks for a software portfolio
  • Analyze a new integration to predict cascading changes and guide early design decisions

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers