Skip to content

Implement circular dependency quality check with dependency inversion enforcement #64

Description

@devill

Problem

Circular dependencies create maintenance challenges and can indicate poor architectural design. RefakTS currently lacks automated detection for:

  1. File-level circular dependencies - Files that import each other directly or indirectly
  2. Directory-level circular dependencies - Directories that depend on each other
  3. Class-level circular dependencies - Classes with circular references

These dependencies can lead to:

  • Build issues and import ordering problems
  • Testing difficulties and mocking complexity
  • Tight coupling that makes refactoring harder
  • Architectural erosion over time

Proposed Solution

Create a comprehensive circular dependency quality check that:

Detection Levels

1. File-Level Circular Dependencies

❌ BAD: A.ts → B.ts → C.ts → A.ts
✅ GOOD: A.ts → B.ts → C.ts (no cycles)

2. Directory-Level Circular Dependencies

❌ BAD: 
src/core/commands/ → src/core/services/ → src/core/commands/
src/core/ → src/command-line-parser/ → src/core/

✅ GOOD: Hierarchical dependencies only

3. Class-Level Circular Dependencies

// ❌ BAD: Circular class dependencies
class A {
  constructor(private b: B) {}
}
class B {
  constructor(private a: A) {}
}

// ✅ GOOD: Dependency inversion
interface IB { doSomething(): void; }
class A {
  constructor(private b: IB) {}
}
class B implements IB {
  doSomething(): void {}
}

Dependency Inversion Guidance

When circular dependencies are detected, suggest dependency inversion solutions:

  • Extract interfaces to break circular references
  • Introduce abstractions at dependency boundaries
  • Use dependency injection patterns
  • Apply observer patterns for loose coupling

Implementation Approach

Detection Algorithm

  1. Build dependency graph from import/export analysis
  2. Apply cycle detection (e.g., depth-first search with cycle tracking)
  3. Report circular paths with specific file/class chains
  4. Suggest solutions based on dependency inversion patterns

Directory-Level Analysis

Treat each directory as a logical unit and detect cycles at the directory level:

src/core/commands/ ↔ src/core/services/     # ❌ Circular
src/core/ ↔ src/command-line-parser/       # ❌ Circular  
src/core/ → src/command-line-parser/       # ✅ Unidirectional

Quality Check Output

🚨 Circular Dependencies Detected:

File-level cycles:
  • src/core/ast/location-range.ts → src/core/services/ast-service.ts → src/core/ast/location-range.ts

Directory-level cycles:  
  • src/core/commands/ ↔ src/core/services/

Suggested fixes:
  • Extract interface from ASTService to break location-range cycle
  • Move shared abstractions to src/core/interfaces/

Advanced Features (Optional Discussion)

Explicit Dependency Direction Enforcement

Question for consideration: Should we enforce specific dependency directions?

Examples:

  • Commands → Services → AST (never reverse)
  • Core → CLI (never CLI → Core)
  • Tests → Source (never Source → Tests)

Benefits: Clearer architecture, prevention of architectural drift
Drawbacks: May be overly restrictive, harder to implement

Recommendation: Start with cycle detection, consider direction enforcement later if needed.

Implementation Steps

  1. Build dependency graph analyzer
    • Parse import/export statements
    • Track file-to-file dependencies
    • Group files by directory
  2. Implement cycle detection algorithms
    • File-level cycle detection
    • Directory-level cycle detection
    • Class-level dependency analysis
  3. Create quality check integration
    • Integrate with existing quality check system
    • Generate actionable error messages
    • Suggest dependency inversion solutions
  4. Add configuration options
    • Enable/disable different levels of checking
    • Configure directory grouping rules
    • Set cycle detection depth limits

Testing Strategy

Test Cases Needed

  • Simple circular imports (A → B → A)
  • Complex circular chains (A → B → C → D → A)
  • Directory-level cycles with multiple files
  • Valid dependency hierarchies (should not trigger)
  • Dependency inversion examples (should not trigger)

Integration Points

  • Post-commit hooks - Detect cycles in changed files
  • CI/CD pipeline - Prevent merging cycle-introducing changes
  • Development workflow - Real-time feedback during development
  • Architecture reviews - Generate dependency reports

Priority

Medium - Architectural quality improvement that prevents technical debt accumulation.

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    DiscussionIssues where community input is encouraged to help refine the ideaQuality ChecksTasks that add to post-commit quality check system

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions