Combine Functions into Class

Referenced by patterns
Compare
Symptom
Human

Two or more functions all take the same data shape as their first parameter and operate on its fields — passive data being acted on from outside.

Agent

The agent finds multiple functions that all take the same data shape; reasoning about the data requires loading every operation that touches it scattered across files.

Goal
Human

Functions that all act on the same data live alongside it as methods; calls become method calls on a domain object.

Agent

Operations live with the data they act on; the agent loads one class to reason about both shape and behavior.

Before the refactoring

function baseCharge(reading) {
return reading.kwh * reading.tariff.baseRate;
}
function taxableCharge(reading) {
return baseCharge(reading) + reading.kwh * reading.tariff.taxRate;
}

After the refactoring

class Reading {
constructor({ kwh, tariff }) { this.kwh = kwh; this.tariff = tariff; }
baseCharge() { return this.kwh * this.tariff.baseRate; }
taxableCharge() { return this.baseCharge() + this.kwh * this.tariff.taxRate; }
}
Example source: Illustrative example written for this site, not a quotation from any source.
Pressure
Human

The data's invariants aren't enforced anywhere; logic that belongs together scatters across modules; new operations have to re-import the data shape and re-derive its rules.

Agent

The agent traces operations across modules to understand what the data can do; invariants the agent must respect aren't enforced at construction.

Tradeoff
Human

Wrapping passive data in a class that nobody else uses adds ceremony — only combine when 2+ functions take the same data and would benefit from co-located behavior.

Agent

Wrapping the data in a class adds construction ceremony at every entry point; for data only used in one place the class is more code than the original concern warranted.

Relief
Human

Encapsulation tightens; tests target the class; new operations land in one obvious place.

Agent

The agent loads the class as a single unit; behavior, fields, and invariants all in one place with one import.

Trap
Human

Wrapping passive data in a class that nobody else needs to be a class — adds construction ceremony at every entry point with no encapsulation gain.

Agent

Wrapping data that nobody else operates on creates a class the agent must instantiate everywhere with no encapsulation gain — pure overhead.