Skill: quochungto/bookforge-modularity-health-evaluator (version 1.0.0)

--- name: modularity-health-evaluator description: Assess code modularity health using quantitative metrics — cohesion (LCOM), coupling (afferent/efferent), abstractness, instability, distance from main sequence, and connascence taxonomy. Use this skill whenever the user asks about module quality, code coupling analysis, cohesion measurement, class decomposition, package dependency analysis, LCOM scores, afferent/efferent coupling, connascence, zone of pain, zone of uselessness, extracting microservices from a monolith, evaluating module boundaries, dependency analysis, or wants to know if a class or package is well-structured — even if they don't use the term "modularity." version: 1.0.0 homepage: https://github.com/bookforge-ai/bookforge-skills/tree/main/books/fundamentals-of-software-architecture/skills/modularity-health-evaluator metadata: {"openclaw":{"emoji":"📚","homepage":"https://github.com/bookforge-ai/bookforge-skills"}} status: draft source-books: - id: fundamentals-of-software-architecture title: "Fundamentals of Software Architecture" authors: ["Mark Richards", "Neal Ford"] chapters: [3] tags: [software-architecture, modularity, cohesion, coupling, connascence, LCOM, metrics, refactoring] depends-on: [] execution: tier: 2 mode: hybrid inputs: - type: codebase description: "A software project or module descriptions to analyze for modularity health" - type: none description: "Alternatively, a textual description of classes, packages, and their dependencies" tools-required: [Read, Write] tools-optional: [Grep, Glob, Bash] mcps-required: [] environment: "Best results inside a codebase directory. Can also work from user-provided descriptions." --- # Modularity Health Evaluator ## When to Use You need to assess the structural health of code modules — classes, packages, components, or services — using quantitative modularity metrics. Typical triggers: - The user has a class with too many methods or responsibilities and wants to evaluate it - The user has a utility package that everything depends on and wants to understand the risk - The user is planning to extract microservices and needs to evaluate which modules are cleanly bounded - The user mentions coupling, cohesion, or dependency problems - The user sees cascading breakage when changing one module and wants to diagnose why - The user wants to evaluate whether a codebase is ready for architectural migration Before starting, verify: - Is there a specific module, class, or package to evaluate? (At minimum, a description of the component and its dependencies) - Does the user have access to dependency analysis tooling, or will this be a manual/descriptive assessment? ## Context & Input Gathering ### Required Context (must have before proceeding) - **Target module(s):** What class, package, or component needs evaluation? -> Check prompt for: class names, package names, module descriptions, dependency complaints -> Check environment for: src/ directories, package structures, build files -> If still missing, ask: "Which specific class, package, or module would you like me to evaluate for modularity health?" - **Dependency information:** What depends on this module, and what does it depend on? -> Check prompt for: import lists, dependency descriptions, "everything depends on X" statements -> Check environment for: import statements, package.json, pom.xml, go.mod, build.gradle -> If still missing, ask: "Can you describe what other modules depend on this one (incoming), and what this module depends on (outgoing)?" ### Observable Context (gather from environment if available) - **Codebase structure:** How is the code organized? -> Look for: directory structure, package naming conventions, module boundaries -> If unavailable: rely on user description - **Class/method details:** Method counts, field usage, abstract vs concrete elements -> Look for: source files, interface definitions, abstract classes -> If unavailable: ask the user for approximate counts - **Existing metrics:** Any existing static analysis reports (SonarQube, JDepend, etc.) -> Look for: build reports, CI artifacts, quality gate configs -> If unavailable: compute metrics manually from code or descriptions ### Default Assumptions - If no specific metrics tools available -> perform manual analysis from code structure and user descriptions - If method-field mapping is unknown -> estimate LCOM from class description and responsibility count - If exact dependency counts unknown -> use the user's qualitative description to estimate Ca/Ce ranges - If abstractness ratio unknown -> assume low abstractness (A ~ 0.1) for typical application code unless interfaces are explicitly described ### Sufficiency Threshold ``` SUFFICIENT when ALL of these are true: - At least one target module is identified with enough detail to assess - Dependency direction (incoming/outgoing) is known or estimable - Module responsibilities are described or observable from code PROCEED WITH DEFAULTS when: - Target module is identified - Dependencies are partially known - Exact counts can be estimated from qualitative descriptions MUST ASK when: - No target module is identified (cannot assess modularity without a subject) - The user's description is too vague to estimate any metrics - It's ambiguous whether the problem is cohesion, coupling, or both ``` ## Process ### Step 1: Identify and Catalog Target Modules **ACTION:** List all modules (classes, packages, components) to be evaluated. For each, document: name, primary responsibility, approximate method/function count, and any known dependencies. **WHY:** Modularity assessment requires concrete targets. Vague discussions about "coupling" without naming specific modules produce generic advice. By naming each module and its responsibility, you establish the scope for all subsequent metrics. A module's responsibility statement also serves as the baseline for evaluating cohesion — if the responsibility can't be stated in one sentence, the module likely has poor cohesion. **IF** a codebase is available -> **AGENT: EXECUTES** — scan directory structure, count files per package, identify key classes **ELSE** -> use the user's description to build the module catalog ### Step 2: Evaluate Cohesion **ACTION:** For each target module, assess cohesion type and estimate LCOM: **Cohesion type** (ranked best to worst): 1. **Functional** — every part relates to a single, well-defined function. All elements are essential. 2. **Sequential** — one part's output feeds the next part's input (pipeline within the module). 3. **Communicational** — parts operate on the same data to produce different outputs. 4. **Procedural** — parts must execute in a specific order but aren't otherwise related. 5. **Temporal** — parts are grouped because they run at the same time (e.g., initialization code). 6. **Logical** — parts are logically related but functionally different (e.g., StringUtils). 7. **Coincidental** — parts have no relationship; they're in the same module by accident. **LCOM estimation:** - Count the instance variables (fields) in the class - For each method, note which fields it accesses - LCOM = the sum of sets of methods NOT sharing fields. Higher LCOM = worse cohesion. - Practical shortcut: if most methods use only 2-3 of 12 fields, LCOM is high (bad). If most methods share most fields, LCOM is low (good). **WHY:** Cohesion determines whether a module is a natural grouping or an artificial one. Low cohesion (logical or coincidental) means the module is really multiple modules crammed together — any change risks unintended side effects on unrelated functionality. LCOM gives a structural measure: a class where methods don't share fields is structurally disconnected, meaning each field/method group could be its own class. This is the single most important indicator for "should I split this class?" **IF** source code is available -> **AGENT: EXECUTES** — analyze field-method relationships, calculate approximate LCOM **ELSE** -> estimate from the user's description of what the class/module does ### Step 3: Measure Coupling (Afferent and Efferent) **ACTION:** For each target module, count: - **Afferent coupling (Ca):** Number of modules that depend on THIS module (incoming connections — "who uses me?") - **Efferent coupling (Ce):** Number of modules THIS module depends on (outgoing connections — "who do I use?") Mnemonic: **a**fferent = **a**pproaching (incoming), **e**fferent = **e**xiting (outgoing). **WHY:** Coupling metrics reveal risk exposure. High Ca means many modules break if you change this one — it's a high-responsibility position. High Ce means this module is fragile because it depends on many others — any upstream change can break it. Neither is inherently bad, but the combination determines the module's stability profile (Step 4). A utility package with Ca=50 and Ce=0 is stable but painful to modify. A service with Ca=0 and Ce=15 is volatile but safe to change. **IF** codebase is available -> **AGENT: EXECUTES** — analyze imports, build dependency graph, count Ca and Ce per module **ELSE** -> estimate from user's description of dependency directions ### Step 4: Calculate Derived Metrics **ACTION:** From the coupling measurements, calculate three derived metrics: 1. **Instability: I = Ce / (Ca + Ce)** - Range: 0 to 1 - I = 0: maximally stable (only incoming dependencies, no outgoing — e.g., a foundational library) - I = 1: maximally unstable (only outgoing dependencies, no incoming — e.g., a leaf application) 2. **Abstractness: A = abstract_elements / total_elements** - Range: 0 to 1 - Count interfaces, abstract classes as abstract elements - Count all classes/modules as total elements - A = 0: fully concrete (no abstractions) - A = 1: fully abstract (all interfaces, no implementations) 3. **Distance from Main Sequence: D = |A + I - 1|** - Range: 0 to 1 - D = 0: perfectly balanced (on the ideal main sequence line) - D = 1: maximally imbalanced **WHY:** These derived metrics reveal architectural health that raw coupling counts miss. The main sequence represents the ideal balance: highly stable modules should be abstract (so dependents rely on interfaces, not implementations), and highly unstable modules should be concrete (they change freely since nobody depends on them). Distance from the main sequence quantifies how far a module deviates from this ideal, identifying the two danger zones. ### Step 5: Identify Zone Placement **ACTION:** Plot each module on the Abstractness-Instability graph and classify: - **Zone of Pain** (lower-left: I near 0, A near 0): Highly stable AND highly concrete. Many modules depend on it, but it has no abstractions. Painful to change because changes ripple to all dependents, and there are no interfaces to provide flexibility. -> Examples: utility libraries, core data models, shared database schemas -> Signal: "We're afraid to touch this because everything breaks" - **Zone of Uselessness** (upper-right: I near 1, A near 1): Highly unstable AND highly abstract. Few modules depend on it, and it's all interfaces with no concrete use. -> Examples: over-engineered frameworks nobody uses, abandoned abstraction layers -> Signal: "Nobody actually uses this interface hierarchy" - **Main Sequence** (diagonal from upper-left to lower-right): The healthy zone. Stable modules are abstract (changeable via interfaces). Unstable modules are concrete (free to change). **WHY:** Zone placement converts abstract metrics into actionable diagnosis. A module in the zone of pain needs abstraction (introduce interfaces so dependents don't couple to concrete implementation). A module in the zone of uselessness needs evaluation for removal or consolidation. Modules near the main sequence are healthy. This visualization makes the metrics tangible for stakeholders who can't interpret raw Ca/Ce numbers. ### Step 6: Analyze Connascence **ACTION:** For each significant coupling relationship between modules, classify the connascence type: **Static connascence** (source-level, weaker, easier to fix): - **Name (CoN):** Components agree on names. Weakest, most desirable. - **Type (CoT):** Components agree on types. Standard in typed languages. - **Meaning/Convention (CoM):** Components agree on value meanings (e.g., magic numbers, status codes). - **Position (CoP):** Components agree on parameter order. - **Algorithm (CoA):** Components must use the same algorithm (e.g., hashing on both client and server). **Dynamic connascence** (runtime, stronger, harder to fix): - **Execution (CoE):** Order of execution matters between components. - **Timing (CoT):** Timing of execution matters (race conditions). - **Values (CoV):** Multiple values must change together (distributed transactions). - **Identity (CoI):** Components must reference the same entity instance. **Three guidelines for improvement:** 1. Minimize overall connascence by encapsulating 2. Minimize connascence that crosses module boundaries 3. Maximize connascence within module boundaries **Rules from Jim Weirich:** - **Rule of Degree:** Convert strong connascence to weaker forms - **Rule of Locality:** As distance between modules increases, use weaker connascence forms **WHY:** Connascence provides a vocabulary for discussing coupling quality, not just quantity. Two modules with the same Ca/Ce scores can have very different coupling health. Connascence of Name is trivially refactorable (rename a method). Connascence of Values across a distributed system (distributed transactions) is architecturally significant and may require redesigning service boundaries. Identifying connascence type tells you HOW hard the coupling is to address, while Ca/Ce tell you HOW MUCH coupling exists. **HANDOFF TO HUMAN** for runtime connascence analysis — dynamic connascence (execution order, timing, values, identity) requires production observation, distributed tracing, or load testing to fully assess. ### Step 7: Synthesize Assessment and Recommend Actions **ACTION:** Produce the Modularity Health Report combining all metrics, zone placements, and connascence findings. For each module, provide: - Overall health rating (Healthy / At Risk / Unhealthy) - Primary concern (cohesion, coupling, zone placement, or connascence) - Specific refactoring recommendation with expected improvement **WHY:** Individual metrics are useful but can be misleading in isolation. A high LCOM is meaningless if the class has low coupling and few dependents. The synthesis step weighs all factors together and prioritizes what to fix first. The recommendation must be specific enough to act on — "improve cohesion" is useless; "extract the notification methods (notifyCustomer, sendEmail, formatNotification) into a NotificationService" is actionable. **IF** the user's goal is microservice extraction -> prioritize recommendations that create clean boundaries (low Ce, functional cohesion, weak cross-boundary connascence) **IF** the user's goal is code quality improvement -> prioritize LCOM reduction and connascence simplification ## Inputs - Target module(s) to evaluate: class names, package names, or component descriptions - Dependency information: what depends on the module and what it depends on - Optionally: source code access, existing static analysis reports, module responsibility descriptions ## Outputs ### Modularity Health Report ```markdown # Modularity Health Report: {System/Component Name} ## Assessment Scope - **Date:** {date} - **Modules assessed:** {count} - **Assessment method:** {codebase analysis / description-based / hybrid} - **Tools used:** {JDepend, SonarQube, manual analysis, etc.} ## Module Catalog | Module | Responsibility | Methods | Fields | Ca | Ce | |--------|---------------|:-------:|:------:|:--:|:--:| | {name} | {one-line responsibility} | {count} | {count} | {count} | {count} | ## Cohesion Assessment | Module | Cohesion Type | LCOM Estimate | Rating | |--------|-------------|:-------------:|:------:| | {name} | {functional/sequential/.../coincidental} | {low/medium/high} | {good/warning/poor} | ### Cohesion Details **{Module name}:** {detailed cohesion analysis with field-method groupings} ## Coupling & Derived Metrics | Module | Ca | Ce | Instability (I) | Abstractness (A) | Distance (D) | Zone | |--------|:--:|:--:|:---------------:|:-----------------:|:-------------:|------| | {name} | {n} | {n} | {0-1} | {0-1} | {0-1} | {pain/uselessness/healthy} | ## Zone Placement Map ``` Abstractness (A) 1 | Zone of / | Uselessness / | / [Module C] | / | / <-- Main Sequence | / | / | [Module B] | / [Module A: Zone of Pain] 0 +----------------------------> 1 Instability (I) ``` ## Connascence Analysis | From -> To | Type | Strength | Across Boundary? | Concern Level | |-----------|------|----------|:----------------:|:-------------:| | {module A -> module B} | {CoN/CoT/CoM/...} | {weak/moderate/strong} | {yes/no} | {low/medium/high} | ## Health Summary | Module | Health | Primary Concern | Recommended Action | |--------|:------:|-----------------|-------------------| | {name} | {Healthy/At Risk/Unhealthy} | {concern} | {specific action} | ## Prioritized Refactoring Recommendations 1. **{Highest priority}** — {specific action} -> Expected improvement: {metric change} 2. **{Second priority}** — {specific action} -> Expected improvement: {metric change} 3. **{Third priority}** — {specific action} -> Expected improvement: {metric change} ``` ## Key Principles - **Cohesion is subjective, coupling is structural** — Cohesion type requires judgment about whether groupings are "functional" or "logical." LCOM provides a structural proxy but can't distinguish essential complexity from accidental grouping. Use LCOM to flag suspects, then apply cohesion type analysis to confirm. Never rely on a single metric. - **High coupling is not inherently bad — directionality matters** — A stable foundation library with Ca=100 and Ce=0 is healthy architecture. The problem is when high Ca combines with low abstractness (zone of pain) or when high Ce makes a module fragile. Always interpret coupling in context of instability and abstractness. - **Connascence strength increases with distance** — Connascence of Name within a module is perfectly fine. Connascence of Values across distributed services is an architectural crisis. The same form of coupling becomes more dangerous as the distance between modules increases. Always evaluate connascence relative to module boundaries. - **Metrics require interpretation, not just calculation** — All code-level metrics have limitations. LCOM detects structural lack of cohesion but can't distinguish essential complexity from poor design. Cyclomatic complexity can't distinguish inherent problem complexity from accidental code complexity. Calculate the metrics, then apply architectural judgment to interpret what they mean in context. - **Zone of pain is more dangerous than zone of uselessness** — Code in the zone of uselessness wastes effort but doesn't block progress. Code in the zone of pain actively resists change and creates cascading failures. Prioritize moving modules out of the zone of pain (by introducing abstractions) over cleaning up the zone of uselessness. - **Prefer weaker forms of connascence** — When you can't eliminate coupling, downgrade it. Convert connascence of meaning (magic numbers) to connascence of name (named constants). Convert connascence of algorithm (shared hashing) to connascence of type (shared library). Each downgrade makes the coupling cheaper to maintain and less likely to cause bugs. ## Examples **Scenario: God class evaluation** Trigger: "I have a CustomerService class with 35 methods, 12 instance variables, and methods spanning registration, billing, notifications, and reporting. Is this well-designed?" Process: Cataloged the class. Identified 4 distinct responsibility groups from the method descriptions. Assessed cohesion as logical (methods related by entity, not by function). Estimated LCOM as high — registration methods use fields A,B,C; billing methods use fields D,E,F; notification methods use fields G,H; reporting methods use fields I,J,K,L. Few fields shared across groups. Measured Ca=15 (many dependents), Ce=8. Calculated I=0.35, A=0.0, D=0.65 — deep in zone of pain. Recommended extracting into 4 focused services: CustomerRegistrationService, BillingService, NotificationService, CustomerReportingService. Expected improvement: each new class achieves functional cohesion, LCOM drops to low, and D approaches 0. Output: Modularity health report showing the class is Unhealthy with a specific 4-way decomposition plan. **Scenario: Utility package dependency analysis** Trigger: "Our utils package has 200 classes and every other package depends on it. We're afraid to change anything." Process: Identified the utils package as having Ca=high (every package depends on it), Ce=low (it depends on nothing), I=0.0, A~0.05 (almost no interfaces). Plotted directly in zone of pain. Cohesion type: coincidental — date formatters, database helpers, and email templates have no functional relationship. Analyzed connascence: mostly CoN (name-based) from the rest of the codebase, but some CoM (magic numbers shared via utility constants). Recommended: (1) Extract date/time utilities into a DateTimeUtils package with an interface, (2) Move database helpers into a persistence package close to where they're used, (3) Extract email templates into a notification package. Each extraction reduces Ca on the remaining utils and moves code to functionally cohesive homes. Output: Modularity health report with 3-phase decomposition plan and expected zone migration from pain to main sequence. **Scenario: Microservice extraction readiness assessment** Trigger: "We have 15 top-level packages in our monolith. Which are ready to extract as microservices?" Process: For each package, measured Ca, Ce, calculated I and A. Assessed cohesion type. Analyzed cross-package connascence. Found 4 packages with functional cohesion, low Ce, and weak cross-boundary connascence (good candidates). Found 3 packages in zone of pain with high Ca (extract last — need abstraction first). Found 2 packages with high CoV (shared transactions — cannot extract without addressing data consistency). Ranked all 15 by extraction readiness score. Recommended extraction order: start with the 4 clean candidates, then refactor the zone-of-pain packages by introducing interfaces, then address shared-transaction packages using saga pattern or shared database strategy. Output: Ranked extraction readiness report with specific blockers and prerequisites for each package. ## References - For the complete modularity metrics reference with formulas, cohesion taxonomy, connascence types, and zone definitions, see [references/modularity-metrics-reference.md](references/modularity-metrics-reference.md) ## 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 This skill is standalone. Browse more BookForge skills: [bookforge-skills](https://github.com/bookforge-ai/bookforge-skills)

