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.