An in-house abstraction exposes only the features common to the platforms beneath it - what leaks through anyway?
answer
- names hide easily, behaviour does not
- consumers get the intersection, not the union
- timing, quotas and errors leak through
- consistency and retry are not signatures
- declare the weaker guarantee explicitly
basics
~20 sBehaviour leaks even when the surface does not: latency and throughput, when a write becomes visible, quota and throttling shape, which errors are retryable, what a partial failure looks like, and how a caller's identity is established.
solid answer
~40 sAn abstraction hides **names** easily and **behaviour** barely at all. What it hides deliberately is the richer feature: a capability one platform has and the other does not is left out, so services receive the intersection and lose things they would otherwise have used. What leaks through regardless is everything that is not a method signature - how long a call takes, whether the next read sees the write just made, what happens when a quota is reached, which errors are worth retrying and with what backoff, what a partially applied operation looks like, and how a workload proves its identity. Code written against the abstraction silently acquires the timing and error assumptions of the one platform it has ever run on.
code
pseudocode · 21 linesinterface ObjectStoreSeam:
put(key, bytes) -> writeReceipt
get(key) -> bytes or NotFound
# the contract the seam promises: the weaker of the platforms behind it
contract:
maxObjectBytes = smaller of the two platform ceilings
readAfterWrite = notGuaranteed
retryableErrors = [Throttled, Unavailable]
retryPolicy = backoffWithJitter, maxAttempts = 4
callDeadline = 5 seconds
# consumers are tested against the contract, not against today's platform
test "a read may miss its own write":
put(key, bytes)
assert get(key) is allowed to return NotFound
test "a throttled call is retried, a NotFound is not":
for each attempt in 1..4:
if response is Throttled: wait backoffWithJitter(attempt); retry
if response is NotFound: stop; report NotFoundgo deeper
Recall that an interface can rename things but cannot change how fast or how reliably they happen. Two systems with the same method names can still behave differently under load.
Explain the intersection effect: an abstraction over several platforms can only offer what all of them do, so richer capabilities are dropped and their users go elsewhere for them.
Name the specific leaks - latency, write visibility, quota shape, retryability, partial failure - and show how consumers absorb them from the single platform they have always run on.
Argue for an explicit, deliberately pessimistic contract as the seam's real deliverable, and for recording which capabilities were left out and who owns that decision.
## What the abstraction hides on purpose An in-house seam can only offer what everything behind it can do. The moment a second implementation is real, the interface collapses towards the **intersection** of the platforms: the capability that exists on one and not the other is either dropped, or emulated badly, or exposed with a note saying it works in only one place - which is the same as not being in the interface at all. The cost is not theoretical. The dropped capability is frequently the thing that made the platform attractive: a richer query, a stronger ordering guarantee, a cheaper storage tier, an integration that removes code. Services that need it do one of three things - press for an exception, work around it clumsily above the seam, or call the platform directly. Planning for which of those is allowed is part of designing the seam; pretending none will happen is not. ## What leaks through anyway Signatures are the easy part. These are not signatures, and no interface hides them: - **Latency and throughput profile.** How fast a call is, and how it degrades as concurrency rises. - **Visibility and ordering.** Whether a read immediately after a write sees it, and whether two writes land in the order they were issued. - **Quota and throttle shape.** Where the ceiling is, whether it is per caller or per object, and whether it is a soft quota that can be raised on request or a hard limit that cannot. - **Error taxonomy and retry semantics.** Which failures are transient, which are permanent, which are safe to retry, and what backoff the platform actually expects. - **Partial failure.** What a call that half-applied leaves behind, and whether repeating it is safe. - **Identity and credential lifetime.** How a workload proves what it is, and how often that proof has to be refreshed. - **Durability and replication behaviour.** How many copies a write has reached before the call returns. | Kind of difference | Can an interface hide it? | |---|---| | Service and object names | yes, trivially | | Payload field names and shapes | yes, by mapping | | Credential plumbing | mostly, behind a client | | Optional capability one platform lacks | only by removing it for everyone | | Latency, throughput and their behaviour under load | no | | Write visibility and ordering | no | | Quota values and throttling behaviour | no | | Retryability and partial-failure semantics | no | ## Why the leaks matter precisely when you need the seam Consumers do not read the interface documentation for timing; they observe the system and write code that works. A retry loop tuned to one platform's throttling, a job that assumes a read sees its own write, a batch sized to one platform's payload ceiling - all of these compile against the abstraction and all of them are assumptions about the platform underneath it. On the day a second implementation appears, the surface matches and the system misbehaves, which is the worst shape of failure because every structural check passes. ## Make the contract explicit, and weaker The fix is to stop pretending the seam has no semantics and to state them deliberately, at or below the weaker of the platforms: 1. **Declare the guarantees** the seam promises - the maximum payload, the write-visibility promise, the call deadline, the retryable error classes and the retry policy - as part of the interface, not as folklore. 2. **Promise the weaker option** wherever the platforms differ. If one gives read-after-write and the other does not, the seam promises that it does not. 3. **Test consumers against the stated contract** rather than against whatever the current platform happens to do: inject the declared errors, enforce the declared deadline, and occasionally return stale reads. 4. **Record the deliberate omissions** so the capability that was left out is a known decision with a named owner, rather than a request that arrives as a surprise. A seam with a written, deliberately pessimistic contract is portable in a way that a seam with matching method names is not. The matching names were never the hard part. It is worth being blunt about what that buys: the contract does not make the platforms behave alike, and it does not recover the capability the intersection removed. What it does is make the assumptions **visible and testable**, so that the day a second implementation appears, the differences show up as contract violations in a test rather than as a slow, unexplained degradation in production.
- How do you stop a hidden capability becoming a queue of exception requests?Decide up front which capabilities are out of scope and publish that decision, then give teams a documented way to call the platform directly where they genuinely need one, with the bypass recorded. An abstraction that neither exposes the capability nor permits going around it turns every real need into a negotiation.
- What is the practical way to stop behavioural assumptions leaking in?Write the seam's contract down and make it weaker than either platform: the payload ceiling, the call deadline, the retryable errors and retry policy, and the write-visibility promise. Then test consumers against those stated limits - inject the errors, enforce the deadline, return a stale read - instead of against whatever the current platform does.
saying these in an interview costs you the question
- Believes a matching interface implies matching latency, consistency and error behaviour
- Assumes consumers will not come to depend on the timing they observe
- Thinks hiding a capability removes the need for it rather than deferring the request
- Treats retry and backoff policy as an implementation detail below the seam
- Expects identity and credential handling to hide as cleanly as method names do