Adapter or Translation Shim¶
Translation tool — instantiates Asymmetric Interface Tolerance Calibration
Inserts a translating layer between two parties so a producer's legacy or foreign variants are accepted and re-emitted as the receiver's current canonical form.
An Adapter or Translation Shim is a component you insert between a producer and a receiver that speak different dialects: it accepts the producer's legacy or foreign form and re-emits it as the receiver's single current canonical form. Its defining move is that the asymmetry lives in a separate, dedicated layer rather than in the receiver — tolerance for old variants is concentrated in the shim, so the real interface behind it stays strict and single-form. Where a Lenient Parser with Canonicalizer makes the receiver's own front door tolerant of variants of its own contract, the adapter bridges two distinct contracts (an old version and a new one, or a foreign system and yours) and is usually meant to be transitional — a bridge you can later remove once everyone has crossed.
Example¶
A hospital is wiring an old lab analyzer into a modern patient record. The lab still emits HL7 v2 pipe-delimited messages; the record expects FHIR resources over JSON. Rather than teach the record to read HL7 v2 — which would drag v2's quirks permanently into the modern system — the team drops a translation shim at the boundary. It parses each incoming v2 message, maps segments to FHIR fields, and emits a strict FHIR resource. The lab keeps sending exactly what it always sent; the record only ever sees clean FHIR. The shim carries an identity — it bridges this lab, HL7 v2.3 → FHIR R4 — and is scheduled to retire once the lab's own upgrade lands. Setup to outcome: two systems that could not talk now interoperate, with all the messy compatibility logic quarantined in one owned place instead of smeared across the receiver.
How it works¶
- It sits between the parties as its own deployable unit — a gateway, sidecar, or client SDK — not woven into the receiver's core.
- It holds an explicit mapping from each recognized source variant to the one canonical target; the mapping, not a heuristic, is what it applies.
- It is directional by design: liberal on the source side (accepts old and foreign forms), strict on the emit side (one canonical form out).
- It carries an identity — which two contracts it bridges — so it can be reasoned about, tested, and retired as a single unit.
Tuning parameters¶
- Translation direction — one-way (accept old, emit canonical) or bidirectional (also down-convert canonical back to the old form for legacy readers). Bidirectional widens reach but doubles the mapping surface to keep correct.
- Mapping fidelity — how much of the source form's nuance to preserve versus drop to fit the target. Lossy mappings are simpler but can silently discard meaning the receiver later needs.
- Placement — inline at the receiver, a standalone gateway, or a producer-side SDK. Closer to the producer covers more of them at once but is harder to update centrally.
- Sunset coupling — open-ended, or bound to a retirement date. Binding forces migration but risks stranding laggards; open-ended invites permanence.
- Emit strictness — whether the canonical output is validated on the way out or trusted. Validating on emit keeps a buggy mapping from quietly corrupting the strict side.
When it helps, and when it misleads¶
Its strength is that it lets incompatible parties interoperate now and buys time to migrate, while concentrating all the compatibility mess in one owned, testable place instead of smearing it across the receiver. Its central failure is that the "temporary" shim becomes permanent load-bearing infrastructure — because everything works, no one migrates, and the shim silently hardens into part of the contract, the very drift the archetype warns against.[1] Lossy mappings are a quieter failure: a field dropped in translation is a bug no one sees until it is needed. The discipline that guards against this is to give every shim an owner and a sunset condition, instrument who still routes through it, and treat a shim that outlives its migration as debt to pay down, not a feature.
How it implements the components¶
The adapter fills the mediation-and-emit side of the archetype's machinery — the parts a between-the-parties translator can own:
interface_role_map— inserting the shim is assigning the mediating "translator" role between a legacy producer and the strict receiver; it makes that role concrete rather than implicit.compatibility_context_record— it encodes exactly which source version and format it bridges to which target, giving the ecosystem a named, reasoned-about compatibility fact.outbound_conformance_policy— on its emit side it produces a single strict canonical form, so everything downstream sees one conformant contract.
It does not set the receiver's own acceptance envelope, draw the repair boundary, or spend an ambiguity budget — that is the Lenient Parser with Canonicalizer; nor does it plan its own retirement, which belongs to the Deprecation Warning and Tightening Schedule.
Related¶
- Instantiates: Asymmetric Interface Tolerance Calibration — the shim is the transitional bridge that lets an asymmetric-tolerance regime exist without making the core interface tolerant.
- Consumes: Version Negotiation or Capability Probe — where present, it tells the shim which source variant it is translating.
- Sibling mechanisms: Lenient Parser with Canonicalizer · Deprecation Warning and Tightening Schedule · Tolerant Reader / Strict Writer Policy · Unknown-Field Handling Rule · Compatibility Matrix · Version Negotiation or Capability Probe
Notes¶
The adapter is the one mechanism here that keeps the core interface strict while still tolerating variety — the tolerance lives outside the contract, in a layer you can delete. That is also why it is the easiest to abuse: a deletable layer that is never deleted stops being an adapter and becomes a second, undocumented contract.
References¶
[1] A dedicated translation layer that keeps a foreign or legacy model from leaking into your own is the Anti-Corruption Layer from domain-driven design (Eric Evans, 2003). Its whole value is being a boundary you own; its whole risk is forgetting it was meant to be temporary. ↩