path: references/modularity-metrics-reference.md
content: # Modularity Metrics Reference

This reference provides the complete metrics framework for evaluating code modularity. Read this when you need exact formulas, threshold values, or the full connascence taxonomy.

## Cohesion Types (Ranked Best to Worst)

| Rank | Type | Definition | Example | Signal |
|:----:|------|-----------|---------|--------|
| 1 | **Functional** | Every part relates to a single function; all parts are essential | A `PaymentProcessor` class that only handles payment authorization, capture, and refund | Methods share most fields; removing any method breaks the class |
| 2 | **Sequential** | One part's output becomes the next part's input | A data pipeline class where `parse()` feeds `validate()` feeds `transform()` | Clear input-output chain between methods |
| 3 | **Communicational** | Parts operate on the same data for different purposes | A class that both saves a customer record to the database and sends a confirmation email using the same customer data | Methods share input data but produce different outputs |
| 4 | **Procedural** | Parts must execute in a specific order | A deployment class where `stopServer()` must run before `deployArtifact()` before `startServer()` | Order matters but methods don't share data |
| 5 | **Temporal** | Parts are grouped by timing, not function | A `SystemStartup` class that initializes logging, opens DB connections, and starts background threads | Methods run at the same time but are functionally unrelated |
| 6 | **Logical** | Parts are logically related but functionally different | `StringUtils` with `toUpperCase()`, `trim()`, `parseDate()`, `formatCurrency()` | Methods operate on similar types but serve different purposes |
| 7 | **Coincidental** | Parts have no meaningful relationship | A `Helpers` class with random methods thrown in for convenience | No discernible reason why these methods are together |

