Architecture System Design - hiraishikentaro/rails-factorybot-jump GitHub Wiki

Architecture: System Design

Overall Architecture Pattern

Rails FactoryBot Jump follows a provider-based architecture with event-driven updates and layered separation of concerns. The design emphasizes performance, maintainability, and seamless integration with VSCode's extension ecosystem.

graph TB
    subgraph "VSCode Extension Host"
        A[Extension Entry Point] --> B[Provider Registration]
        A --> C[Command Registration]
        A --> D[File System Watcher]
    end

    subgraph "Core Logic Layer"
        E[FactoryLinkProvider] --> F[Cache Manager]
        E --> G[Pattern Detector]
        E --> H[Link Generator]
    end

    subgraph "Data Layer"
        I[Factory Cache]
        J[Trait Cache]
        K[File Cache]
    end

    subgraph "External Systems"
        L[File System]
        M[VSCode APIs]
        N[Ruby Factory Files]
    end

    B --> E
    F --> I
    F --> J
    F --> K
    G --> N
    D --> L
    H --> M

Design Principles

1. Single Responsibility Principle

Each component has one clear purpose:

  • Extension: Lifecycle and VSCode integration
  • Provider: Document link generation
  • Cache Manager: Factory definition storage and retrieval
  • Pattern Detector: Text analysis and regex matching

2. Separation of Concerns

Clear boundaries between:

  • Platform Integration (VSCode APIs)
  • Business Logic (factory detection and navigation)
  • Data Management (caching and file system)

3. Event-Driven Architecture

Reactive updates through:

  • File System Events → Cache invalidation
  • Configuration Changes → Provider reconfiguration
  • User Interactions → Navigation commands

Source: src/extension.ts#L28-L41

Layered Architecture

1. Presentation Layer (VSCode Integration)

Extension Entry Point (src/extension.ts):

  • Manages extension lifecycle (activation/deactivation)
  • Registers providers and commands with VSCode
  • Sets up file system watching
  • Handles cross-cutting concerns

Responsibilities:

  • VSCode API integration
  • Resource management
  • Event coordination
  • Extension configuration

2. Business Logic Layer (Core Functionality)

FactoryLinkProvider (src/providers/factoryLinkProvider.ts):

  • Implements VSCode DocumentLinkProvider interface
  • Orchestrates factory detection and link generation
  • Manages configuration changes
  • Coordinates cache operations

Pattern Detection Engine:

  • Regex-based factory call detection
  • Multi-format support (parentheses/non-parentheses)
  • Factory and trait recognition
  • Line-precise matching

3. Data Access Layer (Caching System)

Cache Architecture:

// Simplified cache structure
class CacheSystem {
  factoryCache: Map<string, FactoryDefinition>;
  traitCache: Map<string, TraitDefinition>;
  fileCache: Map<string, vscode.Uri>;
}

Cache Operations:

  • Read: O(1) lookup by factory/trait name
  • Write: Batch updates on file changes
  • Invalidate: Targeted invalidation on specific file changes
  • Refresh: Complete rebuild when needed

Source: src/providers/factoryLinkProvider.ts

Component Interaction Patterns

1. Initialization Flow

sequenceDiagram
    participant VSCode
    participant Extension
    participant Provider
    participant Cache
    participant FileSystem

    VSCode->>Extension: activate(context)
    Extension->>Provider: new FactoryLinkProvider()
    Extension->>VSCode: registerDocumentLinkProvider(provider)
    Extension->>FileSystem: createFileSystemWatcher()
    Note over Provider: Lazy initialization
    VSCode->>Provider: provideDocumentLinks()
    Provider->>Cache: initializeFactoryFiles()
    Cache->>FileSystem: findFiles(factoryPaths)
    FileSystem-->>Cache: factory file URIs
    Cache->>Cache: parseFactoryDefinitions()

2. Link Generation Flow

sequenceDiagram
    participant User
    participant VSCode
    participant Provider
    participant Detector
    participant Cache

    User->>VSCode: hover over factory call
    VSCode->>Provider: provideDocumentLinks(document)
    Provider->>Detector: detectFactoryCalls(text)
    Detector-->>Provider: factory call ranges
    loop for each factory call
        Provider->>Cache: lookup(factoryName)
        Cache-->>Provider: factory definition
        Provider->>Provider: createDocumentLink()
    end
    Provider-->>VSCode: DocumentLink[]
    VSCode-->>User: show clickable links

3. Cache Update Flow

sequenceDiagram
    participant FileSystem
    participant Watcher
    participant Provider
    participant Cache

    FileSystem->>Watcher: file change event
    Watcher->>Provider: initializeFactoryFiles()
    Provider->>Cache: clearAffectedEntries()
    Provider->>FileSystem: readChangedFiles()
    FileSystem-->>Provider: file contents
    Provider->>Cache: updateDefinitions()
    Cache->>Cache: rebuildIndex()

