Refactoring techniqueSimplifying Method Calls
Parameterize Method
Merge several methods that do the same thing with different literal values into one method that takes the value as a parameter.
- Also known as
- Parameterize Function
Problem
You have several methods with almost identical bodies. They differ only in a number, a string or a threshold. A bug fix in one is easily missed in the others, and adding a new variant means copying a method again.
Solution
Replace the family of methods with one method that takes the differing value as a parameter.
Before
class RetentionReport {
activeLast7Days(events: UsageEvent[], now: Date): number {
const since = now.getTime() - 7 * DAY_MS;
return new Set(events.filter((e) => e.at.getTime() >= since).map((e) => e.userId)).size;
}
activeLast30Days(events: UsageEvent[], now: Date): number {
const since = now.getTime() - 30 * DAY_MS;
return new Set(events.filter((e) => e.at.getTime() >= since).map((e) => e.userId)).size;
}
activeLast90Days(events: UsageEvent[], now: Date): number {
const since = now.getTime() - 90 * DAY_MS;
return new Set(events.filter((e) => e.at.getTime() > since).map((e) => e.userId)).size;
}
}After
class RetentionReport {
activeUsers(events: UsageEvent[], now: Date, windowDays: number): number {
const since = now.getTime() - windowDays * DAY_MS;
const recent = events.filter((e) => e.at.getTime() >= since);
return new Set(recent.map((e) => e.userId)).size;
}
}
report.activeUsers(events, now, 30);Why
- One body to read, test and fix.
- New variants (14 days, 365 days) need no new code.
- Differences that were accidental become visible. The 90-day version used
>instead of>=.
Steps
- Line up the methods and list every difference between their bodies. Each difference should be a value, not a different algorithm.
- Resolve accidental differences first. Here, decide whether the boundary is inclusive, and fix the odd method out with a test that pins the chosen behavior.
- Pick one method, add a parameter for the varying value, and replace the literal with it. Run the tests.
- Change each sibling method to call the parameterized method with its literal. Run the tests.
- Move callers to the parameterized method and delete the siblings, or keep them as named shortcuts if they read better at call sites.
Watch out
- Do not merge methods whose bodies differ in logic, not only values. The resulting method would need flags and branches.
- If callers almost always pass one of a few fixed values, named methods can be clearer than a magic number. Keep thin wrappers like
activeLast30Days()that delegate. - Validate the new parameter's range if the old literals were implicitly safe (no negative window, no zero divisor).
- The inverse technique is Replace Parameter with Explicit Methods.
Related
- Fixes Duplicate Code.
- Inverse: Replace Parameter with Explicit Methods.
- Uses Add Parameter.
Agent checklist
- The merged methods differed only in values, not in control flow.
- Accidental differences between copies were resolved deliberately, with a test.
- The parameter has a clear name and unit (
windowDays, notn). - Invalid values for the new parameter are rejected or impossible.
Treats these smells
See also
- Replace Parameter with Explicit MethodsSplit a method that branches on a flag or enum argument into one clearly named method per value.
- Add ParameterGive a method a new parameter when it needs data it cannot reach, migrating callers through a temporary overload or default value.
- Extract MethodMove a coherent fragment of a long function into its own well-named function and call it from the original place.
Original writing and examples. Topic coverage follows Refactoring.Guru, which explains this topic with its own illustrations.