### Cohesion Assessment Heuristic

Ask: "If I described this module's responsibility, how many sentences would it take?"
- 1 sentence -> likely functional cohesion
- 2-3 sentences with "and" -> likely communicational or sequential
- 4+ sentences or uses "and/or" -> likely logical or coincidental

## LCOM (Lack of Cohesion in Methods)

### Definition

LCOM measures the structural cohesion of a class by analyzing how methods share instance variables (fields).

**LCOM = The sum of sets of methods NOT shared via fields**

Practical interpretation:
- **LCOM = 0:** Perfect structural cohesion. All methods access the same fields.
- **LCOM low:** Good cohesion. Most methods share fields.
- **LCOM high:** Poor cohesion. Methods form separate groups that don't share state. The class is likely multiple classes combined.

### How to Estimate LCOM Without Tooling

1. List all instance variables (fields) in the class
2. For each method, note which fields it accesses
3. Group methods by shared field access
4. If you get multiple disconnected groups -> LCOM is high

**Quick check:** If a class has N fields but each method only uses 2-3 of them, and different methods use different subsets, LCOM is high. The class should probably be split along the field-access boundaries.

### Visual Interpretation

```
Class X (Low LCOM - Good)    Class Y (High LCOM - Bad)    Class Z (Mixed)
  Fields: A, B, C              Fields: A, B, C              Fields: A, B, C
  m1() uses A, B, C            m1() uses A                  m1() uses A, B
  m2() uses A, B               m2() uses B                  m2() uses A, B
  m3() uses B, C               m3() uses C                  m3() uses C
  -> All connected             -> All disconnected           -> Two groups: {m1,m2} and {m3}
  -> Keep as one class         -> Split into 3 classes       -> Consider extracting m3+C
```

