Module Splitting Implementation Guide
Related: Module Splitting Analysis
Status: Ready for Implementation
Priority: LOW (Tech Debt)
Quick Start
This guide provides step-by-step instructions for implementing the module splits identified in the analysis document.
Prerequisites
Before starting any module split:
- Create a feature branch:
git checkout -b refactor/split-<module-name> - Ensure all tests pass:
cd icn && cargo test -p <crate-name> - Backup the current file:
cp src/file.rs src/file.rs.backup
Implementation: ledger.rs Split
Phase 1: Extract Query Operations (Lowest Risk)
Risk: ๐ข Low
Step 1.1: Create Module Directory
cd icn/crates/icn-ledger/src
mkdir -p ledger_impl
Step 1.2: Create queries.rs
touch ledger_impl/queries.rs
Add this content:
//! Query operations for ledger entries
//!
//! This module contains read-only operations that query the ledger
//! without modifying state.
use crate::error::Result;
use crate::types::{ContentHash, JournalEntry};
use anyhow::Context;
use icn_identity::Did;
use icn_store::Store;
use std::sync::Arc;
use tracing::warn;
// Re-export pagination types from parent
pub use super::PaginationCursor;
// Constants (copy from ledger.rs)
const JOURNAL_PREFIX: &str = "ledger:journal:";
const JOURNAL_TS_PREFIX: &str = "ledger:journal_ts:";
const ARCHIVE_PREFIX: &str = "ledger:archive:";
/// Query operations for the ledger
pub struct LedgerQueries {
store: Arc<dyn Store>,
}
impl LedgerQueries {
pub fn new(store: Arc<dyn Store>) -> Self {
Self { store }
}
// TODO: Move query functions here:
// - get_entry()
// - get_all_entries()
// - count_entries()
// - get_entries_paginated()
// - get_entries_paginated_asc()
// - get_entries_filtered_paginated()
// - get_archived_entries()
// - list_rollback_timestamps()
}
Step 1.3: Move Functions
Copy these functions from ledger.rs to ledger/queries.rs:
- Lines 2184-2195:
get_entry() - Lines 2198-2212:
get_all_entries() - Lines 2218-2221:
count_entries() - Lines 2237-2281:
get_entries_paginated() - Lines 2297-2328:
get_entries_paginated_asc() - Lines 2358-2495:
get_entries_filtered_paginated() - Lines 3511-3522:
get_archived_entries() - Lines 3525-3545:
list_rollback_timestamps()
Important:
- Change
&selfto useself.storefor the moved functions - Update function signatures to be standalone or methods on
LedgerQueries - Keep doc comments
Step 1.4: Update ledger.rs
In ledger.rs, add at the top of the file (after existing module declarations):
mod ledger_impl;
pub use ledger_impl::queries::LedgerQueries;
Note: The submodule directory should be named ledger_impl/ to avoid naming conflict with ledger.rs.
Then in the impl Ledger block, replace the moved functions with delegation:
impl Ledger {
// ... existing code ...
/// Get a journal entry by its hash
pub fn get_entry(&self, hash: &ContentHash) -> Result<Option<JournalEntry>> {
let queries = LedgerQueries::new(self.store.clone());
queries.get_entry(hash)
}
// ... repeat for all query functions ...
}
Step 1.5: Create ledger_impl/mod.rs
touch ledger_impl/mod.rs
Add this content:
//! Ledger implementation submodules
pub mod queries;
// Re-export commonly used types
pub use queries::LedgerQueries;
Step 1.6: Test
cd ../../../ # Back to icn/ directory
cargo test -p icn-ledger
cargo clippy -p icn-ledger
cargo fmt -p icn-ledger
Step 1.7: Commit
git add .
git commit -m "refactor(ledger): Extract query operations to submodule
- Move read-only query functions to ledger/queries.rs
- Maintain backward compatibility via delegation
- No API changes, all tests pass"
Phase 2: Extract Balance Operations
Risk: ๐ก Medium
Follow similar pattern as Phase 1, extracting:
get_balance()get_account_balances()get_all_balances()total_cleared_by()recompute_balances()recompute_balances_with_retry()load_cached_balances()save_cached_balances()load_cleared_volume_index()save_cleared_volume_index()
Create ledger_impl/balances.rs and follow steps 1.2-1.7.
Phase 3: Extract Fork Operations
Risk: ๐ข Low
Extract fork-related functions to ledger_impl/fork_ops.rs:
detect_forks()has_fork()detect_and_resolve_forks()quarantine_forked_entry()get_fork_stats()rebuild_fork_index()ensure_timestamp_index()
Phase 4: Extract Freeze Operations
Risk: ๐ข Low
Extract freeze-related functions to ledger_impl/freeze_ops.rs:
freeze_member()freeze_member_with_metadata()unfreeze_member()unfreeze_member_with_metadata()is_member_frozen()get_freeze_record()list_frozen_members()frozen_member_count()cleanup_expired_freezes()
Phase 5: Extract Witness Operations
Risk: ๐ก Medium
Extract witness-related functions to ledger_impl/witness_ops.rs:
requires_witnesses()effective_witness_policy()validate_witness_signatures()store_witness_signatures()load_witness_signatures()count_entry_signers()calculate_entry_value()
Phase 6: Final Validation
Risk: ๐ข Low
Run full test suite:
cargo test -p icn-ledger cargo test --workspace # Full integration testsRun linters:
cargo clippy --workspace -- -D warnings cargo fmt --all --checkCheck API compatibility:
cargo doc -p icn-ledger --no-deps # Verify all public APIs still availablePerformance check (optional):
cargo bench -p icn-ledger # Compare with baseline
Alternative Approach: Incremental PR Strategy
If preferred, each phase can be a separate PR:
- PR 1: Extract queries (least risky)
- PR 2: Extract balances
- PR 3: Extract forks
- PR 4: Extract freeze
- PR 5: Extract witness
This allows for:
- Easier code review
- Faster feedback cycles
- Incremental value delivery
- Reduced merge conflict risk
Rollback Plan
If a split causes issues:
Immediate Rollback:
git revert <commit-hash>Restore from Backup:
cp src/file.rs.backup src/file.rsCherry-pick Fix:
git cherry-pick <fix-commit>
Success Criteria
โ
All tests pass
โ
No public API changes
โ
Code compiles without warnings
โ
Documentation builds successfully
โ
No performance regressions
โ
Improved code navigation (smaller files)
โ
Clearer module boundaries
Common Pitfalls
Pitfall 1: Circular Dependencies
Problem: New module needs to reference parent
Solution: Use trait objects or pass dependencies explicitly
Pitfall 2: Lost Documentation
Problem: Doc comments not moved with functions
Solution: Always move complete doc blocks with functions
Pitfall 3: Broken Re-exports
Problem: Public API not accessible after split
Solution: Add pub use statements in parent module
Pitfall 4: Test Failures
Problem: Tests can't find moved functions
Solution: Update test imports to use new paths
Verification Checklist
Before merging each phase:
- All unit tests pass
- All integration tests pass
- No clippy warnings
- Code formatted with rustfmt
- Documentation builds without errors
- Public API unchanged (no breaking changes)
- PR description includes:
- Rationale for split
- Before/after file sizes
- Test results
- Performance impact (if any)
Getting Help
If you encounter issues:
- Check the Module Splitting Analysis for context
- Review git history:
git log --oneline docs/ - Search for similar refactorings:
git log --grep="refactor.*modul" - Ask in team chat/issue tracker
Additional Resources
- Rust API Guidelines
- Cargo Book - Package Layout
- Prior modularization:
docs/dev-journal/2025-12-13-phase4-nat-traversal-supervisor-modularization.md
Last Updated: 2026-01-23
Author: Analysis by GitHub Copilot