Co-authored-by: aider (openai/andrew/openrouter/mistralai/mistral-medium-3.1) <aider@aider.chat>
6.6 KiB
Refactoring Plan to Reduce Code Duplication
1. Create Core Service Layer
Files: src/core/ (new directory)
src/core/item_service.rs- Main service for item operations (synchronous)src/core/async_item_service.rs- Async wrapper for API usesrc/core/compression_service.rs- Compression handlingsrc/core/meta_service.rs- Metadata processingsrc/core/mod.rs- Module exportssrc/core/error.rs- Unified error handling
Reason: Extract common business logic from modes and APIs into reusable services Implementation:
- Move logic from modes (get, save, list, info) and API handlers into service functions
- Services should return structured data, not format output
- Handle compression, metadata, and database operations
- Keep core services synchronous for CLI performance
- Provide async wrappers using
tokio::task::spawn_blockingfor API use - Use streaming for pipeline efficiency (process data in chunks)
2. Create Common Data Structures
Files: src/core/types.rs
Reason: Standardize data structures used across modes and APIs
Implementation:
- Define structs for
Item,ItemWithContent,ItemWithMeta,Response<T> - Include conversion functions from database types (
From<db::Item>) - Add serialization/deserialization support for JSON/YAML
- Ensure all fields are properly documented
- Use zero-copy patterns where possible (slicing instead of copying)
3. Refactor CLI Modes to Use Services
Files:
src/modes/get.rssrc/modes/save.rssrc/modes/list.rssrc/modes/info.rssrc/modes/delete.rssrc/modes/diff.rssrc/modes/status.rs
Reason: Remove direct database and file system access from modes Implementation:
- Replace current implementations with calls to core services
- Keep only CLI-specific formatting and output logic
- Handle command-line argument parsing and validation
- Use synchronous services directly
- Implement streaming for stdin/stdout to maintain pipeline performance
4. Refactor REST API to Use Async Services
Files:
src/modes/server/api/item.rssrc/modes/server/api/status.rs
Reason: Remove business logic from HTTP handlers Implementation:
- Convert handlers to call async core services
- Keep only HTTP-specific code (status codes, headers, etc.)
- Use common error handling with conversions to HTTP responses
- Wrap synchronous service calls in
tokio::task::spawn_blocking
5. Refactor MCP Tools to Use Services
Files: src/modes/server/mcp/tools.rs
Reason: Remove duplication with REST API and CLI modes Implementation:
- Replace current implementation with calls to core services
- Keep only MCP protocol-specific logic
- Use synchronous services directly (MCP is typically local/short-lived)
- Standardize response format to match API/CLI
6. Create Common Error Handling
Files: src/core/error.rs
Reason: Standardize error types across the application
Implementation:
- Define comprehensive error enum with conversions:
- From database errors
- From I/O errors
- From compression errors
- From validation errors
- Implement conversions to:
anyhow::Error(for CLI)axum::http::StatusCode(for API)ToolError(for MCP)
- Provide user-friendly error messages
- Include error codes for programmatic handling
7. Update Database Layer for Batch Operations
Files: src/db.rs
Reason: Support efficient batch operations needed by services
Implementation:
- Add functions to get multiple items with their metadata and tags
- Add batch insertion/updates for tags and metadata
- Add transaction support for atomic operations
- Optimize queries for common access patterns
- Ensure all batch operations are properly documented
8. Add Integration Tests
Files: tests/integration/ (new directory)
Reason: Ensure refactored code maintains functionality and performance
Implementation:
- Test core services independently
- Test CLI modes and APIs through their public interfaces
- Verify compression, metadata, and database operations
- Include performance benchmarks for critical paths
- Use in-memory databases and tempfiles for isolation
- Test both sync and async service implementations
9. Performance Optimization Guidelines
Reason: Ensure the refactored version doesn't slow down pipelines Implementation:
- Use streaming for stdin/stdout processing (chunked I/O)
- Minimize buffering and memory copies
- Offload CPU-bound work (compression, plugins) to thread pools
- Provide fast-path options (e.g.,
--fastflag to skip metadata plugins) - Benchmark critical operations before/after refactoring
- Document performance characteristics
Implementation Order:
- Create core module structure and error types (
core/error.rs,core/types.rs) - Implement core services with basic functionality (sync first)
- Add async wrappers for API use
- Refactor one mode (e.g.,
get) to use services and validate approach - Refactor corresponding API endpoints to use async services
- Repeat for other modes and APIs
- Refactor MCP tools to use services
- Add comprehensive tests and benchmarks
- Clean up removed code from original files
- Document performance characteristics and tradeoffs
Benefits:
- Reduced code duplication between CLI, API, and MCP
- Easier maintenance with clear separation of concerns
- Consistent behavior across all interfaces
- Better testability with isolated service layer
- Maintained or improved pipeline performance
- Flexible architecture supporting both sync and async use cases
Key Risks and Mitigations:
-
Performance Regression:
- Risk: Refactoring could slow down pipeline operations
- Mitigation: Benchmark before/after, use streaming, minimize overhead
-
Increased Complexity:
- Risk: Adding service layer could make code harder to understand
- Mitigation: Clear documentation, gradual refactoring, maintain simple interfaces
-
Async/Sync Boundaries:
- Risk: Mixing sync/async could lead to deadlocks or inefficiencies
- Mitigation: Clear boundaries, use
spawn_blockingfor sync work in async context
-
Breaking Changes:
- Risk: Refactoring could change behavior in subtle ways
- Mitigation: Comprehensive tests, gradual rollout, maintain backward compatibility
Design Principles:
- Zero-Copy Where Possible: Use slicing instead of copying data
- Streaming Processing: Handle data in chunks for memory efficiency
- Clear Boundaries: Separate core logic from interface-specific code
- Performance First: Optimize for common pipeline use cases
- Consistent Errors: Unified error handling across all interfaces
- Backward Compatibility: Maintain existing CLI/API behavior