### Limitations

LCOM measures **structural** lack of cohesion only. It cannot determine if a grouping is **logically** cohesive. A `MathUtils` class with static methods sharing no state has high LCOM but may be a reasonable design choice. Always combine LCOM with cohesion type analysis.

## Coupling Metrics

### Afferent Coupling (Ca) — Incoming

- **What it measures:** The number of external modules that depend on THIS module
- **Mnemonic:** **A**fferent = **A**pproaching = incoming arrows
- **High Ca means:** Many things break if you change this module. It has high responsibility.
- **Example:** A `DateUtils` class used by 50 other classes has Ca = 50

### Efferent Coupling (Ce) — Outgoing

- **What it measures:** The number of external modules THIS module depends on
- **Mnemonic:** **E**fferent = **E**xiting = outgoing arrows
- **High Ce means:** This module is fragile. Changes in any dependency can break it.
- **Example:** A `ReportGenerator` that imports from 12 other packages has Ce = 12

### Coupling Interpretation Table

| Ca | Ce | Profile | Risk |
|:--:|:--:|---------|------|
| High | Low | Foundation/library | Stable but painful to change |
| Low | High | Leaf/application | Volatile but safe to change |
| High | High | Hub/bottleneck | Dangerous — fragile AND high-impact |
| Low | Low | Isolated | Low risk but check if it's actually used |

