Skip to content

Commit d399875

Browse files
committed
docs: add issue specification for command handler refactoring
- Create issue #56: Refactor Command Handlers to Modular Directory Structure - Add detailed specification document with implementation plan - Document target structure following create/ pattern - Include subtask breakdown for independent commits - Add acceptance criteria and architectural constraints This refactoring will migrate provision, configure, and destroy command handlers from single-file pattern to modular directory structure for better maintainability and consistency.
1 parent de98637 commit d399875

1 file changed

Lines changed: 384 additions & 0 deletions

File tree

Lines changed: 384 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,384 @@
1+
# Refactor Command Handlers to Modular Directory Structure
2+
3+
**Issue**: #56
4+
**Type**: Refactoring
5+
**Related**: Follows pattern established in `CreateCommandHandler` (see `src/application/command_handlers/create/`)
6+
7+
## Overview
8+
9+
Refactor the existing single-file command handlers (`provision`, `configure`, `destroy`) to follow the new modular directory structure pattern established in `CreateCommandHandler`. This improves code organization, maintainability, and scalability by separating concerns into dedicated files.
10+
11+
Currently, three command handlers use a single-file pattern:
12+
13+
- `provision.rs` (752 lines) - Too large, mixing handler logic, errors, and tests
14+
- `destroy.rs` (631 lines) - Getting unwieldy
15+
- `configure.rs` (370 lines) - Manageable but would benefit from separation
16+
17+
The `CreateCommandHandler` demonstrates a better structure with separate files for handler logic, errors, and tests.
18+
19+
## Goals
20+
21+
- [ ] Migrate `ProvisionCommandHandler` to modular structure
22+
- [ ] Migrate `ConfigureCommandHandler` to modular structure
23+
- [ ] Migrate `DestroyCommandHandler` to modular structure
24+
- [ ] Improve code maintainability and readability
25+
- [ ] Make test organization clearer and more scalable
26+
- [ ] Establish consistent patterns across all command handlers
27+
28+
## 🏗️ Architecture Requirements
29+
30+
**DDD Layer**: Application Layer
31+
**Module Path**: `src/application/command_handlers/{provision|configure|destroy}/`
32+
**Pattern**: Command Handler with modular organization
33+
34+
### Module Structure Requirements
35+
36+
- [ ] Follow DDD layer separation (see [docs/codebase-architecture.md](../docs/codebase-architecture.md))
37+
- [ ] Maintain existing dependency injection patterns
38+
- [ ] Use appropriate module organization (see [docs/contributing/module-organization.md](../docs/contributing/module-organization.md))
39+
- [ ] Preserve existing public API surface (no breaking changes)
40+
41+
### Architectural Constraints
42+
43+
- [ ] No changes to command handler business logic (refactoring only)
44+
- [ ] Error handling follows project conventions (see [docs/contributing/error-handling.md](../docs/contributing/error-handling.md))
45+
- [ ] Testing strategy aligns with layer responsibilities (see [docs/contributing/testing.md](../docs/contributing/testing.md))
46+
- [ ] All existing tests must continue to pass
47+
- [ ] Preserve traceability and observability features
48+
49+
**Note**: Breaking changes to import paths are acceptable since this library is not yet publicly used. Simplifying the module structure takes priority over backward compatibility.
50+
51+
### Anti-Patterns to Avoid
52+
53+
- ❌ Changing business logic during refactoring
54+
- ❌ Mixing refactoring with new features
55+
- ❌ Creating incomplete module structures
56+
- ❌ Half-migrating modules (finish one completely before moving to next)
57+
58+
## Specifications
59+
60+
### Current Structure (Single-File Pattern)
61+
62+
```text
63+
src/application/command_handlers/
64+
├── configure.rs (370 lines)
65+
├── destroy.rs (631 lines)
66+
├── provision.rs (752 lines)
67+
└── test.rs
68+
```
69+
70+
**Problems**:
71+
72+
- Large files difficult to navigate (provision.rs: 752 lines)
73+
- Mixed concerns: handler logic, errors, tests all in one file
74+
- Poor scalability: adding features bloats single file
75+
- Harder code reviews: changes to errors require reviewing entire handler
76+
- Test organization unclear
77+
78+
### Target Structure (Modular Pattern)
79+
80+
Based on the `create/` command handler pattern:
81+
82+
```text
83+
src/application/command_handlers/
84+
├── configure/
85+
│ ├── mod.rs # Module documentation & public API
86+
│ ├── handler.rs # Command handler implementation
87+
│ ├── errors.rs # Error types with .help()
88+
│ └── tests/
89+
│ ├── mod.rs # Test module entry
90+
│ ├── builders.rs # Test builders and fixtures
91+
│ └── integration.rs # Integration tests
92+
├── destroy/
93+
│ ├── mod.rs
94+
│ ├── handler.rs
95+
│ ├── errors.rs
96+
│ └── tests/
97+
│ ├── mod.rs
98+
│ ├── builders.rs
99+
│ └── integration.rs
100+
├── provision/
101+
│ ├── mod.rs
102+
│ ├── handler.rs
103+
│ ├── errors.rs
104+
│ └── tests/
105+
│ ├── mod.rs
106+
│ ├── builders.rs
107+
│ └── integration.rs
108+
└── test.rs
109+
```
110+
111+
### File Responsibilities
112+
113+
#### `mod.rs` (Module Documentation & Public API)
114+
115+
- Module-level documentation
116+
- Re-exports public types (`pub use`)
117+
- Declares submodules
118+
- Serves as clean entry point
119+
120+
**Example** (based on `create/mod.rs`):
121+
122+
```rust
123+
//! [Command Name] Command Module
124+
//!
125+
//! This module implements the delivery-agnostic `[Command]CommandHandler`
126+
//! for orchestrating [command purpose] business logic.
127+
//!
128+
//! ## Architecture
129+
//!
130+
//! The `[Command]CommandHandler` implements the Command Pattern...
131+
132+
pub mod errors;
133+
pub mod handler;
134+
135+
#[cfg(test)]
136+
pub mod tests;
137+
138+
// Re-export public API
139+
pub use errors::{[Command]CommandHandlerError};
140+
pub use handler::{[Command]CommandHandler};
141+
```
142+
143+
#### `handler.rs` (Command Handler Implementation)
144+
145+
- Command handler struct definition
146+
- Business logic orchestration
147+
- Dependency injection via constructor
148+
- Public `execute()` method
149+
- No error definitions (moved to `errors.rs`)
150+
151+
**Size**: 200-300 lines typical
152+
153+
#### `errors.rs` (Error Types)
154+
155+
- Error enum definitions using `thiserror`
156+
- `Traceable` trait implementation
157+
- `.help()` methods for actionable error messages
158+
- Error documentation
159+
160+
**Size**: 150-200 lines typical
161+
162+
#### `tests/` (Test Organization)
163+
164+
- `mod.rs`: Test module entry, re-exports
165+
- `builders.rs`: Test builders and fixtures
166+
- `integration.rs`: Integration test cases
167+
168+
### Migration Strategy (Per Command Handler)
169+
170+
For each command handler (`provision`, `configure`, `destroy`):
171+
172+
1. **Create Directory Structure**
173+
174+
```bash
175+
mkdir -p src/application/command_handlers/{command}/tests
176+
```
177+
178+
2. **Split Files**
179+
180+
- Extract errors → `errors.rs`
181+
- Move handler → `handler.rs`
182+
- Create `mod.rs` with documentation
183+
- Organize tests → `tests/`
184+
185+
3. **Update Imports Throughout Codebase**
186+
187+
- Update parent `mod.rs` to use new module structure
188+
- Fix ALL imports in other modules that use the command handler
189+
- Update CLI/presentation layer imports
190+
- Update any test imports
191+
- **Breaking changes acceptable** - simplify paths where possible
192+
193+
4. **Verify**
194+
195+
- Run `cargo test` - all tests must pass
196+
- Run `cargo clippy` - no new warnings
197+
- Run `./scripts/pre-commit.sh` - all checks pass
198+
199+
## Implementation Plan
200+
201+
**Important**: Migrate and commit each command handler independently. Run pre-commit checks after completing each one before moving to the next.
202+
203+
### Subtask 1: Migrate ProvisionCommandHandler (3-4 hours)
204+
205+
- [ ] Create `src/application/command_handlers/provision/` directory
206+
- [ ] Create `provision/mod.rs` with module documentation and re-exports
207+
- [ ] Create `provision/handler.rs` - move handler implementation from `provision.rs`
208+
- [ ] Create `provision/errors.rs` - extract error types from `provision.rs`
209+
- [ ] Create `provision/tests/mod.rs` - test module entry point
210+
- [ ] Create `provision/tests/builders.rs` - extract or create test builders
211+
- [ ] Create `provision/tests/integration.rs` - move existing tests
212+
- [ ] Update `src/application/command_handlers/mod.rs` to use new structure
213+
- [ ] **Update ALL imports across codebase** (CLI, presentation, other modules)
214+
- [ ] Delete old `provision.rs` file
215+
- [ ] Run `cargo test` to verify all tests pass
216+
- [ ] Run `cargo clippy` to check for issues
217+
- [ ] Run `./scripts/pre-commit.sh` to verify quality
218+
- [ ] **Commit this refactoring independently before moving to next handler**
219+
220+
### Subtask 2: Migrate ConfigureCommandHandler (2-3 hours)
221+
222+
- [ ] Create `src/application/command_handlers/configure/` directory
223+
- [ ] Create `configure/mod.rs` with module documentation and re-exports
224+
- [ ] Create `configure/handler.rs` - move handler implementation from `configure.rs`
225+
- [ ] Create `configure/errors.rs` - extract error types from `configure.rs`
226+
- [ ] Create `configure/tests/mod.rs` - test module entry point
227+
- [ ] Create `configure/tests/builders.rs` - extract or create test builders
228+
- [ ] Create `configure/tests/integration.rs` - move existing tests
229+
- [ ] Update `src/application/command_handlers/mod.rs` to use new structure
230+
- [ ] **Update ALL imports across codebase** (CLI, presentation, other modules)
231+
- [ ] Delete old `configure.rs` file
232+
- [ ] Run `cargo test` to verify all tests pass
233+
- [ ] Run `cargo clippy` to check for issues
234+
- [ ] Run `./scripts/pre-commit.sh` to verify quality
235+
- [ ] **Commit this refactoring independently before moving to next handler**
236+
237+
### Subtask 3: Migrate DestroyCommandHandler (2-3 hours)
238+
239+
- [ ] Create `src/application/command_handlers/destroy/` directory
240+
- [ ] Create `destroy/mod.rs` with module documentation and re-exports
241+
- [ ] Create `destroy/handler.rs` - move handler implementation from `destroy.rs`
242+
- [ ] Create `destroy/errors.rs` - extract error types from `destroy.rs`
243+
- [ ] Create `destroy/tests/mod.rs` - test module entry point
244+
- [ ] Create `destroy/tests/builders.rs` - extract or create test builders
245+
- [ ] Create `destroy/tests/integration.rs` - move existing tests
246+
- [ ] Update `src/application/command_handlers/mod.rs` to use new structure
247+
- [ ] **Update ALL imports across codebase** (CLI, presentation, other modules)
248+
- [ ] Delete old `destroy.rs` file
249+
- [ ] Run `cargo test` to verify all tests pass
250+
- [ ] Run `cargo clippy` to check for issues
251+
- [ ] Run `./scripts/pre-commit.sh` to verify quality
252+
- [ ] **Commit this refactoring independently**
253+
254+
### Subtask 4: Final Verification and Documentation (1 hour)
255+
256+
- [ ] Run full test suite: `cargo test`
257+
- [ ] Run E2E tests: `cargo run --bin e2e-tests-full`
258+
- [ ] Verify all command handlers follow consistent structure
259+
- [ ] Update any relevant documentation mentioning command handler structure
260+
- [ ] Ensure all imports across the codebase are correct
261+
- [ ] Final pre-commit verification: `./scripts/pre-commit.sh`
262+
- [ ] **Final commit with any documentation updates**
263+
264+
## Acceptance Criteria
265+
266+
**Quality Checks**:
267+
268+
- [ ] Pre-commit checks pass: `./scripts/pre-commit.sh`
269+
270+
**Refactoring-Specific Criteria**:
271+
272+
- [ ] All three command handlers use modular directory structure
273+
- [ ] Directory structure matches `create/` pattern exactly
274+
- [ ] All existing tests continue to pass
275+
- [ ] No changes to business logic (pure refactoring)
276+
- [ ] File sizes reduced to manageable levels (< 300 lines per file)
277+
- [ ] Clear separation of concerns (handler, errors, tests)
278+
- [ ] Module documentation is comprehensive
279+
- [ ] Error types include `.help()` methods
280+
- [ ] Test organization is clear and scalable
281+
- [ ] All imports updated correctly throughout entire codebase
282+
- [ ] No clippy warnings introduced
283+
- [ ] Code follows module organization conventions
284+
285+
**Import Updates**:
286+
287+
- [ ] All imports in CLI/presentation layer updated
288+
- [ ] All imports in tests updated
289+
- [ ] All imports in other application modules updated
290+
- [ ] Parent `mod.rs` correctly re-exports types for convenience
291+
292+
**Structure Verification**:
293+
294+
- [ ] Each command handler has `mod.rs`, `handler.rs`, `errors.rs`
295+
- [ ] Each has `tests/` subdirectory with `mod.rs`, `builders.rs`, `integration.rs`
296+
- [ ] Parent `mod.rs` correctly imports and re-exports all handlers
297+
- [ ] No orphaned files or unused code
298+
299+
**Commit Strategy**:
300+
301+
- [ ] Each command handler refactoring committed independently
302+
- [ ] Pre-commit checks pass before each commit
303+
- [ ] Clear, descriptive commit messages following conventional commits format
304+
- [ ] Final documentation commit separate from refactoring commits
305+
306+
## Related Documentation
307+
308+
- [Module Organization Guide](../contributing/module-organization.md) - File organization conventions
309+
- [Error Handling Guide](../contributing/error-handling.md) - Error type patterns and `.help()` methods
310+
- [Testing Conventions](../contributing/testing.md) - Test organization and naming
311+
- [Codebase Architecture](../codebase-architecture.md) - DDD layer structure
312+
- Reference Implementation: `src/application/command_handlers/create/` - Example of target structure
313+
314+
## Benefits
315+
316+
### Maintainability ✅
317+
318+
- **Smaller files**: Easier to navigate (200-300 lines vs 752 lines)
319+
- **Single responsibility**: Each file has one clear purpose
320+
- **Easier reviews**: Changes to errors don't require reviewing handler logic
321+
322+
### Scalability ✅
323+
324+
- **Room to grow**: Can add validators, mappers without bloating main file
325+
- **Test organization**: Can add more test modules easily
326+
- **Better IDE support**: Smaller files improve code navigation
327+
328+
### Consistency ✅
329+
330+
- **Uniform patterns**: All command handlers follow same structure
331+
- **Predictable locations**: Developers know where to find handler vs errors vs tests
332+
- **Easier onboarding**: New contributors understand structure quickly
333+
334+
### Testing ✅
335+
336+
- **Dedicated test builders**: Clear separation of test fixtures
337+
- **Integration tests isolated**: Easier to maintain and extend
338+
- **Better test discoverability**: Tests organized by purpose
339+
340+
## Notes
341+
342+
### Migration Order Rationale
343+
344+
Starting with `provision` (largest, most complex) first because:
345+
346+
1. It demonstrates the most value (752 → ~600 total lines split appropriately)
347+
2. Establishes patterns for subsequent migrations
348+
3. Most complex case first helps validate the approach
349+
350+
### Preserving Git History
351+
352+
Consider using `git mv` where possible to preserve file history:
353+
354+
```bash
355+
# When creating new files, use git mv for better history tracking
356+
git mv src/application/command_handlers/provision.rs \
357+
src/application/command_handlers/provision/handler.rs
358+
```
359+
360+
However, since we're splitting files, manual creation may be clearer.
361+
362+
### Breaking Changes: Acceptable
363+
364+
**Important**: Since this library is not yet publicly used, breaking changes to import paths are acceptable and even encouraged if they simplify the refactoring:
365+
366+
- ✅ Import paths will change (e.g., `use crate::application::command_handlers::provision::ProvisionCommandHandler`)
367+
- ✅ Can simplify re-exports if it improves clarity
368+
- ✅ Focus on best final structure, not backward compatibility
369+
- ⚠️ Business logic must remain unchanged (pure refactoring)
370+
- ⚠️ All existing tests must still pass (behavior unchanged)
371+
372+
This freedom allows us to:
373+
374+
- Create the cleanest possible module structure
375+
- Avoid complex re-export chains just for compatibility
376+
- Optimize for maintainability over backward compatibility
377+
378+
### Future Work
379+
380+
After this refactoring, consider:
381+
382+
- Adding more comprehensive test coverage where gaps exist
383+
- Extracting common patterns into shared utilities
384+
- Creating ADR documenting this as the standard command handler pattern

0 commit comments

Comments
 (0)