Compare
Symptom
Human

A constructor takes many positional arguments, several of which are optional and most of which are easy to swap by accident. Call sites pass null or 0 as placeholders for arguments that don't apply, and reviewers cannot tell from the call site which argument means what. The reader's rises at every call site.

Agent

The agent reads a multi-parameter constructor call and consults the constructor signature (often elsewhere in the codebase) to know which positional slot means what. Editing the call site requires keeping positional alignment correct on every parameter change. The agent's for the signature compounds across every reading, and the doubles for what reads as one construction.

Goal
Human

A step-by-step construction surface where each step is named after what it sets, optional inputs are explicit, and the moment of 'now build it' is a separate, terminal call. The product is immutable once built; partial construction states never leak, supporting between assembly and use.

Agent

Self-describing construction the agent reads top-to-bottom without cross-file lookup. Each chained method names what it sets; the build() terminator marks the point where the product is verified. The agent's holds the call chain and the builder definition; the count drops because positional alignment is no longer a verification axis.

Before the pattern

const request = new HttpRequest(
'GET',
'/api/users/42',
{ 'Accept': 'application/json', 'Authorization': 'Bearer xyz' },
null,
30000,
3,
true
);

After the pattern

const request = new HttpRequestBuilder('GET', '/api/users/42')
.accept('application/json')
.bearer('xyz')
.timeoutMs(30000)
.retries(3)
.followRedirects(true)
.build();
class HttpRequestBuilder {
constructor(method, url) {
this.spec = { method, url, headers: {}, body: null, timeoutMs: 0, retries: 0, followRedirects: false };
}
accept(mediaType) { this.spec.headers['Accept'] = mediaType; return this; }
bearer(token) { this.spec.headers['Authorization'] = `Bearer ${token}`; return this; }
body(value) { this.spec.body = value; return this; }
timeoutMs(ms) { this.spec.timeoutMs = ms; return this; }
retries(count) { this.spec.retries = count; return this; }
followRedirects(flag) { this.spec.followRedirects = flag; return this; }
build() { return new HttpRequest(this.spec); }
}
Example source: Illustrative example written for this site in the spirit of Design Patterns (Gamma, Helm, Johnson, Vlissides, Addison-Wesley, 1994), chapter 3. The book's running example is a maze builder; this JavaScript adaptation uses HTTP request construction to show the same step-by-step assembly with named, optional inputs and a single terminating build() that produces the immutable product.
Pressure
Human

Adding a new optional input to the constructor breaks every existing call site and forces each to add a placeholder for the new slot. Default values drift between languages, frameworks, and developer assumptions; the constructor signature stops describing what a valid request looks like. The team's compounds across every call site updated for a new optional input.

Agent

Positional argument lists are the worst-case input shape for context budget — the agent holds the parameter order in context while reading every call. Mis-aligned arguments produce type-compatible bugs that escape , exactly the bug class that demands the most verification effort. The agent's multiplies with parameter count.

Tradeoff
Human

The builder is a second object the reader navigates to understand what a fully-constructed product contains. Fluent chains hide the build step's complexity behind method-chaining syntax that some teammates find unidiomatic; debugging a misconfigured builder requires stepping through every chained call. The team's reshapes across two objects rather than one.

Agent

The builder's chainable method set is a second surface the agent reads alongside the product itself; tests cover construction paths separately from product behaviour, so the agent traces any regression through two surfaces instead of one. The agent's rises during the migration itself as every existing constructor call must be confirmed to route through the builder.

Relief
Human

Call sites read as a sequence of named decisions; new optional inputs are additive without breaking existing callers; the immutable product is constructed once and never mutated thereafter. Code review reads top-to-bottom in domain terms, not positional argument terms. The team's drops because adding an input is one builder method, not N call-site updates.

Agent

Call-site edits become append-or-remove single-line operations on the chain. The build() step is a structural commit the agent relies on as the moment of validation; partial-construction bugs surface as builder-test failures rather than runtime mysteries scattered across consumers of the product. The agent's per call-site edit drops to one chained method.

Trap
Human

Builders that allow .build() to be called from any state — including states where required inputs were skipped — defeat the immutability win and replace one bug class (positional confusion) with another (silently-incomplete construction). A builder without 'build() validates the full spec' is a fluent setter chain, not the pattern; the cure adds without delivering structural guarantees.

Agent

Inconsistent builder discipline — some builders enforce required-input checks at build(), others tolerate missing inputs and produce half-built products with default sentinels — forces the agent to verify enforcement on every new builder it encounters. The pattern stops being a structural promise and becomes a per-class convention to look up, raising retrieval cost on every read.