## Derived Metrics

### Instability

```
I = Ce / (Ca + Ce)
```

| I Value | Meaning | Description |
|:-------:|---------|-------------|
| 0.0 | Maximally stable | Only dependents, no dependencies. Foundation code. |
| 0.5 | Balanced | Equal incoming and outgoing. |
| 1.0 | Maximally unstable | Only dependencies, no dependents. Leaf code. |

**Key insight:** Instability is not inherently bad. Leaf code SHOULD be unstable (I near 1) because it can change freely without affecting others. Foundation code SHOULD be stable (I near 0) because many things depend on it. The problem arises when stability doesn't match abstractness (see Distance).

### Abstractness

```
A = sum(abstract_elements) / sum(total_elements)
```

Where abstract elements = interfaces + abstract classes, total elements = all classes/modules.

| A Value | Meaning | Description |
|:-------:|---------|-------------|
| 0.0 | Fully concrete | No interfaces or abstract classes. All implementation. |
| 0.5 | Balanced | Half abstract, half concrete. |
| 1.0 | Fully abstract | All interfaces/abstract classes. No implementations. |

### Distance from Main Sequence

```
D = |A + I - 1|
```

| D Value | Meaning | Description |
|:-------:|---------|-------------|
| 0.0 | On the main sequence | Perfect balance of abstractness and instability. |
| 0.5 | Moderate deviation | Somewhat imbalanced. Worth investigating. |
| 1.0 | Maximum deviation | Severely imbalanced. In a danger zone. |

