Other teams want to register specialized bodies for your shared archiver writer - what policy do you set?
answer
- who may add a narrower body
- behaviour becomes scope-dependent
- cost may change, meaning may not
- conformance suite as admission price
- two teams' claims can overlap
basics
~20 sDecide first whether specialization is part of the published contract or an internal optimisation. If outside teams may add bodies, publish the observable behaviour every body must reproduce, restrict overrides to cost and layout, and make a conformance suite the price of admission.
solid answer
~50 sOpening specialization changes what your API is. Because selection happens per call site, the behaviour of one call now depends on which bodies happen to be visible there, so a third team's override can change what a fourth team's code writes. Three positions are available. Closed: overrides stay internal, and outside teams get an extension point that selects on a value they pass, which is visible and testable. Open but constrained: publish the observable contract, state that an override may change representation and cost but never output, errors or effects, require every registered body to pass a shared conformance suite, and require overrides to be declared in one place so overlaps are caught. Open and unconstrained is how one team's performance patch becomes another team's unreadable archive. Also decide up front who resolves an overlap between two teams' family-shaped claims, because that failure lands in a consumer's build.
go deeper
Recall the risk rather than the policy: letting other teams attach their own implementations to a shared operation means that operation can behave differently depending on whose code is in the build.
Explain the mechanics behind the policy: selection is resolved per call site from static knowledge, so an override added by one team changes what another team's call produces without either of them touching the other's code.
Show the operational guardrails you would insist on - a written observable contract, invariant steps the override cannot replace, and a conformance suite instantiated for every registered body before it is allowed to exist.
The call you own is whether the implementation's identity is part of the contract. Weigh a reversible closed extension point against an open mechanism you can never withdraw, and decide in advance who owns overlap resolution and the deprecation path.
## What you are actually deciding The request sounds local - "let us write a faster body for our record type" - but it changes a global property. Selection of a specialized body is resolved **per call site**, from the static knowledge available there. Granting it means: - the behaviour of your operation is no longer a property of your library, but of **which bodies are visible where each call is compiled**; - a team that has never heard of the override can have their output changed by it; - the set of claims grows without your review, and two independent family-shaped claims can overlap, failing in a **third** team's build. So the decision is not "should we allow an optimisation" but "is the identity of the implementation part of our published contract". ## The three positions | Policy | What teams get | What you keep | Where it hurts | |---|---|---|---| | **Closed** - overrides are internal | an extension point that selects on a value they pass in | one implementation set, fully testable by you | you become the bottleneck for every genuine performance need | | **Open but constrained** | may add a body for their own type, under a published contract and a conformance suite | the observable behaviour, enforced mechanically | you must build and maintain the suite, and police overlaps | | **Open, unconstrained** | anything | nothing | drift, scope-dependent behaviour, ambiguity failures in consumers' builds | Most shared libraries should start closed and move to constrained only when the closed extension point is measurably inadequate - because the closed option is reversible and the open one is not: once outside bodies exist, withdrawing the mechanism is a breaking change to every one of them. ## If you open it, the rules that make it survivable 1. **Publish the observable contract in words.** What the output is, in what order, what happens on empty input, what is thrown or returned on failure. Without this there is nothing for a registered body to conform to. 2. **Bound what an override may change**: representation, layout and cost - never output, errors, or observable effects. If a team's requirement is a *different* archive, that is a different operation and gets its own name. 3. **Ship the conformance suite as the admission price.** Parameterise it over the type argument, so registering a body means instantiating the suite for that argument and proving it agrees with a general-body reference. 4. **Make the invariant steps unreachable.** Keep framing and checksums in a step the override cannot replace, so the contract is partly enforced by construction rather than entirely by tests. 5. **Require every override to be declared in one published place.** Scattered claims are how an overlap survives to a consumer's build; listed together, an overlap is visible when it is written. 6. **Own the overlap resolution.** Say in advance who writes the body claiming the intersection when two teams' family claims collide, and that neither team may simply narrow the other's claim. ## The question to ask each requester Before granting anything, ask what the override is *for*. Two answers are common and they point opposite ways: - **"Ours is much cheaper for our record shape."** This is the legitimate case. Constrain it and take the conformance suite. - **"Ours needs to write the header differently."** This is a second operation wearing your name. Give it a name of its own; a specialization would make your archive's format depend on which team's code happened to be linked into the call. ## How to keep the door closeable If you do open it, keep two levers. First, a registry - even a simple published list of which team owns which claim - so you know the blast radius of a contract change. Second, a stated deprecation path: what happens to registered bodies if you later need to change the general body's behaviour. A shared operation whose implementations you cannot enumerate is a contract you can no longer change, and that, rather than any individual override, is the cost a lead is being asked to sign for.
- Why is closing this later harder than keeping it closed now?Because every registered body becomes a caller of the mechanism. Withdrawing it breaks all of them at once, and you usually cannot enumerate them unless you kept a registry. Closed is reversible - you can open it when a real need is measured - so the asymmetry argues for starting closed and demanding evidence before granting.
- What extension point do you offer instead if you keep specialization closed?One that selects on something the caller passes rather than on the type: a writer strategy handed to the operation, or a registered handler chosen from a value. It is visible in the call, testable in isolation, and its behaviour does not depend on what happened to be in scope where the call was compiled.
- Who should resolve an overlap between two teams' family-shaped claims?You should, and you should say so before it happens. The failure appears in a consumer's build, neither claimant sees it, and each team's obvious fix is to narrow the other. Owning the intersection body - and the rule that claims must be registered in one place - keeps that from becoming a standoff between two teams.
saying these in an interview costs you the question
- Lets any team add a body with no contract stated
- Assumes overrides compose safely because the call shapes match
- Says an override may change results as long as it is faster
- Treats an overlap between two teams' claims as their problem
- Opens the mechanism without a registry of who owns what
- Publishes it as an extension point with no conformance suite