
Code Modularization Evaluator
- 430 installs
- 3 repo stars
- Updated January 23, 2026
- dotneet/claude-code-marketplace
code-modularization-evaluator is a Claude Code skill that assesses code modularization using the Balanced Coupling Model, analyzing coupling strength, connascence types, and distance to recommend refactoring before merge
About
code-modularization-evaluator is a Claude Code skill (version 1.0.0) from dotneet/claude-code-marketplace that evaluates module boundaries using Vlad Khononov's Balanced Coupling Model. It scores integration strength across four levels (intrusive through contract), distance across seven scopes, and volatility via DDD subdomain classification, then maps nine connascence types from name through identity. Red flags include CBO above 14, circular module dependencies, and intrusive cross-service database access. Output follows a structured assessment with coupling tables, connascence issues, and a prioritized refactoring plan. Reach for it before merging large refactors or designing new service boundaries.
- Cohesion and coupling checks
- Boundary clarity scoring
- Refactor risk assessment
- Testability impact review
Code Modularization Evaluator by the numbers
- 430 all-time installs (skills.sh)
- Ranked #251 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dotneet/claude-code-marketplace --skill code-modularization-evaluatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 430 |
|---|---|
| repo stars | ★ 3 |
| Last updated | January 23, 2026 |
| Repository | dotneet/claude-code-marketplace ↗ |
How do you evaluate module coupling before refactoring?
Assess whether a codebase module split improves cohesion, boundaries, and testability before merging a refactor.
Who is it for?
Senior developers reviewing architecture refactors or service splits who need a structured coupling assessment with actionable recommendations before merge.
Skip if: Skip code-modularization-evaluator when you need runtime profiling, security auditing, or lint-style style checks—those require performance, security, or static-analysis tools.
When should I use this skill?
User asks to evaluate modularization, review coupling between modules, assess refactor boundaries, or check for distributed monolith patterns.
What you get
Modularization assessment with coupling analysis table, connascence issues list, and prioritized refactoring plan.
- Modularization assessment report
- Coupling analysis table
- Prioritized refactoring plan
By the numbers
- Skill version 1.0.0
- Nine connascence types across static and dynamic categories
- Three reference files: connascence-types, coupling-metrics, refactoring-patterns
Files
Code Modularization Evaluator
Evaluate code modularization using the Balanced Coupling Model from Vlad Khononov's "Balancing Coupling in Software Design." This skill helps identify problematic coupling patterns and provides actionable refactoring guidance.
Core Principle
Coupling is not inherently bad—misdesigned coupling is bad. The goal is balanced coupling, not zero coupling.
The fundamental formula:
MODULARITY = (STRENGTH XOR DISTANCE) OR NOT VOLATILITYA system achieves modularity when:
- High integration strength components are close together (same module/service)
- Low integration strength components can be far apart (different services)
- Low volatility components can tolerate coupling mismatches
The Three Dimensions of Coupling
Always evaluate coupling across these three dimensions:
1. Integration Strength (What knowledge is shared?)
From strongest (worst) to weakest (best):
| Level | Type | Description | Example |
|---|---|---|---|
| 1 | Intrusive | Using non-public interfaces | Direct database access to another service, reflection on private fields |
| 2 | Functional | Sharing business logic/rules | Same validation duplicated in two places, order-dependent operations |
| 3 | Model | Sharing domain models | Two services using identical entity definitions |
| 4 | Contract | Only explicit interfaces | Well-designed APIs, DTOs, protocols |
2. Distance (How far does knowledge travel?)
From closest to most distant: 1. Methods within same class 2. Classes within same file 3. Classes in same namespace/package 4. Modules in different namespaces 5. Separate services/microservices 6. Services owned by different teams 7. Different systems/organizations
3. Volatility (How often will it change?)
Use Domain-Driven Design subdomain classification:
- Core subdomains: High volatility (competitive advantage, frequent changes)
- Supporting subdomains: Low volatility (necessary but not differentiating)
- Generic subdomains: Low volatility (solved problems, stable)
Decision Framework
When evaluating code, apply this matrix:
| Integration Strength | Distance | Result |
|---|---|---|
| High | High | ❌ COMPLEXITY (Distributed monolith) |
| Low | Low | ❌ COMPLEXITY (Unnecessary abstraction) |
| High | Low | ✅ MODULARITY (Related things together) |
| Low | High | ✅ MODULARITY (Independent components apart) |
Exception: If volatility is LOW, coupling mismatches are acceptable.
Connascence Analysis
Use connascence to identify specific coupling types. See references/connascence-types.md for detailed examples.
Static Connascence (Compile-time, easier to fix)
Ordered weakest to strongest: 1. Name (CoN): Components agree on names 2. Type (CoT): Components agree on types 3. Meaning (CoM): Components agree on value meanings (magic numbers) 4. Position (CoP): Components agree on order of values 5. Algorithm (CoA): Components share algorithm logic
Dynamic Connascence (Runtime, harder to detect)
Ordered weakest to strongest: 6. Execution (CoE): Order of method calls matters 7. Timing (CoTm): Timing of execution matters 8. Value (CoV): Multiple values must change together 9. Identity (CoI): Must reference same instance
Connascence Rules
1. Minimize overall connascence 2. Minimize connascence crossing module boundaries 3. Maximize connascence within module boundaries 4. Convert stronger connascence to weaker forms 5. As distance increases, connascence should weaken
Evaluation Checklist
When analyzing code, check for:
Red Flags (Immediate Action Required)
- [ ] Direct database access to another service's data (Intrusive coupling)
- [ ] Reflection to access private fields
- [ ] Business logic duplicated across services
- [ ] Microservices requiring synchronized deployments
- [ ] CBO (Coupling Between Objects) > 14 for a class
- [ ] Instability index 0.3-0.7 for frequently-changing modules
- [ ] Circular dependencies between modules
Warning Signs (Investigate Further)
- [ ] Magic numbers/values shared between components (CoM)
- [ ] Position-dependent parameters in APIs (CoP)
- [ ] Algorithm logic duplicated in multiple places (CoA)
- [ ] Methods must be called in specific order (CoE)
- [ ] Long method chains:
a.b().c().d()(Law of Demeter violation) - [ ] Classes with "Manager", "Helper", "Utility" doing too much
Healthy Patterns
- [x] Contract-based integration between services
- [x] DTOs that truly abstract internal models
- [x] High cohesion within modules
- [x] Single responsibility per class
- [x] Dependency injection for external dependencies
Refactoring Strategies
By Integration Strength Problem
Intrusive → Contract Coupling: 1. Identify all direct dependencies on implementation details 2. Define explicit interface/contract 3. Create adapter layer 4. Route all access through adapter
Functional → Model Coupling: 1. Extract shared business logic to dedicated module 2. Define clear ownership 3. Consume via explicit dependency
Model → Contract Coupling: 1. Create integration-specific DTOs 2. Map between internal models and DTOs at boundaries 3. Version contracts independently of models
By Connascence Type
| From | To | Technique |
|---|---|---|
| CoM (Meaning) | CoN (Name) | Replace magic values with named constants/enums |
| CoP (Position) | CoN (Name) | Use named parameters, builder pattern, or parameter objects |
| CoA (Algorithm) | CoN (Name) | Extract algorithm to single location, reference by name |
| CoT (Type) | CoN (Name) | Use duck typing or interfaces |
| CoE (Execution) | Explicit | Use state machines, builder pattern, or constructor injection |
| CoI (Identity) | Explicit | Use dependency injection with explicit wiring |
By Distance Problem
High Strength + High Distance (Distributed Monolith):
- Option A: Reduce distance—merge services/modules
- Option B: Reduce strength—introduce contracts, async messaging
Low Strength + Low Distance (Over-abstraction):
- Remove unnecessary abstraction layers
- Inline overly generic code
- Combine closely-related classes
Analysis Workflow
When asked to evaluate code modularization:
1. Map the component structure
- Identify modules, services, classes
- Draw dependency graph
2. Assess Integration Strength
- For each dependency, classify: Intrusive/Functional/Model/Contract
- Flag high-strength cross-boundary dependencies
3. Measure Distance
- Note component locations (same file → different systems)
- Identify team/ownership boundaries
4. Evaluate Volatility
- Classify each component's subdomain type
- Note historically frequently-changed areas
5. Apply the formula
- Check: Does strength match distance appropriately?
- Does volatility excuse any mismatches?
6. Identify Connascence
- Scan for specific connascence types
- Prioritize: high strength + low locality + high degree
7. Recommend actions
- Prioritize by impact and effort
- Provide specific refactoring techniques
Output Format
Structure your evaluation as:
## Modularization Assessment
### Summary
[Brief overview of coupling health]
### Component Map
[Describe module/service structure]
### Coupling Analysis
| Component Pair | Strength | Distance | Volatility | Balance |
|---------------|----------|----------|------------|---------|
| A → B | Model | High | High | ❌ |
### Connascence Issues
1. [Specific connascence type]: [Location] - [Impact]
### Recommendations
1. **Priority 1**: [Action] - [Rationale]
2. **Priority 2**: [Action] - [Rationale]
### Refactoring Plan
[Step-by-step approach for highest-priority item]References
- For detailed connascence examples: see
references/connascence-types.md - For coupling metrics: see
references/coupling-metrics.md - For refactoring patterns: see
references/refactoring-patterns.md
Limitations
- Cannot assess runtime behavior without execution context
- Volatility assessment requires domain knowledge
- Team/organizational distance requires project context
- Historical change frequency not available from static analysis alone
Connascence Types: Detailed Examples
Static Connascence
Connascence of Name (CoN) - Weakest
Components must agree on the name of an entity.
# If deliver() is renamed, all callers must update
class Mailer:
def deliver(self, message):
pass
mailer = Mailer()
mailer.deliver(message) # Coupled to name "deliver"Impact: Low - IDE refactoring handles this easily Action: Generally acceptable; use consistent naming conventions
---
Connascence of Type (CoT)
Components must agree on the type of an entity.
# BAD: Strict type coupling
def average(values: list) -> float:
return sum(values) / len(values)
# BETTER: Duck typing reduces to CoN
def average(values):
"""Works with any iterable supporting sum() and len()"""
return sum(values) / len(values)Impact: Medium - Changes require updating type annotations Action: Use interfaces/protocols; prefer duck typing where appropriate
---
Connascence of Meaning (CoM) - Magic Values
Components must agree on the meaning of specific values.
# BAD: Magic number coupling
def get_user_role(user):
if user.is_admin:
return 0 # What does 0 mean?
return 2
if get_user_role(user) == 0: # Must know 0 = admin
grant_access()
# GOOD: Named constant (reduces to CoN)
class Role:
ADMIN = "admin"
USER = "user"
def get_user_role(user):
return Role.ADMIN if user.is_admin else Role.USER
if get_user_role(user) == Role.ADMIN:
grant_access()Impact: High - Silent bugs when meanings diverge Action: Replace magic values with named constants, enums, or types
---
Connascence of Position (CoP)
Components must agree on the order of values.
# BAD: Position-dependent
def create_user(first, last, age, email, admin):
pass
create_user("John", "Doe", 30, "john@example.com", True)
# Easy to mix up parameters
# GOOD: Named parameters or object (reduces to CoN)
@dataclass
class UserData:
first_name: str
last_name: str
age: int
email: str
is_admin: bool
def create_user(data: UserData):
pass
# Or use keyword arguments
create_user(first="John", last="Doe", age=30,
email="john@example.com", admin=True)Impact: High - Silent bugs from parameter order mistakes Action: Use named parameters, builder pattern, or parameter objects
---
Connascence of Algorithm (CoA) - Strongest Static
Components must agree on a particular algorithm.
# BAD: Algorithm duplicated
class PasswordService:
def hash_password(self, password):
return hashlib.sha256(password.encode()).hexdigest()
class AuthService:
def verify_password(self, password, stored_hash):
# Algorithm duplicated - must stay in sync!
return hashlib.sha256(password.encode()).hexdigest() == stored_hash
# GOOD: Single algorithm location (reduces to CoN)
class PasswordHasher:
@staticmethod
def hash(value: str) -> str:
return hashlib.sha256(value.encode()).hexdigest()
class PasswordService:
def hash_password(self, password):
return PasswordHasher.hash(password)
class AuthService:
def verify_password(self, password, stored_hash):
return PasswordHasher.hash(password) == stored_hashImpact: Very High - Algorithm changes break dependent code Action: Extract shared algorithms to single, well-tested location
---
Dynamic Connascence
Connascence of Execution (CoE) - Weakest Dynamic
Order of method execution matters.
# BAD: Implicit order dependency
email = Email()
email.set_recipient("user@example.com")
email.set_sender("me@example.com")
email.send()
email.set_subject("Hello") # Too late! Already sent
# GOOD: Constructor enforces required fields
email = Email(
recipient="user@example.com",
sender="me@example.com",
subject="Hello"
)
email.send()
# Or use builder pattern
email = EmailBuilder()
.recipient("user@example.com")
.sender("me@example.com")
.subject("Hello")
.build() # Validates all required fields
.send()Impact: High - Runtime errors from wrong order Action: Use constructors, builders, or state machines to enforce order
---
Connascence of Timing (CoTm)
Timing of execution matters.
# BAD: Timing dependency
cache.write("session", data)
time.sleep(61) # Cache expires after 60 seconds
data = cache.read("session") # Returns None - expired!
# Common scenarios:
# - Database connection timeouts
# - Race conditions in concurrent code
# - Eventual consistency windowsImpact: Very High - Intermittent, hard-to-reproduce bugs Action: Make timing explicit; use async/await, promises, locks appropriately
---
Connascence of Value (CoV)
Multiple values must change together.
# BAD: Values must stay consistent
class Rectangle:
def __init__(self):
self.width = 10
self.height = 5
self.area = 50 # Must equal width * height!
def set_width(self, w):
self.width = w
# Forgot to update area!
# GOOD: Compute derived values
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
return self.width * self.height # Always consistentImpact: Very High - Data inconsistency bugs Action: Compute derived values; use invariant-preserving methods
---
Connascence of Identity (CoI) - Strongest
Components must reference the same instance.
# BAD: Implicit shared identity
class Publisher:
def __init__(self):
self.queue = Queue()
def publish(self, msg):
self.queue.put(msg)
class Subscriber:
def __init__(self, publisher):
self._pub = publisher
def consume(self):
return self._pub.queue.get() # Depends on same Queue instance
# GOOD: Explicit dependency injection
class Publisher:
def __init__(self, queue: Queue):
self._queue = queue
def publish(self, msg):
self._queue.put(msg)
class Subscriber:
def __init__(self, queue: Queue):
self._queue = queue
def consume(self):
return self._queue.get()
# Wiring is explicit
shared_queue = Queue()
publisher = Publisher(shared_queue)
subscriber = Subscriber(shared_queue)Impact: Highest - Hidden dependencies, testing nightmares Action: Make identity dependencies explicit through dependency injection
---
Connascence Strength Hierarchy
WEAKEST (easiest to refactor)
│
├── STATIC
│ ├── 1. Name (CoN)
│ ├── 2. Type (CoT)
│ ├── 3. Meaning (CoM)
│ ├── 4. Position (CoP)
│ └── 5. Algorithm (CoA)
│
├── DYNAMIC
│ ├── 6. Execution (CoE)
│ ├── 7. Timing (CoTm)
│ ├── 8. Value (CoV)
│ └── 9. Identity (CoI)
│
STRONGEST (hardest to refactor)Rule: Static connascence is always weaker than dynamic because it can be detected by examining source code.
Coupling Metrics and Thresholds
Primary Metrics
CBO (Coupling Between Objects)
Count of unique classes this class is coupled to via:
- Method calls
- Field access
- Inheritance
- Parameter types
- Return types
- Exception types
| Range | Assessment |
|---|---|
| 0-8 | Healthy |
| 9-14 | Warning |
| >14 | Critical - refactor |
Afferent Coupling (Ca)
How many OTHER classes depend ON this class.
- High Ca = high responsibility, changes affect many
- Appropriate for stable infrastructure (logging, utils)
Efferent Coupling (Ce)
How many classes THIS class depends on.
- High Ce = high dependency, vulnerable to changes
- Should be low for stable classes
Instability Index
I = Ce / (Ce + Ca)| Value | Meaning |
|---|---|
| 0.0 | Maximally stable (high Ca, low Ce) |
| 1.0 | Maximally unstable (low Ca, high Ce) |
| 0.3-0.7 | "Zone of Pain" - avoid for frequently-changing code |
Stable Abstractions Principle: Stable packages (I→0) should be abstract. Unstable packages (I→1) should be concrete.
Measurement Tools
- Java: JDepend, ckjm, Structure101
- .NET: NDepend
- Multi-language: SonarQube
- PHP: PHPDepend
Quick Assessment Heuristics
| Indicator | Threshold | Action |
|---|---|---|
| Method parameters | >5 | Create parameter object |
| Import statements | >15 | Split class responsibilities |
| Class lines | >500 | Extract classes |
| Public methods | >20 | Consider splitting interface |
| Inheritance depth | >4 | Prefer composition |
Refactoring Patterns for Coupling Reduction
Pattern: Extract Contract
When: High model coupling between services
# BEFORE: Services share domain model
# Service A
class Order:
customer: Customer
items: List[OrderItem]
internal_status: str # Internal detail
# Service B imports and uses Order directly
# AFTER: Contract coupling via DTO
# Shared contract
@dataclass
class OrderDTO:
customer_id: str
item_ids: List[str]
status: str
# Service A
class OrderService:
def get_order(self, id) -> OrderDTO:
order = self._repository.find(id)
return OrderDTO(
customer_id=order.customer.id,
item_ids=[i.id for i in order.items],
status=self._map_status(order.internal_status)
)Pattern: Introduce Facade
When: High efferent coupling from orchestration
# BEFORE: Client couples to many subsystems
client.subsystem_a.operation1()
client.subsystem_b.operation2()
client.subsystem_c.operation3()
# AFTER: Single facade reduces coupling
class Facade:
def unified_operation(self):
self._a.operation1()
self._b.operation2()
self._c.operation3()
client.facade.unified_operation()Pattern: Replace Inheritance with Composition
When: Inheritance creates tight coupling
# BEFORE: Inheritance coupling
class Animal:
def move(self): pass
class Bird(Animal):
def move(self):
self.fly()
class Penguin(Bird): # Problem: penguins can't fly!
def move(self):
self.swim() # Breaks Liskov Substitution
# AFTER: Composition
class Animal:
def __init__(self, movement_strategy):
self._movement = movement_strategy
def move(self):
self._movement.move()
penguin = Animal(SwimmingStrategy())
eagle = Animal(FlyingStrategy())Pattern: Dependency Injection
When: Content/common coupling via direct instantiation
# BEFORE: Hardcoded dependency
class OrderProcessor:
def __init__(self):
self._repository = MySQLRepository() # Tight coupling
def process(self, order):
self._repository.save(order)
# AFTER: Injected dependency
class OrderProcessor:
def __init__(self, repository: Repository):
self._repository = repository
def process(self, order):
self._repository.save(order)
# Wiring
processor = OrderProcessor(MySQLRepository())
# Or for testing
test_processor = OrderProcessor(InMemoryRepository())Pattern: Event-Driven Decoupling
When: Functional coupling requiring synchronous communication
# BEFORE: Direct coupling
class OrderService:
def __init__(self, inventory_service, notification_service):
self._inventory = inventory_service
self._notifications = notification_service
def place_order(self, order):
self._inventory.reserve(order.items) # Sync call
self._notifications.send(order.customer) # Sync call
# AFTER: Event-driven
class OrderService:
def __init__(self, event_bus):
self._events = event_bus
def place_order(self, order):
self._events.publish(OrderPlaced(order))
# Inventory and Notification services subscribe independentlyRelated skills
How it compares
Pick code-modularization-evaluator for pre-merge architecture coupling review; pick lint or security skills for style rules or vulnerability scanning.
FAQ
What model does code-modularization-evaluator use?
code-modularization-evaluator applies the Balanced Coupling Model from Vlad Khononov's 'Balancing Coupling in Software Design.' It evaluates integration strength, distance, and volatility—not zero coupling, but balanced coupling.
What red flags does code-modularization-evaluator detect?
code-modularization-evaluator flags direct cross-service database access, CBO above 14, circular module dependencies, duplicated business logic across services, and microservices requiring synchronized deployments.
What output does code-modularization-evaluator produce?
code-modularization-evaluator outputs a Modularization Assessment with a coupling analysis table, connascence issues, prioritized recommendations, and a step-by-step refactoring plan for the highest-priority item.