In a chained configuration API, what makes one call follow another, and what does the closing call add?
answer
- one call feeds the next
- the return value is the thread
- state accumulates on the receiver
- the last call is a different kind
- closing call validates, then produces
basics
~20 sEach configuring call returns a receiver carrying everything recorded so far, so the next call can be written straight onto it. The closing call is different: it validates the accumulated state and produces the finished result.
solid answer
~40 sA chain works because every configuring step hands back an object the next step can be called on. That returned receiver carries the accumulated state forward, which is why the steps can be written as one expression instead of a sequence of statements against a named variable. The steps themselves usually only record data — a path here, a handler there. The last call is a different kind of call: it looks at everything recorded as a whole, checks it is coherent, and returns the finished result, whose type is normally *not* chainable. So the chain describes something and the closing call realises it; drop the closing call and you have typed a description nobody ever asked to be built.
code
pseudocode · 11 linestable = newRoutingTable()
.route("/orders")
.method("GET")
.handler(listOrders)
.route("/orders")
.method("POST")
.handler(createOrder)
.build()
// each configuring call returned a receiver
// build() returned the routing table itselfgo deeper
Recall the one rule: a configuring call hands back an object the next call is written on, and the last call turns the accumulated description into a result.
Explain where the accumulated state lives, why the closing call is the only place a whole-configuration check can happen, and why its return type is deliberately not chainable.
Show you can read an unfamiliar chain cold: find the origin, the closing call and any step whose meaning depends on an earlier one, and say what the design makes hard to diagnose.
Weigh the readability win against the costs a team lives with: coarse failure reporting, invisible ordering rules, and half-built values that are legal to pass around.
## The rule that makes a chain possible A fluent API is an ordinary API plus one convention: **every configuring call returns an object that the next call can be written on**. Because each call gives a receiver back, the caller never has to name a variable between steps, and what would have been a paragraph of statements collapses into a single expression that reads close to a sentence. Two consequences follow immediately: - **The return value is the thread.** A step that returned nothing would end the chain there. The whole readability effect rests on what each step hands back, not on how the step is named. - **State has to accumulate somewhere.** Each step records something — a path, a request method, a handler. The object that comes back must carry everything recorded so far, or later steps would have nothing to attach to. That is the entire mechanism. Everything else in this style is a consequence of it. ## Two kinds of call in one chain Reading an unfamiliar chain is mostly a matter of separating the two kinds of call in it. | | Intermediate call | Closing call | |---|---|---| | What it returns | a receiver that can be chained further | the finished result, normally a different type | | What it does | records one piece of state | inspects the accumulated state and produces the result | | If it is omitted | that one piece is simply unset | usually nothing is produced at all | | How often it appears | many times, in a legal order | once, at the end | The closing call is the call that earns the design. Until it runs, the chain has only *described* something. It is also the only point at which the accumulated state is visible as a whole, which is why it is the natural home for checks no single step could make on its own: that a path was actually given, that a handler was attached to it, that two entries do not claim the same route. ## Reading a chain you did not write 1. **Find the origin.** Something produced the first receiver — a factory call, an empty collection of entries, a fresh configuration object. That is what the whole chain is accumulating into. 2. **Find the closing call.** It is normally the last call, and normally the only one whose name is a verb of completion rather than a noun of configuration. 3. **Classify the middle.** Each remaining call is one recorded fact. Their order may or may not matter — that is a property of the specific API, not of chaining. 4. **Ask what the chain's value is used for.** If the expression's result is assigned or passed on, the closing call is present and its result matters. If the whole expression stands alone as a statement, look hard: either a step had an effect of its own, or the chain does nothing. ## Where the accumulated state actually lives There are two common contracts, and the difference is invisible at the call site: - **Mutate and return the same receiver.** Each step changes one object and hands the very same object back. Cheap, and the chain reads identically. - **Return a fresh receiver.** Each step produces a new object carrying the old state plus one addition, leaving the previous one untouched. Both chain. They differ only once a partly built chain is stored in a variable and used more than once — which is exactly why an API that supports that use has to say which contract it offers. ## What the style costs Chaining is not free, and an interviewer usually wants to hear that you know the bill: - **A failure is reported against the whole expression.** One long expression gives a diagnostic less precise than a statement per step. - **Ordering rules become invisible.** If a step is only meaningful after another, nothing in a uniform chain says so. - **A half-finished chain is a perfectly legal value.** It can be stored, passed and returned, even though it represents nothing usable yet. - **Discoverability depends entirely on return types.** What may be written next is whatever the returned type offers, so a single broad receiver type offers everything everywhere — convenient to build, uninformative to read. The pay-off is the one everybody notices first: a reader who has never seen the API can often follow what a chain configures on the first pass, because the calls sit in the order the domain would state them.
- Why is it useful that the closing call returns a type that cannot be chained further?It separates describing from having. A non-chainable result type tells the reader the chain is over, stops configuration calls being written after the state was already frozen, and lets the surrounding code demand that type — which in turn makes an omitted closing call visible rather than silent.
- Does the order of the configuring calls in a chain matter?It depends on the API. If each step records an independent fact, order is free. If a step refines whatever the previous step opened, or overwrites a value an earlier step set, order is part of the contract — and a uniform chain gives the reader no signal either way, so it has to be documented or encoded in the return types.
saying these in an interview costs you the question
- Thinks each chained call has already applied its change permanently
- Says chaining is only about saving keystrokes
- Believes the closing call is optional sugar
- Claims the closing call returns the same chainable receiver
- Assumes chaining requires the underlying object to be immutable