Skip to content

Parameterize Function

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.

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.

Two functions that compute a discounted price, differing only by the rate. After, one function takes the rate as a parameter.

// Before
function 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);
// After
function discountedPrice(price: number, rate: number): number {
return price - price * rate;
}
const a = discountedPrice(200, 0.05);
const b = discountedPrice(200, 0.10);
  1. Pick one of the near-identical functions to be the template.
  2. Add a parameter for the value that varies. Give it a descriptive name like rate or threshold, not value.
  3. 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.
  4. For each remaining clone, redirect its callers to the parameterized function, passing the clone’s specific literal as the argument.
  5. Run your tests after redirecting each clone, so a failure points at one call.
  6. Once nothing calls the old clones, delete them.
  7. 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.

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.

What pattern signals that Parameterize Function applies?
After adding the parameter to the template function, what confirms you have not changed its behaviour?
What is a downside of a bare literal argument at the call site?
When does a difference between functions suggest splitting rather than parameterizing?