**Target:** D < 0.3 is generally healthy. D > 0.5 requires investigation.

## The Main Sequence Graph

```
Abstractness (A)
1.0 |  ZONE OF USELESSNESS
    |  (high A, high I)         /
    |  Too abstract,          /
    |  nobody uses it       /
    |                     /
0.5 |                   /  <-- Main Sequence (ideal)
    |                 /
    |               /
    |             /
    |           /    ZONE OF PAIN
    |         /      (low A, low I)
0.0 |       /        Too concrete, hard to change
    +----+----+----+----+----+-> Instability (I)
    0.0  0.2  0.4  0.6  0.8  1.0
```

### Zone of Pain (Bottom-Left Corner)

- **Metrics:** I near 0 (very stable) + A near 0 (very concrete)
- **What it means:** The module has many dependents (stable) but no abstractions (concrete). Changing it forces changes in all dependents. There's no interface to provide flexibility.
- **Common examples:** Utility libraries, core domain models, shared database schemas, configuration classes
- **Symptom:** "We're afraid to touch this because everything breaks"
- **Fix:** Introduce interfaces/abstractions so dependents couple to the interface, not the implementation. This increases A without changing I, moving toward the main sequence.
- **Caveat:** Some zone-of-pain modules are acceptable. The Java String class is concrete (A=0) and maximally stable (Ca=enormous), but it rarely needs to change. Non-volatile concrete libraries can safely live in this zone.

