Skip to content

Introduce Parameter Object

Find a group of arguments that keep appearing together across several functions, and replace them with a single object that holds them all. The cluster gets a name, the relationship between the values becomes explicit, and every function that took the loose arguments now takes one tidy parameter.

This cures the Long Parameter List and its cousin the Data Clump — the same two or three values passed side by side, in the same order, to function after function. A start and end that are really a date range. A latitude and longitude that are really a location. When values travel as a pack, that pack is a concept the code has not named yet. Worse, a long bare list invites the classic mistake of passing the arguments in the wrong order.

A flight booking that drags four loosely-related arguments around. After, they become a single Trip object.

// Before
function bookFlight(
from: string,
to: string,
startDate: string,
endDate: string,
): string {
return `Flight ${from}->${to} from ${startDate} to ${endDate}`;
}
const summary = bookFlight("BKK", "NRT", "2026-07-01", "2026-07-09");
// After
interface Trip {
from: string;
to: string;
startDate: string;
endDate: string;
}
function bookFlight(trip: Trip): string {
return `Flight ${trip.from}->${trip.to} from ${trip.startDate} to ${trip.endDate}`;
}
const summary = bookFlight({
from: "BKK",
to: "NRT",
startDate: "2026-07-01",
endDate: "2026-07-09",
});
flowchart LR
  subgraph Before["Before"]
    A["bookFlight(<br/>from, to,<br/>startDate, endDate)"]
  end
  subgraph After["After"]
    B["bookFlight(trip)"]
    B --> C["Trip<br/>{ from, to,<br/>startDate, endDate }"]
  end
  Before -.->|"Introduce Parameter Object"| After
Four loose arguments become one named Trip object
  1. Identify the clump — the arguments that always appear together. Pick a name for the concept they represent.
  2. Create a new structure (a class, struct, record, or interface) with a field for each member of the clump.
  3. Add the new object as a parameter to one target function, alongside the existing arguments at first. Run your tests.
  4. Inside the body, start reading from the object’s fields instead of the loose parameters, one field at a time, testing as you go.
  5. Once the body reads only from the object, remove the now-unused loose parameters from the signature, then update that function’s callers to build and pass the object.
  6. Repeat for the other functions that share the same clump, so they all take the object.
  7. Run your tests after each function. Watch for new behaviour to emerge: once the data lives together, logic that operated on it often wants to move onto the object too.

Introduce a parameter object when the same values are passed together repeatedly, when a parameter list has grown long enough that callers get the order wrong, or when you sense an unnamed concept hiding inside the argument list. The object documents the relationship and gives behaviour that belongs to the group a natural home.

The trade-off is an extra type to define and a small amount of ceremony to construct it at each call. For a one-off two-argument call that never recurs, that ceremony may not pay for itself. The win grows with reuse: the more functions share the clump, the more the object earns its keep — and the more it becomes a magnet for related methods.

Which smells does Introduce Parameter Object primarily address?
Why is a group of arguments that always travel together significant?
What often happens after the data is grouped into one object?
When might introducing a parameter object not pay off?