Parameterize Function
Intent
Section titled “Intent”Spot two or more functions whose bodies are the same except for one baked-in value, then collapse them into a single function that takes that value as a parameter. The duplicated logic now lives in exactly one place, and the difference between the old variants becomes a visible argument at the call site.
The smell
Section titled “The smell”This is a flavour of Duplicated Code. You see discountFivePercent and discountTenPercent sitting next to each other, identical apart from the number. Or tierBronze and tierSilver, differing only by a threshold. Every time the shared logic needs a fix, you have to remember to fix each clone — and one day you will forget one. The hard-coded constant is the only thing that varies, so it wants to be an argument, not a copy of the whole function.
Before → After
Section titled “Before → After”Two functions that compute a discounted price, differing only by the rate. After, one function takes the rate as a parameter.
// Beforefunction priceWithFivePercentOff(price: number): number { return price - price * 0.05;}
function priceWithTenPercentOff(price: number): number { return price - price * 0.10;}
const a = priceWithFivePercentOff(200);const b = priceWithTenPercentOff(200);
// Afterfunction discountedPrice(price: number, rate: number): number { return price - price * rate;}
const a = discountedPrice(200, 0.05);const b = discountedPrice(200, 0.10);# Beforedef price_with_five_percent_off(price): return price - price * 0.05
def price_with_ten_percent_off(price): return price - price * 0.10
a = price_with_five_percent_off(200)b = price_with_ten_percent_off(200)
# Afterdef discounted_price(price, rate): return price - price * rate
a = discounted_price(200, 0.05)b = discounted_price(200, 0.10)// Beforefunc PriceWithFivePercentOff(price float64) float64 { return price - price*0.05}
func PriceWithTenPercentOff(price float64) float64 { return price - price*0.10}
a := PriceWithFivePercentOff(200)b := PriceWithTenPercentOff(200)
// Afterfunc DiscountedPrice(price, rate float64) float64 { return price - price*rate}
a := DiscountedPrice(200, 0.05)b := DiscountedPrice(200, 0.10)// Beforefn price_with_five_percent_off(price: f64) -> f64 { price - price * 0.05}
fn price_with_ten_percent_off(price: f64) -> f64 { price - price * 0.10}
let a = price_with_five_percent_off(200.0);let b = price_with_ten_percent_off(200.0);
// Afterfn discounted_price(price: f64, rate: f64) -> f64 { price - price * rate}
let a = discounted_price(200.0, 0.05);let b = discounted_price(200.0, 0.10);Mechanics
Section titled “Mechanics”- Pick one of the near-identical functions to be the template.
- Add a parameter for the value that varies. Give it a descriptive name like
rateorthreshold, notvalue. - Inside the body, replace the hard-coded literal with the new parameter. Run your tests — behaviour should be unchanged for that one function’s original case when you pass its old constant.
- For each remaining clone, redirect its callers to the parameterized function, passing the clone’s specific literal as the argument.
- Run your tests after redirecting each clone, so a failure points at one call.
- Once nothing calls the old clones, delete them.
- Consider whether the new parameter should be validated — for example, a discount rate outside the range zero to one is probably a bug worth rejecting.
When to use / trade-offs
Section titled “When to use / trade-offs”Reach for this when functions differ only by a constant, when you are about to copy-paste a function and tweak one number, or when a family of named variants keeps growing. Parameterizing kills the duplication and makes the varying dimension explicit and discoverable.
The trade-off is that a literal argument at the call site can be less self-documenting than a well-named function — a bare 0.05 says less than priceWithFivePercentOff. If the set of values is small and meaningful, named constants or an enum at the call site restore that clarity. And resist over-parameterizing: a function with eight knobs is harder to use than the clones it replaced.