Skip to content
aipatterns.dev

Refactoring techniqueSimplifying Method Calls

Replace Parameter with Method Call

Stop passing a value the method can obtain itself; have the method call the query directly and drop the parameter.

Also known as
Replace Parameter with Query

Problem

A caller computes a value by calling a method and then passes the result into another method. The receiving method could have called that same query itself. The parameter only lengthens the signature and forces every caller to repeat the computation.

Solution

Remove the parameter and have the method call the query internally.

Before

TypeScript
class Shipment {
  constructor(private order: Order, private carrier: Carrier) {}

  dimensionalWeight(): number {
    return (this.order.lengthCm * this.order.widthCm * this.order.heightCm) / 5000;
  }

  label(billableWeight: number): ShippingLabel {
    return this.carrier.createLabel({ orderId: this.order.id, weightKg: billableWeight });
  }
}

const billable = Math.max(shipment.dimensionalWeight(), order.weightKg);
const label = shipment.label(billable);

After

TypeScript
class Shipment {
  constructor(private order: Order, private carrier: Carrier) {}

  dimensionalWeight(): number {
    return (this.order.lengthCm * this.order.widthCm * this.order.heightCm) / 5000;
  }

  billableWeight(): number {
    return Math.max(this.dimensionalWeight(), this.order.weightKg);
  }

  label(): ShippingLabel {
    return this.carrier.createLabel({ orderId: this.order.id, weightKg: this.billableWeight() });
  }
}

const label = shipment.label();

Why

  • Callers cannot pass a wrong or stale value, because they no longer pass anything.
  • The rule for billable weight lives in one place, next to the data it reads.
  • Shorter signatures and simpler call sites.

Steps

  1. Confirm the value passed is always computed the same way, from data the method can reach.
  2. If the computation is an expression, extract it into a query method on the receiving class. Run the tests.
  3. Inside the method, replace uses of the parameter with a call to the query. Run the tests.
  4. Remove the parameter with Remove Parameter, updating callers. Run the tests.

Watch out

  • Do not do this when callers pass different values on purpose, such as an override for a manual weight. The parameter is then a real input.
  • Do not do this if it makes the method depend on something it should not, like a global clock, a database or a service locator. A parameter is easier to test than a hidden call to Date.now(). The inverse direction, passing the value in, is how you remove such dependencies.
  • The query must be cheap or cached if the method calls it repeatedly, and it must return the same value the caller would have passed at that moment.
  • The inverse is Replace Query with Parameter, performed with Add Parameter: move the query out to callers and pass its result in.

Agent checklist

  • All callers computed the argument the same way.
  • The method can reach the data without new dependencies on globals, time or I/O.
  • The query returns the same value at the new call time as at the old one.
  • Tests that passed custom values now set up the underlying data instead.

Treats these smells

See also

Original writing and examples. Topic coverage follows Refactoring.Guru, which explains this topic with its own illustrations.