skip to content

Your shared wiring container matches manifest entries to constructors by argument shape and teams hit ambiguous matches — what standard do you set?

level: principalimportance: should knowfreq 34%

answer

  1. ambiguity is a contract problem
  2. exactness against ergonomics
  3. name the signature or designate one
  4. validate the whole manifest first
  5. list the candidates you rejected

basics

~20 s

Trade ergonomics for exactness deliberately: make entries address a member by full signature or by parameter name, designate one wireable constructor where you own the type, validate every entry before anything is built, and require the error to list the candidates it rejected.

solid answer

~40 s

Shape matching is pleasant to write and impossible to reason about, because the resolution is redone on every load and no build step ever sees it. The policies worth choosing between are: keep matching but add a whole-manifest validation pass that fails fast on ambiguity; designate a single wireable constructor per type; require entries to name the full parameter-type list; or bind by parameter name rather than position. Signature addressing is the most exact and the most verbose, and it is the only one that works for types you do not own. The lead's real job is the transition: a validator in the build, error messages that list rejected candidates, a deprecation window, and a number that shows how many entries still resolve by scan.

go deeper

for a junior

Know that a container may have several constructors to choose from and that the choice can be genuinely ambiguous, which is why some platforms make you write more in the entry than feels necessary.

for a middle

Be able to state the alternatives concretely: fail fast on ambiguity, designate one constructor, name the full parameter-type list, or bind by parameter name — and what each one costs the person writing an entry.

for a senior

Show how you would move an existing estate: accept both forms, warn on the old, validate in the build, and make the failure message list the rejected candidates so teams can act on it alone.

for a principal

Own the trade across teams and across types you do not control, set the rule in writing with the failure it prevents, and carry a measurement that says when the old form is actually gone.

## What the ambiguity actually costs Ambiguous matching is not primarily an outage risk; it is a **reasoning** risk. Nobody can look at a manifest entry and say which constructor it will call without knowing the current declared members of that type. That has three costs that compound across teams: - **No locality.** The entry and the decision live in different repositories, and the decision changes when the other repository ships. - **No build signal.** A change that re-points an entry is green everywhere, because nothing in the build reads the manifest. - **No shared vocabulary for the failure.** Each team hits it once, calls it something different, and works around it locally. That is why the decision is a platform standard rather than a bug fix: the mechanism is working exactly as designed, and what is missing is a contract. ## Four policies and what each buys | Policy | Buys | Costs | |---|---|---| | Validate the whole manifest, fail fast on ambiguity | cheap, keeps existing ergonomics | resolution still happens at load; a new overload can still shift a match | | Designate one wireable constructor per type | ambiguity becomes impossible | needs a marker on types you own, and is unavailable for types you do not | | Entries name the full parameter-type list | exact selection, loud failure on change | verbose; every signature change breaks entries — which is the point and the complaint | | Bind by parameter name, not position | survives reordering and same-typed neighbours | depends on the runtime recording names, which not all do | These combine. The common landing place is **name-based binding for readability plus signature addressing for identity**, with the designated-constructor rule applied only to types the platform itself owns. ## Choosing 1. **How many teams write manifests?** One team can live with scan-and-fail-fast. Twenty cannot, because the failure lands on whoever deployed last rather than whoever changed a signature. 2. **Do you own the wireable types?** If a substantial share are external, the designated-constructor rule is unavailable for them, and signature or name addressing is the only policy that covers everything. 3. **How often do signatures change?** Frequent change argues for name binding, which survives reordering; rare change makes full signatures cheap to maintain. 4. **What is the blast radius of a wrong pick?** If a mis-wired collaborator can silently produce wrong results rather than an immediate failure, buy exactness and pay the verbosity. ## What you owe the teams - **A written rule, with the failure it prevents named.** A standard whose motivation is not written down gets re-litigated by the next person who finds it verbose. - **A validator that runs in the build**, over every manifest, so the loud failure arrives before deployment rather than at startup. - **Error messages that explain the choice.** When selection fails, list every candidate considered and say why each was rejected — wrong count, a value that would not bind, equally applicable. A matcher that cannot explain itself cannot be adopted. - **A migration path and a deprecation window.** Accept both forms, warn on the old one, and set a date. - **A number to watch.** Count the entries still resolving by scan. Without it the migration is finished when people stop talking about it, which is not the same thing. ## The trap in this decision The tempting move is to make the matcher smarter — more conversions, a preference for the most specific candidate, a fallback that tries the next candidate when construction fails. Every one of those makes the outcome *less* predictable, because the rule that decides now lives in the container rather than in the entry. A fallback is the worst of them: it can build a differently-shaped object in response to a transient failure, and it will do so at three in the morning. Prefer a standard that makes the entry say what it means over a matcher that guesses better.

  • Why is a smarter matcher — more conversions, a better tie-break — usually the wrong answer here?
    Because it moves the deciding rule further from the entry. The team writing the manifest still cannot predict the outcome, and now the rule can change when the container ships rather than when the type does. Exactness at the entry is auditable; cleverness in the matcher is not.
  • You cannot designate a constructor on a type another team owns. What covers those?
    Addressing by full parameter-type list, or by parameter name where the runtime records names. Both are properties of the entry rather than of the type, so they work for anything, including types you will never be able to annotate or change.
  • How do you know the migration actually finished?
    Count the entries still resolving by scan and watch the number go to zero, with the validator failing the build on new ones. Without a count, the deprecation ends when complaints stop, which measures patience rather than adoption.

saying these in an interview costs you the question

  • Treats ambiguous matching as a bug to patch rather than a contract to set.
  • Adds a fallback that tries the next candidate when construction fails.
  • Assumes every wireable type can be marked, including ones another team owns.
  • Ships the standard with no validator, so the failure still arrives at startup.
  • Declares the migration done without counting entries still resolving by scan.