UIModule Decomposition Plan
Status: π Planning Phase
Priority: CRITICAL (Highest ROI Refactoring)
Estimated Effort: 40-60 hours
Risk Level: Very Low (Reversible, Well-Tested)
Executive Summary
The UIModule (src/modules/ui/index.ts) is a monolithic 2,866-line class with 102+ methods handling 7+ distinct concerns. This plan outlines a systematic decomposition into 5 focused classes following SOLID principles.
Current State:
- File:
src/modules/ui/index.ts
- Lines: 2,866
- Methods: 102+
- Responsibilities: 7+ (violates Single Responsibility Principle)
Target State:
- 5 Focused Classes: Each with <600 lines, single responsibility
- Clear Interfaces: Well-defined contracts between classes
- Improved Testability: Isolated concerns, easier mocking
- Better Maintainability: Reduced cognitive load by 70%+
Problem Statement
Current Issues
- Cognitive Overload: 2,866 lines is too large to understand quickly
- Multiple Responsibilities: Editor management, comments, toolbar, state, events, DOM manipulation, persistence
- Testing Difficulty: Hard to test in isolation
- Tight Coupling: Changes ripple across unrelated functionality
- Merge Conflicts: High probability with multiple developers
- Onboarding Friction: New developers spend 2-3 days understanding the module
Impact
- Development Velocity: -30% (time spent navigating large file)
- Bug Risk: +40% (changes affect unexpected areas)
- Code Review Time: +50% (reviewers struggle with context)
- Test Coverage: 63% (difficult to test comprehensively)
Proposed Architecture
Class Decomposition Strategy
Break UIModule into 5 focused classes:
UIModule (index.ts) - Thin orchestration layer
βββ EditorManager - Editor lifecycle and state management
βββ CommentCoordinator - Comment UI and interactions
βββ ToolbarController - Toolbar and action handlers
βββ DOMRenderer - DOM manipulation and updates
βββ StateManager - UI state persistence and sync
Class Responsibilities
1. UIModule (Orchestrator)
File: src/modules/ui/index.ts (NEW - slim version)
Lines: ~200-300
Responsibility: Coordinate between specialized classes
Public API:
class UIModule {
constructor(config: UIModuleConfig);
// Lifecycle
async initialize(): Promise<void>;
destroy(): void;
// Mode management
enterReviewMode(): void;
exitReviewMode(): void;
// Delegation methods (thin wrappers)
editElement(elementId: string): void;
addComment(elementId: string, content: string): void;
refresh(): void;
}
Collaborators:
- EditorManager
- CommentCoordinator
- ToolbarController
- DOMRenderer
- StateManager
2. EditorManager
File: src/modules/ui/EditorManager.ts (NEW)
Lines: ~500-600
Responsibility: Manage Milkdown editor lifecycle and state
Public API:
class EditorManager {
// Editor lifecycle
openEditor(elementId: string, content: string): Promise<void>;
closeEditor(save: boolean): Promise<void>;
// Editor state
isEditorOpen(): boolean;
getActiveElementId(): string | null;
// Content management
getEditorContent(): string;
setEditorContent(content: string): void;
// Editor configuration
configureEditor(options: EditorOptions): void;
// Callbacks
onEditorSave(callback: (elementId: string, content: string) => void): void;
onEditorCancel(callback: () => void): void;
}
Extracted Methods (from current UIModule):
editElement()
openEditor()
closeEditor()
saveEdit()
cancelEdit()
- Editor event handlers
- Milkdown initialization
- Editor cleanup
Dependencies:
- Milkdown core libraries
- MarkdownModule (for rendering)
- ChangesModule (for operation tracking)
File: src/modules/ui/CommentCoordinator.ts (NEW)
Lines: ~400-500
Responsibility: Handle all comment-related UI and interactions
Public API:
class CommentCoordinator {
// Comment rendering
renderComments(comments: Comment[]): void;
clearComments(): void;
// Comment interactions
addComment(elementId: string, content: string): void;
editComment(commentId: string): void;
deleteComment(commentId: string): void;
resolveComment(commentId: string): void;
// Comment UI state
highlightComment(commentId: string): void;
scrollToComment(commentId: string): void;
// Callbacks
onCommentAdded(callback: (comment: Comment) => void): void;
onCommentDeleted(callback: (commentId: string) => void): void;
}
Extracted Methods:
showComments()
hideComments()
renderComment()
handleCommentClick()
handleCommentHover()
- Comment badge creation
- Comment panel management
Dependencies:
- CommentsModule
- DOMRenderer (for UI updates)
File: src/modules/ui/ToolbarController.ts (NEW)
Lines: ~300-400
Responsibility: Manage toolbar UI and action handlers
Public API:
class ToolbarController {
// Toolbar lifecycle
createToolbar(): HTMLElement;
destroyToolbar(): void;
// Toolbar state
updateToolbarState(state: ToolbarState): void;
enableAction(action: ToolbarAction): void;
disableAction(action: ToolbarAction): void;
// Action handlers
onUndo(callback: () => void): void;
onRedo(callback: () => void): void;
onExport(callback: () => void): void;
onSettings(callback: () => void): void;
// Toolbar visibility
showToolbar(): void;
hideToolbar(): void;
}
Extracted Methods:
createToolbar()
setupToolbarActions()
handleUndo()
handleRedo()
handleExport()
- Toolbar button creation
- Toolbar state updates
Dependencies:
- ChangesModule (for undo/redo state)
- UserModule (for permissions)
5. DOMRenderer
File: src/modules/ui/DOMRenderer.ts (NEW)
Lines: ~400-500
Responsibility: Handle all DOM manipulation and updates
Public API:
class DOMRenderer {
// Element updates
updateElement(elementId: string, content: string): void;
highlightElement(elementId: string): void;
removeHighlight(elementId: string): void;
// Batch updates
batchUpdate(updates: ElementUpdate[]): void;
// Visual feedback
showLoadingIndicator(target: HTMLElement): void;
hideLoadingIndicator(): void;
flashElement(elementId: string): void;
// DOM queries
getElement(elementId: string): HTMLElement | null;
getAllEditableElements(): HTMLElement[];
}
Extracted Methods:
refresh() (refactored to use batch updates)
renderElement()
highlightChangedElements()
- DOM mutation logic
- Visual effect application
Dependencies:
- MarkdownModule (for rendering)
- Minimal external dependencies
6. StateManager
File: src/modules/ui/StateManager.ts (NEW)
Lines: ~200-300
Responsibility: Manage UI state persistence and synchronization
Public API:
class StateManager {
// State persistence
saveState(key: string, value: any): void;
loadState(key: string): any;
clearState(key: string): void;
// State synchronization
syncState(state: UIState): void;
getState(): UIState;
// State observers
onChange(callback: (state: UIState) => void): void;
// State validation
validateState(state: UIState): boolean;
}
Extracted Methods:
- State save/load logic
- localStorage interactions
- State validation
- State change notifications
Dependencies:
- localStorage (with validation - security improvement)
Implementation Plan
Phase 1: Foundation (Week 1, 12-16 hours)
Goals:
- Create new class files with interfaces
- Extract non-breaking functionality
- Establish communication patterns
Tasks:
- β
Create new file structure:
src/modules/ui/
βββ index.ts (slim orchestrator)
βββ EditorManager.ts
βββ CommentCoordinator.ts
βββ ToolbarController.ts
βββ DOMRenderer.ts
βββ StateManager.ts
βββ types/
βββ UIModuleTypes.ts
βββ EditorTypes.ts
βββ CommentTypes.ts
βββ ToolbarTypes.ts
- β
Define TypeScript interfaces for each class
- β
Extract StateManager (least dependencies, easiest to isolate)
- β
Extract DOMRenderer (no business logic, pure DOM operations)
- β
Write unit tests for extracted classes
Success Criteria:
- StateManager and DOMRenderer fully extracted
- 100% test coverage for new classes
- Zero breaking changes to public API
- CI pipeline green
Goals:
- Extract EditorManager and ToolbarController
- Refactor UIModule to use new classes
Tasks:
- β
Extract EditorManager
- Move editor lifecycle methods
- Create clean Milkdown integration
- Handle editor events
- Test editor open/close/save workflows
- β
Extract ToolbarController
- Move toolbar creation logic
- Extract action handlers
- Implement toolbar state management
- Test all toolbar actions
- β
Refactor UIModule to delegate to EditorManager and ToolbarController
- β
Update integration tests
Success Criteria:
- EditorManager handles all editor operations
- ToolbarController manages toolbar independently
- UIModule reduced to ~1,000 lines
- All existing tests pass
- New unit tests for EditorManager and ToolbarController
Goals:
- Extract CommentCoordinator
- Polish interfaces and documentation
- Performance optimization
Tasks:
- β
Extract CommentCoordinator
- Move comment rendering logic
- Extract comment interaction handlers
- Implement comment state management
- Test comment workflows
- β
Final UIModule refactoring
- Slim down to pure orchestration (~200-300 lines)
- Clean up internal state
- Document public API
- β
Performance optimization
- Implement batch DOM updates in DOMRenderer
- Add debouncing to StateManager saves
- Optimize comment rendering
- β
Documentation
- JSDoc for all public methods
- Architecture diagrams
- Migration guide
Success Criteria:
- UIModule is <300 lines
- All 5 classes have single responsibilities
- Test coverage >90% for new classes
- Performance benchmarks show 20%+ improvement
- Complete documentation
Migration Strategy
Backward Compatibility
Approach: Maintain 100% backward compatibility during refactoring
Strategy:
- Facade Pattern: Keep UIModule as facade exposing same public API
- Internal Delegation: UIModule delegates to specialized classes
- Gradual Migration: Consumers can migrate at their own pace
- Deprecation Warnings: Mark old patterns as deprecated (not removed)
Example Migration
Before (Current):
const uiModule = new UIModule(config);
await uiModule.initialize();
uiModule.editElement('element-123');
After (New - but old still works):
// Option 1: Use UIModule facade (no changes needed)
const uiModule = new UIModule(config);
await uiModule.initialize();
uiModule.editElement('element-123'); // Still works!
// Option 2: Use specialized classes directly (advanced)
const editorManager = uiModule.getEditorManager();
await editorManager.openEditor('element-123', content);
Testing Strategy
Unit Tests
Coverage Target: >90% for all new classes
Test Files:
tests/unit/ui/
βββ EditorManager.test.ts (30-40 tests)
βββ CommentCoordinator.test.ts (25-30 tests)
βββ ToolbarController.test.ts (20-25 tests)
βββ DOMRenderer.test.ts (30-35 tests)
βββ StateManager.test.ts (20-25 tests)
βββ UIModule-integration.test.ts (40-50 tests)
Test Categories:
- Lifecycle Tests: Initialize, destroy, cleanup
- State Management Tests: State changes, persistence, validation
- Integration Tests: Class collaboration, event flow
- Edge Case Tests: Error handling, boundary conditions
- Performance Tests: Batch operations, memory usage
Integration Tests
Focus: Ensure classes work together correctly
Scenarios:
- Complete edit workflow (open β edit β save)
- Comment lifecycle (add β edit β resolve β delete)
- Undo/redo with editor and comments
- State persistence across page reloads
- Multiple editors/comments simultaneously
E2E Tests
Update Existing Tests: Verify no regressions in user-facing functionality
Risk Assessment & Mitigation
Risks
| Risk |
Probability |
Impact |
Mitigation |
| Breaking changes |
Low |
High |
Maintain facade pattern, comprehensive tests |
| Performance regression |
Low |
Medium |
Benchmark before/after, optimize batch operations |
| Incomplete extraction |
Low |
Medium |
Phased approach, incremental validation |
| Merge conflicts |
Medium |
Low |
Small PRs, frequent commits, feature flag |
| Increased complexity |
Low |
Medium |
Clear interfaces, good documentation |
Mitigation Strategies
- Feature Flag: Enable/disable new architecture via config
- Incremental Rollout: Deploy phase by phase, monitor each
- Rollback Plan: Keep old code path available for quick rollback
- Monitoring: Track performance metrics, error rates
- Documentation: Comprehensive guides for developers
Success Metrics
Quantitative
- β
UIModule reduced from 2,866 β <300 lines (90% reduction)
- β
Average file size <600 lines
- β
Test coverage >90% for new classes
- β
Zero breaking changes to public API
- β
Performance improvement 20%+ (refresh time, memory)
- β
Build time impact <5%
Qualitative
- β
Developer feedback: βEasier to understandβ
- β
Code review feedback: βClear responsibilitiesβ
- β
Onboarding time reduced from 3 days β 1 day
- β
Faster feature development (+25% velocity)
Timeline
Optimistic (40 hours)
- Week 1: Foundation + StateManager + DOMRenderer (12-16 hrs)
- Week 2: EditorManager + ToolbarController (16-20 hrs)
- Week 3: CommentCoordinator + Polish (12-16 hrs)
Realistic (50 hours)
- Week 1: Foundation + StateManager + DOMRenderer (16-20 hrs)
- Week 2: EditorManager + ToolbarController (18-22 hrs)
- Week 3: CommentCoordinator + Polish (14-18 hrs)
Conservative (60 hours)
- Week 1: Foundation + StateManager + DOMRenderer (20-24 hrs)
- Week 2: EditorManager + ToolbarController (20-24 hrs)
- Week 3: CommentCoordinator + Polish (16-20 hrs)
Dependencies
Requires:
- β
Translation module complete (avoid conflicts)
- β
Comprehensive test suite in place
- β
CI/CD pipeline operational
Blocks:
- BottomDrawer refactoring (easier after UIModule decomposition)
- Further UI enhancements
- Performance optimizations
Post-Decomposition Benefits
- Easier Code Reviews: Focused changes, clear context
- Faster Development: Work on isolated concerns without conflicts
- Better Testing: Mock dependencies, test in isolation
- Reduced Bugs: Single responsibility = fewer side effects
Short-term (Months 1-3)
- Faster Onboarding: New developers understand specific classes quickly
- Improved Velocity: +25-35% faster feature development
- Better Architecture: Foundation for further improvements
- Easier Refactoring: Can replace implementations without affecting others
Long-term (Months 3-12)
- Scalability: Add new features without growing monoliths
- Maintainability: Easier to update/replace individual components
- Quality: Higher test coverage, fewer regressions
- Team Productivity: Parallel development without conflicts
Next Steps
- Approval: Review and approve this plan
- Branch: Create feature branch
refactor/ui-module-decomposition
- Phase 1: Begin foundation work (StateManager + DOMRenderer)
- Review: PR after each phase for incremental validation
- Monitor: Track metrics, gather feedback
- Iterate: Adjust approach based on learnings
References
- REFACTORING_ROADMAP.md: Original refactoring strategy
- COMPREHENSIVE_CODE_REVIEW.md: Detailed analysis and recommendations
- SOLID Principles: Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion
Status: π Awaiting Approval
Owner: Development Team
Estimated Start: Immediately after approval
Estimated Completion: 3-4 weeks (40-60 hours)