You set the binding strategy for many teams' command-line tools: generate binders, inspect while running, or ship a hybrid — how do you decide?
answer
- measure before you choose
- who pays the build, who gets the saving
- which declarations exist at build time
- hybrid keeps the engine forever reachable
- a silent fallback decays into inspection
basics
~20 sDecide from four facts: whether binding is genuinely inside the startup budget, whether every bound declaration exists while the build runs, whether the artifact must survive a whole-program build, and who pays the build cost. The hybrid is the default worth defending, provided its fallback is loud.
solid answer
~50 sStart by making the decision empirical rather than aesthetic: measure what binding costs in the startup window, count how many bound declarations arrive after the build, and check whether artifacts are shrunk or compiled whole. If everything is known at build time and the budget is tight, generate. If types arrive later, or the build cost lands on teams who get nothing back, inspect. The **hybrid** — use an emitted binder when one is registered, otherwise inspect — is usually the honest answer, but it has a real price: two code paths to keep behaviourally identical, an inspection engine the analyser can never delete, and a fallback that silently absorbs regressions. So the policy, not the mechanism, is what you actually set: generation on by default, the fallback observable, and a strict mode that fails where the budget is contractual.
code
pseudocode · 10 linesfunction bindAny(target, values)
binder = generatedBinders.lookup(typeOf(target)) // registry filled during the build
if binder is present
return binder(target, values)
recordFallback(typeOf(target)) // the fallback is observable
if strictMode
fail("no emitted binder for " + nameOf(typeOf(target)))
return bindByInspection(target, values)go deeper
Know that there is a choice here at all, and that it turns on when binding is decided rather than on which approach sounds more modern.
Be able to state the inputs: measured startup cost, whether all bound declarations exist while the build runs, and what the build has to host.
Argue a concrete recommendation for a concrete tool, including how you would verify the premise and what evidence would make you change it later.
Own the standard: who pays the build cost against who gets the saving, why the hybrid's fallback must be observable, and how the decision is recorded so it is not re-argued every year.
## Make the decision out of facts, not taste Four inputs decide it, and each is measurable before anyone argues: 1. **Is binding actually in the startup budget?** Measure the startup window and attribute time to it. Many tools discover binding is a rounding error, which ends the discussion. 2. **Does every bound declaration exist while the build runs?** If extension types arrive later, generation cannot cover them and something must inspect — or the extension's own build must emit and register a binder. 3. **Must the artifact survive a whole-program build or a shrinker?** If it must, binding by name needs a maintained list of names to keep, and that list is unenforced by anything. 4. **Who pays the build cost?** A generator you host is one build step; a generator every consuming team hosts is N build steps chosen by someone else. A fifth, softer input: **what should a failure look like?** Generation can fail a build and point at a declaration. Inspection fails in a user's terminal on the path that binds. Teams shipping tools to outside users usually want the first. ## What the hybrid actually is The hybrid is not a compromise on the mechanism; it is a lookup with a fallback. A registry built during the build maps a type to its emitted binder; when a type arrives with no entry, the engine inspects it. Extension types keep working, known types pay nothing at startup, and no one has to choose per tool. ## What the hybrid costs The costs are specific, and a lead is expected to name them rather than to admire the flexibility: - **Two paths, one behaviour.** Emitted and inspected binding must agree on every edge — an absent key, a blank value, a key naming nothing, a member that cannot be converted. Any divergence is a bug that appears only for types on one side. - **The engine can never be deleted.** Because the fallback exists, the inspection engine and the type descriptions it reads are reachable forever. The artifact-size argument for generating is largely surrendered. - **Silent absorption.** A type that quietly stops being generated — a declaration moved, a generator misconfigured in one build — still binds correctly. Nothing fails; the tool simply gets slower, and only a measurement notices. - **Two things to explain.** Every contributor now has to know which path their type takes and how to find out. ## Making the fallback loud The fix for silent absorption is not cleverness, it is visibility: - A strict mode that refuses to fall back, used wherever the startup budget is contractual. - A record of every fallback, so a type that dropped out of generation shows up as an event rather than as a slightly slower tool. - A startup budget asserted in a test, so a regression fails a pipeline instead of reaching users. A fallback nobody can observe is indistinguishable from not having generated at all, which is why a hybrid with no strict mode tends to decay into pure inspection over a few years. ## Setting it for other teams The decision is only half technical; the rest is who bears it. | Consideration | Points to generating | Points to inspecting | |---|---|---| | Startup budget | hard, and binding measures inside it | generous, or binding is negligible | | Where declarations come from | all in the build's input | some arrive after the build | | Artifact handling | shrunk, or compiled whole ahead of time | shipped as-is | | Build ownership | you own the builds that pay | many teams pay for your saving | | Desired failure point | the build | acceptable at run time | A workable standard looks like: generation is the default for tools with a real budget; the fallback exists and is observable; strict mode is required for the handful of tools where the budget is a promise; and one team owns the generator, its incrementality and its upgrades, because a generator maintained by nobody is a build step every team resents. Write down which case each tool is in, so the next person inherits a decision rather than an argument. ## How it is asked This is a judgment question with no single right answer, so what is being assessed is the shape of the argument: do you measure before choosing, do you notice that the build cost falls on people who do not get the benefit, and can you name what the hybrid gives up? Candidates who answer "generate everything, it is faster" have skipped both the extension types and the bill. Candidates who answer "always hybrid" without mentioning the undeletable engine and the silent fallback have chosen the default without pricing it.
- Why does a hybrid surrender most of the artifact-size argument for generating?Because the fallback keeps the inspection engine reachable, and with it the type descriptions the engine reads. The analysis cannot delete either, so you carry the engine and the emitted binders at once. You keep the startup benefit for generated types; you give up the deletion that made the size case attractive.
- What would make you reverse a decision to generate, a year after making it?Evidence that the premise moved: binding stopped being measurable in the startup window, extension types became a normal case rather than an exception, or the generator's build cost turned into the dominant complaint of teams who get no startup benefit from it. Any of those makes the earlier trade a bad deal now.
- How do you stop a hybrid decaying into pure inspection?Make falling back visible and sometimes fatal: record each fallback, assert the startup budget in a pipeline test, and require strict mode for tools whose budget is a commitment. Without those, a type that drops out of generation still works, so nothing ever surfaces the regression.
saying these in an interview costs you the question
- Chooses generation without measuring what binding costs at startup
- Ignores that a generator lands on every consuming team's build
- Calls the hybrid free, missing the engine it keeps reachable forever
- Assumes a fallback nobody records will be noticed when it fires
- Sets one strategy for all tools regardless of startup budget or extensions