Skip to content

Remove Setting Method

Some fields are part of an object’s identity: an account number, a creation timestamp, a currency. They should be chosen when the object is born and never touched again. If such a field has a setter, anyone can quietly mutate it later. Move the assignment into the constructor and delete the setter, so the field is set exactly once and the object is immutable in that respect.

You construct an object, then immediately call a setter to give it a value that will never legitimately change — new Account(); account.setId(42). The two-step birth invites a third party to call the setter again, far from construction, and corrupt the object’s identity. A setter that exists only to be called once at the start is a setter that should not exist.

An Account exposes a settable id. We accept the id in the constructor and remove setId, making the identity permanent. In Go and Rust there is no setter to begin with — the point is to fix the value at construction and expose no mutator.

// Before
class Account {
private _id = 0;
setId(id: number): void { this._id = id; }
get id(): number { return this._id; }
}
const account = new Account();
account.setId(42);
// After
class Account {
constructor(private readonly _id: number) {}
get id(): number { return this._id; }
}
const account = new Account(42);
flowchart LR
  subgraph Before["Before"]
    A["new Account()<br/>then setId(...)<br/>setId callable anytime"]
  end
  subgraph After["After"]
    B["new Account(id)<br/>id fixed forever<br/>no setId"]
  end
  Before -.->|"Remove Setting Method"| After
A two-step build with a setter becomes a one-shot immutable construction
  1. If the constructor cannot yet accept the field, add it as a parameter and assign it inside the constructor.
  2. Update every caller that creates the object to pass the value through the constructor instead of via the setter. Run your tests after each.
  3. Search for any remaining calls to the setter. If a caller still mutates the field after construction, decide whether that is a real requirement — if so, this field is not a candidate; if not, route it through the constructor.
  4. Once no caller uses the setter, delete it.
  5. Where the language allows, mark the field readonly/final/private-with-no-mutator so the compiler enforces the immutability.

Apply this to fields that define identity or are fixed for the object’s lifetime, and to value objects you want to treat as immutable so they can be shared and cached freely. Removing the setter shrinks the surface area for bugs: a value that cannot change cannot be changed at the wrong time.

The trade-off is constructor pressure. If many such fields exist, the constructor’s parameter list can grow long — that is a cue for Introduce Parameter Object or a builder, not a reason to keep the setters. And genuinely mutable state — a balance, a status — still needs a controlled way to change; do not strip setters that model real, ongoing change. Frameworks that require a no-arg constructor and field injection may also force a compromise here.

Which kind of field is the right target for Remove Setting Method?
Where does the field’s value get assigned after the refactoring?
What is the main benefit of removing the setter?
If removing setters leaves the constructor with too many parameters, what is the right response?