Complete (All 11 Phases)
Latest Update: 2025-10-15
- ✅ Phase 1 completed: Constants and types extracted
- ✅ Phase 2 completed: Cache functions extracted
- ✅ Phase 3 completed: Path utilities extracted
- ✅ Phase 4 completed: Project analysis functions extracted
- ✅ Phase 5 completed: Import update functions extracted
- ✅ Phase 6 completed: Export management functions extracted
- ✅ Phase 7 completed: Validation functions extracted
- ✅ Phase 8 completed: Core operations extracted
- ✅ Phase 9 completed: Test organization improved
- ✅ Phase 10 completed: Performance benchmarks added
- ✅ Phase 11 completed: Documentation updated
All 11 phases complete! 🎉
The @nxworker/workspace:move-file generator has grown to ~2,000 lines in a single file (generator.ts) with 54 functions. The main test file (generator.spec.ts) has grown to ~2,700 lines. This monolithic structure makes the codebase difficult to:
- Navigate: Finding specific functionality requires scrolling through thousands of lines
- Understand: Complex interactions between functions are not immediately clear
- Test: Tests are scattered across a single large file, making it hard to find tests for specific functions
- Modify: Changes to one function risk affecting others due to shared state and unclear dependencies
- Review: PRs with changes to the generator file are difficult to review due to file size
- Optimize: Performance bottlenecks are hard to identify and benchmark
The codebase has already undergone several performance optimizations (glob batching, AST caching, tree caching, smart file cache, dependency graph cache) that are well-documented but scattered throughout the monolithic file.
Before Refactoring (Phase 0):
- generator.ts: ~2,000 lines, 54 functions
- generator.spec.ts: ~2,700 lines, 141 tests
- Test coverage: Good (all tests passing)
- Performance: Good (already optimized with multiple caches)
- Maintainability: Poor (monolithic structure)
After All Phases Complete:
- generator.ts: 307 lines (85% reduction from original)
- Functions extracted: 55+ functions across 10 directories
- Test files: 52 test suites (+11 tests since Phase 7)
- Total tests: 601 tests (+48 since Phase 7)
- Test coverage: Excellent (100% pass rate)
- Performance: Maintained (no regressions, benchmarks added)
- Maintainability: Excellent (modular structure + comprehensive documentation)
- Module READMEs: 10 comprehensive documentation files
The issue requests:
- One function per file (or logically grouped functions)
- One unit test suite per file
- Optional performance benchmark test per function
We will refactor the move-file generator using an incremental, phased approach with the following principles:
-
One Function Per File (or small, tightly-related functions)
- Each file contains a single, focused function or a small group of related helper functions
- File name matches function name (kebab-case)
- Maximum ~100 lines per file
-
One Test Suite Per File
- Each function file has a corresponding
.spec.tsfile - Test file name matches source file name
- Tests are focused and fast
- Each function file has a corresponding
-
Organized by Domain
- Functions grouped into directories by domain (cache, path-utils, import-updates, etc.)
- Direct imports from specific files (no barrel exports)
- Clear separation of concerns
-
Performance Benchmarks
- Critical path functions have
.bench.tsfiles - Benchmarks prevent performance regressions
- Baseline metrics documented
- Critical path functions have
move-file/
├── cache/ # Cache operations
├── validation/ # Validation and resolution
├── path-utils/ # Path manipulation
├── import-updates/ # Import path updates
├── export-management/ # Export management
├── project-analysis/ # Project utilities
├── core-operations/ # Core move logic
├── constants/ # Shared constants
├── types/ # Shared types
├── security-utils/ # Security (already done)
├── benchmarks/ # Performance tests
└── generator.ts # Main orchestration (<200 lines)
- Phase 1: Extract constants and types (low risk)
- Phase 2: Extract cache functions (low-medium risk)
- Phase 3: Extract path utilities (low-medium risk)
- Phase 4: Extract project analysis (medium risk)
- Phase 5: Extract import updates (medium-high risk)
- Phase 6: Extract export management (medium risk)
- Phase 7: Extract validation (low-medium risk)
- Phase 8: Extract core operations (medium-high risk)
- Phase 9: Split test suites (low risk)
- Phase 10: Add benchmarks (low risk)
- Phase 11: Documentation (low risk)
- All existing tests must pass after each phase
- New unit tests for extracted functions
- Integration tests for module interactions
- E2E tests remain unchanged (already comprehensive)
- Benchmark tests for critical paths
// Before (in generator.ts):
function buildTargetPath(...) {
// 20 lines of implementation
}
// After:
// File: path-utils/build-target-path.ts
export function buildTargetPath(...) {
// 20 lines of implementation
}
// File: path-utils/build-target-path.spec.ts
describe('buildTargetPath', () => {
// Unit tests
});
// File: generator.ts
import { buildTargetPath } from './path-utils/build-target-path';-
Improved Discoverability
- Easy to find specific functionality by file name
- IDE autocomplete works better with smaller files
- New developers can navigate the codebase faster
-
Better Testability
- Each function has focused unit tests
- Test failures point to specific files
- Easier to achieve high test coverage
- Faster test execution (can run specific suites)
-
Easier Maintenance
- Changes isolated to specific files
- Smaller PRs that are easier to review
- Less risk of unintended side effects
- Clear dependencies between modules
-
Performance Visibility
- Benchmark tests establish baselines
- Performance bottlenecks easier to identify
- Optimization targets are clear
- Prevent performance regressions
-
Code Reusability
- Functions can be imported by other generators
- Clear module boundaries
- Easier to extract to shared libraries
-
More Files
- Directory structure is more complex
- More files to navigate (but easier to find specific functionality)
- More test files to maintain
-
More Imports
- More import statements at top of files
- Risk of circular dependencies (mitigated by clear module boundaries)
-
Initial Time Investment
- ~35-42 hours of refactoring work
- Need to update all imports
- Need to write new tests
-
Potential for Over-Engineering
- Risk of splitting too aggressively
- Need to balance "one function per file" with practicality
- Some small helper functions may not need separate files
-
No Functional Changes
- All existing functionality preserved
- No API changes
- All existing tests continue to pass
- Performance characteristics unchanged
-
Backwards Compatible
- Public API (
moveFileGenerator) unchanged - Internal refactoring only
- No breaking changes
- Public API (
Decision: Rejected
Rationale: Technical debt is already high. The monolithic structure makes it difficult to onboard new developers and maintain the codebase. The issue explicitly requests refactoring.
Decision: Rejected
Rationale: Too risky. The current implementation is well-tested and optimized. A rewrite would take months and introduce risk of bugs. The incremental approach provides the same benefits with lower risk.
Decision: Rejected
Rationale: Partial refactoring would result in an inconsistent structure with some functions in separate files and others in the monolith. Better to be comprehensive for long-term maintainability.
Decision: Considered but decided against
Rationale: While this would reduce the number of files, it goes against the "one function per file" principle requested in the issue. However, we will allow small, tightly-related helper functions in the same file as the main function.
Decision: Rejected
Rationale: The current functional approach works well. Classes would add unnecessary complexity. The existing caching classes (ASTCache, TreeReadCache) demonstrate that classes are used where appropriate, but most of the logic is better suited to pure functions.
- Functions:
kebab-case.ts(e.g.,build-target-path.ts) - Tests:
kebab-case.spec.ts(e.g.,build-target-path.spec.ts) - Benchmarks:
kebab-case.bench.ts(e.g.,import-updates.bench.ts) - Types:
kebab-case.ts(e.g.,move-context.ts)
Each directory will have function files and their corresponding test files:
directory/
├── function-1.ts
├── function-1.spec.ts
├── function-2.ts
└── function-2.spec.ts
Import directly from specific files:
import { function1 } from './directory/function-1';
import { function2 } from './directory/function-2';Note: We avoid barrel exports (index.ts files that re-export from multiple modules) within the codebase. Barrel exports are only used for package entrypoints (e.g., packages/workspace/src/index.ts). This keeps imports explicit and improves tree-shaking.
- Module-level caches will be moved to dedicated cache modules
- Four caches are currently in use:
projectSourceFilesCache- caches source file lists per projectfileExistenceCache- caches file existence checkscompilerPathsCache- caches TypeScript compiler pathsdependencyGraphCache- caches dependent project lookups (newly added)
- Cache state will be explicit and documented
- Cache lifecycle (clear, update, invalidate) will be clear
- All exported functions will have JSDoc comments
- Each directory will have a README explaining its purpose
- Module-level documentation will describe relationships
- No performance regression allowed
- Benchmark tests will establish baselines
- Critical path functions will be monitored
- Consider lazy loading for less frequently used modules
- ✅ All 141+ existing tests pass (Phase 1)
- ✅ 497 new unit tests added (Phases 1-8)
- ✅ Test coverage maintained or improved (All phases)
- ✅ No performance regression in benchmarks (Phase 10)
- ✅
generator.tsreduced to 307 lines (was 1,967 - achieved 85% reduction ✅) - ✅ Constants and types have JSDoc documentation (Phase 1)
- ✅ Constants have unit tests (Phase 1)
- ✅ Cache functions have unit tests (Phase 2)
- ✅ Path utilities have unit tests (Phase 3)
- ✅ Critical path functions have benchmarks (Phase 10)
- ✅ Documentation updated (README, ADR, inline docs) (Phase 11)
- ✅ Module-level READMEs created for all 10 directories (Phase 11)
All Phases Status: ✅ Complete
Final Test Count: 601 tests (88 integration + 497 unit + 16 benchmark)
Final Line Count: 307 lines (85% reduction from 1,967)
- Issue: Refactor for maintainability
- REFACTORING_PLAN.md
- ✅ REFACTORING_PHASE_1_GUIDE.md - Complete
- ✅ REFACTORING_PHASE_2_GUIDE.md - Complete
- ✅ Phase 3: Path Utilities - Complete
- ✅ REFACTORING_PHASE_4_GUIDE.md - Complete
- ✅ REFACTORING_PHASE_5_GUIDE.md - Complete
- ✅ REFACTORING_PHASE_6_GUIDE.md - Complete
- ✅ REFACTORING_PHASE_7_GUIDE.md - Complete
- ✅ REFACTORING_PHASE_8_GUIDE.md - Complete
- ✅ REFACTORING_PHASE_9_GUIDE.md - Complete
- ✅ REFACTORING_PHASE_10_GUIDE.md - Complete
- ✅ REFACTORING_PHASE_11_GUIDE.md - Complete
- Existing Performance Documentation
- Glob Optimization
- AST Cache Optimization
- Dependency Graph Cache
- Phase 1 (Low risk): ✅ Complete - Constants & Types extracted
- Phase 2-3 (Low-Med risk): ✅ Complete - Cache & Path utilities
- Phase 4-7 (Medium risk): ✅ Complete - Analysis, Imports, Exports, Validation
- Phase 8 (High risk): ✅ Complete - Core operations
- Phase 9-11 (Low risk): ✅ Complete - Tests, Benchmarks, Docs
Total: ~35-42 hours (1 week of focused work)
Completed: All 11 phases ✅
Status: 🎉 Refactoring Complete!
This ADR requires approval from:
- ✅ Project maintainers (Approved for Phase 1)
- Technical lead (For subsequent phases)
- Code reviewers (Ongoing)
- 2025-10-12: Initial draft created
- 2025-10-13: Phase 1 completed, Phase 2 guide created, status updated
- 2025-10-14: Phases 2-7 completed, status updated, metrics updated
- 2025-10-15: Phases 8-11 completed, all phases finished, final metrics updated
Refactoring Complete: All 11 phases successfully completed! 🎉