### Zone of Uselessness (Top-Right Corner)

- **Metrics:** I near 1 (very unstable) + A near 1 (very abstract)
- **What it means:** The module is all interfaces with no concrete use, and nobody depends on it. It was probably designed speculatively or is an abandoned abstraction layer.
- **Common examples:** Over-engineered framework interfaces, abandoned plugin systems, "just in case" abstractions
- **Symptom:** "Nobody actually implements this interface"
- **Fix:** Either find concrete uses or delete it. Dead abstractions add cognitive load without value.

## Connascence Taxonomy

### Static Connascence (Source-Level, Weaker)

| Type | Abbreviation | Definition | Example | Refactoring Ease |
|------|:------------:|-----------|---------|:----------------:|
| **Name** | CoN | Components agree on the name of an entity | Method names, variable names | Trivial (IDE rename) |
| **Type** | CoT | Components agree on the type of an entity | Parameter types, return types | Easy (type refactoring) |
| **Meaning** | CoM / CoC | Components agree on the meaning of values | `int TRUE = 1; int FALSE = 0;` or status code conventions | Moderate (replace magic values with named constants) |
| **Position** | CoP | Components agree on the order of values | Parameter order in method calls | Moderate (use named parameters or builder pattern) |
| **Algorithm** | CoA | Components must use the same algorithm | Client and server both use SHA-256 for auth tokens | Hard (algorithm change requires coordinated update) |

