| name | code-refactoring |
| description | Use when refactoring large files (800+ lines) — both source and test code — by splitting into sibling modules or submodules based on scope and concern boundaries. |
code-refactoring
SDLC Phase: Maintenance
Refactor large files by extracting cohesive groups into separate modules while preserving behaviour.
Principles
- Behaviour preservation — The refactored code must produce identical results. No logic changes during refactoring.
- Cohesive grouping — Extract groups of code that belong together: a type + its impls, a family of algorithms, related utilities.
- Incremental extraction — Extract one module at a time, verifying after each step.
- Smell-first, structure-second — Fix code smells (duplication, tight coupling, magic numbers) in place before moving code between files.
When to Refactor
| File Size | Action |
|---|
| < 400 lines | No action needed |
| 400–800 lines | Monitor; consider extracting if concern boundaries are clear |
| > 800 lines | Extract cohesive groups into separate modules |
Exceptions: A file that is 800+ lines but has one clear responsibility and no code smells may be left as-is.
Sibling vs Submodule Decision
| Criterion | Sibling (mod) | Submodule (dir/mod.rs) |
|---|
| Extracted code is a peer concern at the same abstraction level | ✅ | ❌ |
| Extracted code is a supporting detail of the current module | ❌ | ✅ |
| Other sibling modules would import from it | ✅ | ❌ |
| It implements a single trait or type | ❌ | ✅ |
| It is a standalone utility used by 2+ siblings | ✅ | ❌ |
Rule of thumb: If the extracted code would feel natural as a separate file at the crate root, make it a sibling. If it is an internal detail that only the parent module touches, keep it as a submodule.
Code Smell Remediation
When refactoring, address these smells:
Duplicated Code
- Extract repeated logic into a shared function in the lowest common parent.
- Consider a generic trait + blanket impl for near-identical
impl blocks.
Long Parameter List (5+ params)
- Introduce a parameter struct or builder pattern to group related parameters.
Feature Envy
- A method that accesses another struct's data more than its own should move to that struct.
Global Mutable State
static mut, AtomicBool at module level — isolate in a single state.rs module with clear enable/disable/reset functions.
- Pass state explicitly through function parameters where possible.
Magic Numbers/Strings
- Extract inline literals with domain meaning to named
const at module top or a constants.rs sibling.
Tight Coupling
- Module A reaches into B's internals. Define a facade in B that exposes only what consumers need.
Circular Dependencies
- Modules A and B import each other. Extract their shared types (error types, trait definitions, simple data structs) into a third module C.
Test File Refactoring
- Split by domain:
algebra_tests.rs, calculus_tests.rs, not by function.
- Shared test utilities go in
tests/common/mod.rs (Cargo treats tests/common.rs as a test binary).
- Large
describe blocks stay in the test file; split the suite function, not individual test closures.
- Reusable test infrastructure goes in
src/*/test_utils.rs behind #[cfg(test)].
Verification Checklist
After each extraction step, verify:
Output Requirements
- A summary of what was extracted and why
- Before/after module structure
- Any remaining issues registered as GitHub Issues with code comments linking to them