Design Patterns

1. Provider Pattern

Intent: Encapsulate the algorithm for generating document links.

Implementation:

class FactoryLinkProvider implements vscode.DocumentLinkProvider {
  provideDocumentLinks(document: vscode.TextDocument): vscode.DocumentLink[];
}

Benefits:

  • Clean separation from VSCode integration
  • Testable business logic
  • Swappable implementations

2. Observer Pattern

Intent: Reactive updates when factory files change.

Implementation:

  • File System Watcher observes file changes
  • Provider reacts to changes by updating caches
  • VSCode automatically refreshes links

Benefits:

  • Real-time updates
  • Loose coupling between components
  • Efficient resource utilization

3. Cache-Aside Pattern

Intent: Application manages cache separately from data source.

Implementation:

  • Application checks cache first
  • On cache miss, loads from file system
  • Updates cache with new data
  • Cache invalidation on file changes

Benefits:

  • Performance optimization
  • Explicit cache control
  • Flexibility in caching strategies

4. Command Pattern

Intent: Encapsulate navigation requests as objects.

Implementation:

vscode.commands.registerCommand(
  "rails-factorybot-jump.gotoLine",
  async (args: { uri: string; lineNumber: number }) => {
    // Navigation logic
  }
);

Benefits:

  • Uniform command interface
  • Parameter passing
  • Integration with VSCode command system

Source: src/extension.ts#L14-L26

Error Handling Strategy

1. Graceful Degradation

Philosophy: Continue providing value even when some features fail.

Implementation:

  • Missing factory files → Continue with available files
  • Parse errors → Skip problematic definitions
  • Permission issues → Work with accessible files

2. Defensive Programming

Strategy: Assume external systems may fail.

Implementation:

  • Null checks for file operations
  • Try-catch blocks around file parsing
  • Validation of configuration values
  • Safe regex operations

3. Logging Strategy

Approach: Log for debugging without disrupting user experience.

Implementation:

  • Silent error handling for users
  • Detailed logging for developers
  • Performance metrics collection
  • Error categorization

Performance Design

1. Lazy Initialization

Strategy: Defer expensive operations until needed.

Implementation:

  • Factory files not scanned until first link request
  • Cache built on-demand
  • File system operations minimized

2. Incremental Updates

Strategy: Update only what changed.

Implementation:

  • File watcher provides specific change events
  • Targeted cache invalidation
  • Minimal re-parsing on updates

3. Efficient Data Structures

Strategy: Choose optimal data structures for access patterns.

Implementation:

  • Map<string, Definition> for O(1) lookups
  • Pre-compiled regex patterns
  • Minimal memory footprint

4. Batching Operations

Strategy: Group related operations for efficiency.

Implementation:

  • Batch file reading operations
  • Bulk cache updates
  • Grouped regex operations

Configuration Design

1. Schema-Driven Configuration

Approach: Define configuration schema in extension manifest.

Benefits:

  • VSCode validates configuration
  • Type safety for configuration values
  • Automatic UI generation in settings

Source: package.json#L52-L66

2. Runtime Configuration Updates

Approach: React to configuration changes without restart.

Implementation:

  • Configuration change events trigger cache refresh
  • Dynamic path pattern updates
  • Live configuration validation

3. Default Configuration Strategy

Approach: Sensible defaults that work for most Rails projects.

Implementation:

  • Default path: spec/factories/**/*.rb
  • Standard Rails conventions
  • Progressive enhancement for custom setups

Security Design

1. Principle of Least Privilege

Strategy: Request minimal permissions necessary.

Implementation:

  • Read-only file system access
  • Workspace-scoped operations only
  • No network access required

2. Input Validation

Strategy: Validate all external inputs.

Implementation:

  • Configuration value validation
  • File path sanitization
  • Regex pattern safety checks

3. Resource Boundaries

Strategy: Respect system and user boundaries.

Implementation:

  • Memory usage limits
  • File system access restrictions
  • VSCode security model compliance

Extensibility Design

1. Plugin Architecture Ready

Strategy: Design for future extensibility.

Implementation:

  • Modular provider system
  • Configurable pattern detection
  • Pluggable cache strategies

2. Configuration Extensibility

Strategy: Allow customization without code changes.

Implementation:

  • Flexible path patterns
  • Configurable factory methods
  • Extensible file type support

3. API Design

Strategy: Design internal APIs for future extension.

Implementation:

  • Clean interfaces between components
  • Minimal coupling
  • Well-defined contracts

This architecture provides a solid foundation for the extension while maintaining flexibility for future enhancements and ensuring optimal performance and user experience.