provisioning/docs/src/architecture/adr/ADR-006-provisioning-cli-refactoring.md
2026-01-14 03:09:18 +00:00

12 KiB

ADR-006: Provisioning CLI Refactoring to Modular Architecture\n\nStatus: Implemented \nDate: 2025-09-30\nAuthors: Infrastructure Team\nRelated: ADR-001 (Project Structure), ADR-004 (Hybrid Architecture)\n\n## Context\n\nThe main provisioning CLI script (provisioning/core/nulib/provisioning) had grown to\n1,329 lines with a massive 1,100+ line match statement handling all commands. This\nmonolithic structure created multiple critical problems:\n\n### Problems Identified\n\n1. Maintainability Crisis\n - 54 command branches in one file\n - Code duplication: Flag handling repeated 50+ times\n - Hard to navigate: Finding specific command logic required scrolling through 1,000+ lines\n - Mixed concerns: Routing, validation, and execution all intertwined\n\n2. Development Friction\n - Adding new commands required editing massive file\n - Testing was nearly impossible (monolithic, no isolation)\n - High cognitive load for contributors\n - Code review difficult due to file size\n\n3. Technical Debt\n - 10+ lines of repetitive flag handling per command\n - No separation of concerns\n - Poor code reusability\n - Difficult to test individual command handlers\n\n4. User Experience Issues\n - No bi-directional help system\n - Inconsistent command shortcuts\n - Help system not fully integrated\n\n## Decision\n\nWe refactored the monolithic CLI into a modular, domain-driven architecture with the following structure:\n\n\nprovisioning/core/nulib/\n├── provisioning (211 lines) ⬅️ 84% reduction\n├── main_provisioning/\n│ ├── flags.nu (139 lines) ⭐ Centralized flag handling\n│ ├── dispatcher.nu (264 lines) ⭐ Command routing\n│ ├── mod.nu (updated)\n│ └── commands/ ⭐ Domain-focused handlers\n│ ├── configuration.nu (316 lines)\n│ ├── development.nu (72 lines)\n│ ├── generation.nu (78 lines)\n│ ├── infrastructure.nu (117 lines)\n│ ├── orchestration.nu (64 lines)\n│ ├── utilities.nu (157 lines)\n│ └── workspace.nu (56 lines)\n\n\n### Key Components\n\n#### 1. Centralized Flag Handling (flags.nu)\n\nSingle source of truth for all flag parsing and argument building:\n\n\nexport def parse_common_flags [flags: record]: nothing -> record\nexport def build_module_args [flags: record, extra: string = ""]: nothing -> string\nexport def set_debug_env [flags: record]\nexport def get_debug_flag [flags: record]: nothing -> string\n\n\nBenefits:\n\n- Eliminates 50+ instances of duplicate code\n- Single place to add/modify flags\n- Consistent flag handling across all commands\n- Reduced from 10 lines to 3 lines per command handler\n\n#### 2. Command Dispatcher (dispatcher.nu)\n\nCentral routing with 80+ command mappings:\n\n\nexport def get_command_registry []: nothing -> record # 80+ shortcuts\nexport def dispatch_command [args: list, flags: record] # Main router\n\n\nFeatures:\n\n- Command registry with shortcuts (ws → workspace, orch → orchestrator, etc.)\n- Bi-directional help support (provisioning ws help works)\n- Domain-based routing (infrastructure, orchestration, development, etc.)\n- Special command handling (create, delete, price, etc.)\n\n#### 3. Domain Command Handlers (commands/*.nu)\n\nSeven focused modules organized by domain:\n\n| Module | Lines | Responsibility |\n| -------- | ------- | ---------------- |\n| infrastructure.nu | 117 | Server, taskserv, cluster, infra |\n| orchestration.nu | 64 | Workflow, batch, orchestrator |\n| development.nu | 72 | Module, layer, version, pack |\n| workspace.nu | 56 | Workspace, template |\n| generation.nu | 78 | Generate commands |\n| utilities.nu | 157 | SSH, SOPS, cache, providers |\n| configuration.nu | 316 | Env, show, init, validate |\n\nEach handler:\n\n- Exports handle_<domain>_command function\n- Uses shared flag handling\n- Provides error messages with usage hints\n- Isolated and testable\n\n## Architecture Principles\n\n### 1. Separation of Concerns\n\n- Routingdispatcher.nu\n- Flag parsingflags.nu\n- Business logiccommands/*.nu\n- Help systemhelp_system.nu (existing)\n\n### 2. Single Responsibility\n\nEach module has ONE clear purpose:\n\n- Command handlers execute specific domains\n- Dispatcher routes to correct handler\n- Flags module normalizes all inputs\n\n### 3. DRY (Don't Repeat Yourself)\n\nEliminated repetition:\n\n- Flag handling: 50+ instances → 1 function\n- Command routing: Scattered logic → Command registry\n- Error handling: Consistent across all domains\n\n### 4. Open/Closed Principle\n\n- Open for extension: Add new handlers easily\n- Closed for modification: Core routing unchanged\n\n### 5. Dependency Inversion\n\nAll handlers depend on abstractions (flag records, not concrete flags):\n\n\n# Handler signature\nexport def handle_infrastructure_command [\n command: string\n ops: string\n flags: record # ⬅️ Abstraction, not concrete flags\n]\n\n\n## Implementation Details\n\n### Migration Path (Completed in 2 Phases)\n\nPhase 1: Foundation\n\n1. Created commands/ directory structure\n2. Created flags.nu with common flag handling\n3. Created initial command handlers (infrastructure, utilities, configuration)\n4. Created dispatcher.nu with routing logic\n5. Refactored main file (1,329 → 211 lines)\n6. Tested basic functionality\n\nPhase 2: Completion\n\n1. Fixed bi-directional help (provisioning ws help now works)\n2. Created remaining handlers (orchestration, development, workspace, generation)\n3. Removed duplicate code from dispatcher\n4. Added comprehensive test suite\n5. Verified all shortcuts work\n\n### Bi-directional Help System\n\nUsers can now access help in multiple ways:\n\n\n# All these work equivalently:\nprovisioning help workspace\nprovisioning workspace help # ⬅️ NEW: Bi-directional\nprovisioning ws help # ⬅️ NEW: With shortcuts\nprovisioning help ws # ⬅️ NEW: Shortcut in help\n\n\nImplementation:\n\n\n# Intercept "command help" → "help command"\nlet first_op = if ($ops_list | length) > 0 { ($ops_list | get 0) } else { "" }\nif $first_op in ["help" "h"] {\n exec $"($env.PROVISIONING_NAME)" help $task --notitles\n}\n\n\n### Command Shortcuts\n\nComprehensive shortcut system with 30+ mappings:\n\nInfrastructure:\n\n- sserver\n- t, tasktaskserv\n- clcluster\n- iinfra\n\nOrchestration:\n\n- wf, flowworkflow\n- batbatch\n- orchorchestrator\n\nDevelopment:\n\n- modmodule\n- lyrlayer\n\nWorkspace:\n\n- wsworkspace\n- tpl, tmpltemplate\n\n## Testing\n\nComprehensive test suite created (tests/test_provisioning_refactor.nu):\n\n### Test Coverage\n\n- Main help display\n- Category help (infrastructure, orchestration, development, workspace)\n- Bi-directional help routing\n- All command shortcuts\n- Category shortcut help\n- Command routing to correct handlers\n\n### Test Results\n\n\n📋 Testing main help... ✅\n📋 Testing category help... ✅\n🔄 Testing bi-directional help... ✅\n⚡ Testing command shortcuts... ✅\n📚 Testing category shortcut help... ✅\n🎯 Testing command routing... ✅\n\n📊 TEST RESULTS: 6 passed, 0 failed\n\n\n## Results\n\n### Quantitative Improvements\n\n| Metric | Before | After | Improvement |\n| -------- | -------- | ------- | ------------- |\n| Main file size | 1,329 lines | 211 lines | 84% reduction |\n| Command handler | 1 massive match (1,100+ lines) | 7 focused modules | Domain separation |\n| Flag handling | Repeated 50+ times | 1 function | 98% duplication removal |\n| Code per command | 10 lines | 3 lines | 70% reduction |\n| Modules count | 1 monolith | 9 modules | Modular architecture |\n| Test coverage | None | 6 test groups | Comprehensive testing |\n\n### Qualitative Improvements\n\nMaintainability\n\n- Easy to find specific command logic\n- Clear separation of concerns\n- Self-documenting structure\n- Focused modules (< 320 lines each)\n\nExtensibility\n\n- Add new commands: Just update appropriate handler\n- Add new flags: Single function update\n- Add new shortcuts: Update command registry\n- No massive file edits required\n\nTestability\n\n- Isolated command handlers\n- Mockable dependencies\n- Test individual domains\n- Fast test execution\n\nDeveloper Experience\n\n- Lower cognitive load\n- Faster onboarding\n- Easier code review\n- Better IDE navigation\n\n## Trade-offs\n\n### Advantages\n\n1. Dramatically reduced complexity: 84% smaller main file\n2. Better organization: Domain-focused modules\n3. Easier testing: Isolated, testable units\n4. Improved maintainability: Clear structure, less duplication\n5. Enhanced UX: Bi-directional help, shortcuts\n6. Future-proof: Easy to extend\n\n### Disadvantages\n\n1. More files: 1 file → 9 files (but smaller, focused)\n2. Module imports: Need to import multiple modules (automated via mod.nu)\n3. Learning curve: New structure requires documentation (this ADR)\n\nDecision: Advantages significantly outweigh disadvantages.\n\n## Examples\n\n### Before: Repetitive Flag Handling\n\n\n"server" => {\n let use_check = if $check { "--check "} else { "" }\n let use_yes = if $yes { "--yes" } else { "" }\n let use_wait = if $wait { "--wait" } else { "" }\n let use_keepstorage = if $keepstorage { "--keepstorage "} else { "" }\n let str_infra = if $infra != null { $"--infra ($infra) "} else { "" }\n let str_outfile = if $outfile != null { $"--outfile ($outfile) "} else { "" }\n let str_out = if $out != null { $"--out ($out) "} else { "" }\n let arg_include_notuse = if $include_notuse { $"--include_notuse "} else { "" }\n run_module $"($str_ops) ($str_infra) ($use_check)..." "server" --exec\n}\n\n\n### After: Clean, Reusable\n\n\ndef handle_server [ops: string, flags: record] {\n let args = build_module_args $flags $ops\n run_module $args "server" --exec\n}\n\n\nReduction: 10 lines → 3 lines (70% reduction)\n\n## Future Considerations\n\n### Potential Enhancements\n\n1. Unit test expansion: Add tests for each command handler\n2. Integration tests: End-to-end workflow tests\n3. Performance profiling: Measure routing overhead (expected to be negligible)\n4. Documentation generation: Auto-generate docs from handlers\n5. Plugin architecture: Allow third-party command extensions\n\n### Migration Guide for Contributors\n\nSee docs/development/COMMAND_HANDLER_GUIDE.md for:\n\n- How to add new commands\n- How to modify existing handlers\n- How to add new shortcuts\n- Testing guidelines\n\n## Related Documentation\n\n- Architecture Overview: docs/architecture/system-overview.md\n- Developer Guide: docs/development/COMMAND_HANDLER_GUIDE.md\n- Main Project Docs: CLAUDE.md (updated with new structure)\n- Test Suite: tests/test_provisioning_refactor.nu\n\n## Conclusion\n\nThis refactoring transforms the provisioning CLI from a monolithic, hard-to-maintain script into a modular, well-organized system following software\nengineering best practices. The 84% reduction in main file size, elimination of code duplication, and comprehensive test coverage position the project\nfor sustainable long-term growth.\n\nThe new architecture enables:\n\n- Faster development: Add commands in minutes, not hours\n- Better quality: Isolated testing catches bugs early\n- Easier maintenance: Clear structure reduces cognitive load\n- Enhanced UX: Shortcuts and bi-directional help improve usability\n\nStatus: Successfully implemented and tested. All commands operational. Ready for production use.\n\n---\n\nThis ADR documents a major architectural improvement completed on 2025-09-30.