2.1 KiB
2.1 KiB
Common Refactoring Patterns
Extract Method
When: Duplicated code or long function
// Before: Long function
fn process(data: Vec<i32>) -> i32 {
let mut sum = 0;
for x in data {
sum += x * x;
}
sum
}
// After: Extracted method
fn process(data: Vec<i32>) -> i32 {
data.iter().map(|x| square(x)).sum()
}
fn square(x: &i32) -> i32 {
x * x
}
Steps:
- Extract square() function
- Run tests
- Commit
- Replace loop with iterator
- Run tests
- Commit
Rename Variable/Function
When: Name is unclear or misleading
// Before
fn calc(d: Vec<i32>) -> f64 {
let s: i32 = d.iter().sum();
s as f64 / d.len() as f64
}
// After - Step by step
// Step 1: Rename function
fn calculate_average(d: Vec<i32>) -> f64 { ... } // Test, commit
// Step 2: Rename parameter
fn calculate_average(data: Vec<i32>) -> f64 { ... } // Test, commit
// Step 3: Rename variable
fn calculate_average(data: Vec<i32>) -> f64 {
let sum: i32 = data.iter().sum(); // Test, commit
sum as f64 / data.len() as f64
}
Extract Class/Struct
When: Class has multiple responsibilities
// Before: God object
struct UserService {
db: Database,
email_validator: Regex,
name_validator: Regex,
}
// After: Single responsibility
struct UserService {
db: Database,
validator: UserValidator, // EXTRACTED
}
struct UserValidator {
email_pattern: Regex,
name_pattern: Regex,
}
Steps:
- Create empty UserValidator struct
- Test, commit
- Move email_validator field
- Test, commit
- Move name_validator field
- Test, commit
- Update UserService to use UserValidator
- Test, commit
Inline Unnecessary Abstraction
When: Abstraction adds no value
// Before: Pointless wrapper
fn get_user_email(user: &User) -> &str {
&user.email
}
fn process() {
let email = get_user_email(&user); // Just use user.email!
}
// After: Inline
fn process() {
let email = &user.email;
}
Steps:
- Replace one call site with direct access
- Test, commit
- Replace next call site
- Test, commit
- Remove wrapper function
- Test, commit