-
Notifications
You must be signed in to change notification settings - Fork 29
Description
feat: Implement SeparationOfConcernsAssessor
Attribute Definition
Attribute ID: separation_of_concerns (Attribute #17 - Tier 2)
Definition: Organizing code so each module/file/function has single, well-defined responsibility (SOLID principles).
Why It Matters: 2 of 5 SOLID principles derive directly from separation of concerns. Clear boundaries improve testability, maintainability, and reduce cognitive load.
Impact on Agent Behavior:
- Targeted modifications without affecting unrelated code
- Better refactoring suggestions
- Clearer module purpose understanding
- Reduced side effect risk
Measurable Criteria:
- Each module/class has one reason to change
- High cohesion within modules (related functions together)
- Low coupling between modules (minimal dependencies)
- Organize by feature/domain, not technical layer (avoid separate "controllers", "services", "models" directories)
Implementation Requirements
File Location: src/agentready/assessors/structure.py
Class Name: SeparationOfConcernsAssessor
Tier: 2 (Critical)
Default Weight: 0.03 (3% of total score)
Assessment Logic
Scoring Approach: Heuristic checks for common anti-patterns
Evidence to Check (score components):
-
Directory organization (40%)
- Feature-based structure (good): auth/, users/, billing/
- Layer-based structure (bad): models/, views/, controllers/
- Check for directories named: models, views, controllers, services, utils, helpers
-
File length as cohesion indicator (30%)
- Files >500 lines likely have multiple responsibilities
- Count files exceeding threshold
- Penalize repositories with many large files
-
Import analysis (30%)
- Check for circular dependencies (Python)
- Count cross-module imports (high coupling)
- Look for "God modules" imported by many others
Scoring Logic:
org_score = 100 if feature_based else 60
length_score = 100 - (oversized_files / total_files) * 100
import_score = 100 - (circular_deps * 20) # Each circular dep -20
total_score = (org_score * 0.4) + (length_score * 0.3) + (import_score * 0.3)
status = "pass" if total_score >= 75 else "fail"Anti-Patterns to Detect:
- Directories: models/, views/, controllers/, services/, utils/
- Files: utils.py, helpers.py, common.py (catch-all modules)
- Large files: >500 lines
- Circular imports (Python)
Code Pattern to Follow
Reference: StandardLayoutAssessor in structure.py
Pattern:
- Examine directory structure for layer-based anti-patterns
- Check file sizes across repository
- For Python: Parse imports to detect circular dependencies
- Calculate score based on multiple factors
- Provide actionable remediation
Example Finding Responses
Pass (Score: 88)
Finding(
attribute=self.attribute,
status="pass",
score=88.0,
measured_value="feature-based organization",
threshold="feature-based with cohesive modules",
evidence=[
"Feature-based directory structure detected",
"Average file length: 187 lines (good cohesion)",
"2/45 files exceed 500 lines (acceptable)",
"No circular dependencies detected",
],
remediation=None,
error_message=None,
)Fail (Score: 52)
Finding(
attribute=self.attribute,
status="fail",
score=52.0,
measured_value="layer-based organization",
threshold="feature-based with cohesive modules",
evidence=[
"Layer-based directories detected: models/, views/, controllers/",
"8/45 files exceed 500 lines (poor cohesion)",
"Catch-all modules found: utils.py, helpers.py",
"2 circular import cycles detected",
],
remediation=self._create_remediation(),
error_message=None,
)Not Applicable
Finding.not_applicable(
self.attribute,
reason="Cannot assess: insufficient code files (<5)"
)Registration
Add to src/agentready/services/scanner.py in create_all_assessors():
from ..assessors.structure import (
StandardLayoutAssessor,
GitignoreCompletenessAssessor,
OneCommandSetupAssessor,
SeparationOfConcernsAssessor, # Add this import
)
def create_all_assessors() -> List[BaseAssessor]:
return [
# ... existing assessors ...
SeparationOfConcernsAssessor(), # Add this line
]Testing Guidance
Test File: tests/unit/test_assessors_structure.py
Test Cases to Add:
test_separation_pass_feature_based: Feature-organized repo scores welltest_separation_fail_layer_based: Layer-organized repo failstest_separation_fail_large_files: Repository with many 500+ line filestest_separation_detect_circular_imports: Python repo with circular importstest_separation_not_applicable: Repository with <5 code files
Note: AgentReady uses feature-based organization (assessors/, models/, services/), should score well.
Dependencies
External Tools: None (uses file system inspection and AST parsing)
Python Standard Library:
pathlib.Pathfor directory inspectionastfor import analysis (Python only)os.walk()for recursive file traversal
Remediation Steps
def _create_remediation(self) -> Remediation:
return Remediation(
summary="Refactor code to improve separation of concerns",
steps=[
"Reorganize from layer-based to feature-based structure",
"Break down large files (>500 lines) into focused modules",
"Extract catch-all modules (utils, helpers) into specific domains",
"Eliminate circular dependencies",
"Group related functionality together",
"Apply Single Responsibility Principle to modules",
],
tools=[],
commands=[
"# Find large files",
"find src/ -name '*.py' -exec wc -l {} + | sort -rn | head -20",
"",
"# Detect circular imports (Python)",
"pip install pydeps",
"pydeps src/ --show-cycles",
],
examples=[
"""# Good: Feature-based organization
src/
├── auth/
│ ├── login_service.py
│ ├── oauth_provider.py
│ └── session_manager.py
├── users/
│ ├── user_model.py
│ ├── user_service.py
│ └── user_repository.py
└── billing/
├── payment_processor.py
└── invoice_generator.py
""",
"""# Bad: Layer-based organization
src/
├── models/
│ ├── user.py
│ ├── order.py
│ └── payment.py
├── services/
│ ├── user_service.py
│ ├── order_service.py
│ └── payment_service.py
└── utils/
└── helpers.py # Catch-all
""",
],
citations=[
Citation(
source="Wikipedia",
title="Separation of concerns",
url="https://en.wikipedia.org/wiki/Separation_of_concerns",
relevance="Foundational principle of software design",
),
Citation(
source="DevIQ",
title="Separation of Concerns",
url="https://deviq.com/principles/separation-of-concerns",
relevance="Practical guide to applying SoC",
),
],
)Implementation Notes
- Directory Detection: Check for common layer-based directory names
- File Length: Calculate via line count, threshold at 500 lines
- Import Analysis: Parse Python imports with AST, build dependency graph
- Circular Dependencies: Use graph traversal to detect cycles
- Catch-all Modules: Flag files named utils.py, helpers.py, common.py
- Edge Cases: Small repositories (<5 files) return not_applicable
- Language-Specific: Full import analysis only for Python, heuristics for others