### Dynamic Connascence (Runtime, Stronger)

| Type | Abbreviation | Definition | Example | Refactoring Ease |
|------|:------------:|-----------|---------|:----------------:|
| **Execution** | CoE | Order of execution matters | Must call `init()` before `send()` | Hard (requires API redesign) |
| **Timing** | CoT | Timing of execution matters | Race conditions between threads | Very hard (requires synchronization redesign) |
| **Values** | CoV | Multiple values must change together | Distributed transaction: all or nothing | Very hard (may require saga pattern) |
| **Identity** | CoI | Components must reference the same entity | Two services sharing a distributed queue | Very hard (requires shared state management) |

### Connascence Strength Diagram

```
WEAKER (prefer)                                    STRONGER (avoid across boundaries)
    |                                                        |
    Name -> Type -> Meaning -> Position -> Algorithm -> Execution -> Timing -> Values -> Identity
    |<--- Static (compile-time) --->|                  |<--- Dynamic (runtime) ----------->|
    |<--- Easier to detect/fix ---->|                  |<--- Harder to detect/fix -------->|
```

### Connascence Properties

**Strength:** Weaker forms are easier to refactor. Always convert strong connascence to weaker forms when possible.

**Locality:** The same connascence form is more acceptable within a module boundary than across boundaries. Connascence of Meaning within one class is a code smell. Connascence of Meaning across microservices is an architectural crisis.

**Degree:** The number of components affected. Connascence of Values between 2 components is manageable. Between 20 components, it's a systemic problem.

### Three Guidelines for Improving Modularity via Connascence

1. **Minimize overall connascence** by breaking the system into encapsulated elements
2. **Minimize cross-boundary connascence** — coupling that crosses module boundaries should be as weak as possible
3. **Maximize within-boundary connascence** — strong coupling within a cohesive module is fine

### Weirich's Rules

- **Rule of Degree:** Convert strong forms of connascence into weaker forms
- **Rule of Locality:** As the distance between software elements increases, use weaker forms of connascence

## Unifying Coupling and Connascence

Structured Design coupling (afferent/efferent) and connascence are complementary views:
- **Coupling** tells you HOW MUCH coupling exists (Ca/Ce counts)
- **Connascence** tells you WHAT KIND of coupling exists (how they're coupled)

Both are needed for a complete picture. High Ca with CoN (name-based coupling) is far less concerning than moderate Ca with CoV (value-based coupling across a distributed system).

## Practical Tooling

| Language | Coupling Analysis | LCOM Analysis | Connascence |
|----------|------------------|---------------|-------------|
| Java | JDepend, SonarQube, ArchUnit | SonarQube LCOM4, Checkstyle | Manual / code review |
| .NET | NDepend, SonarQube | NDepend LCOM | Manual / code review |
| Python | import analysis, pydeps | Manual (dynamic typing limits) | Manual / code review |
| JavaScript/TypeScript | madge, dependency-cruiser | ESLint complexity rules | Manual / code review |
| Go | go vet, staticcheck | Manual (composition over inheritance) | Manual / code review |
| General | Graphviz for dependency visualization | Structural analysis from imports | Always requires human judgment |


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