A customer portal receives “closed” from a legacy repair system and displays “ready for collection”. The technician has finished an assigned task, but final inspection is still pending. The field was transmitted correctly. Its meaning was not.
An Anti-Corruption Layer, or ACL, protects an internal model from importing those assumptions. “Corruption” here means distortion of the model, not malware or misconduct. The layer understands an external contract and expresses relevant information in the receiving application's terms. It cannot manufacture a fact the provider never supplies.
Renaming the field is not enough
The portal may need distinct states for work completed, inspection passed and collection authorised. If the external status establishes only the first, it cannot prove the third. The product needs another source, a clarification from the provider or an honest intermediate state for customers.
The Azure Architecture Center pattern describes protecting meaning rather than merely changing formats. Converting XML to JSON can be ordinary technical adaptation. An ACL becomes relevant when the systems genuinely use different models of the work.
The older system need not be badly designed. It may serve technicians who only need the status of their own task. A customer portal answers a different question and needs a contract appropriate to that question.
Write down what each state actually establishes
For every external state the product uses, specify the evidence it provides. What is confirmed? What is still unknown? Which action can follow? Completing a repair task may permit an inspection request without allowing a collection notification.
Include missing and unknown values. An unfamiliar provider status should not silently become success because the translator cannot classify it. Equally, missing information should not become a rejection that tells a customer their repair was cancelled when an update is merely unavailable.
Identifiers also need a contract. A technician's task number may differ from the customer case number, and one case can contain several tasks. Preserve mappings with the source and scope of uniqueness. Matching short numbers from different organisations must not merge their records.
Measurement units, time zones and mandatory fields matter too. If a due date has no time or time zone, a translator should not invent precision. Deciding what to promise on the basis of incomplete information remains a product responsibility.
Do not hide uncertainty inside a convenient error
The portal requests a change to the collection location and times out. That does not establish rejection: the legacy system may have saved the change before the response was lost. A new command could repeat an effect; a definitive failure message could prompt the user into an incompatible follow-up action.
The internal application benefits from distinguishing confirmed rejection, temporary unavailability and an unknown outcome. The last needs an operation lookup using a stable identifier or another agreed reconciliation path. The Amazon Builders' Library explains why retry safety depends on operation semantics, not just a pause before trying again.
The translator can normalise responses and preserve identifier mappings. It should not quietly acquire responsibility for completing an entire repair process after several partially successful steps. A long-running workflow deserves explicit states and an accountable owner outside the translation detail.
Where translation becomes a second application
Mapping the provider's model belongs at the boundary. Discount, warranty and compensation decisions belong to the relevant product domain. If every awkward business decision is moved into the adapter, it becomes another business system without an acknowledged owner.
An ACL can be an internal module. A separate service may be appropriate for independent operation, scaling or reuse, but introduces another network hop and failure boundary. A few straightforward mappings do not automatically justify a new deployed component.
Even a module needs diagnostics: which response could not be interpreted, which mapping version ran and which customer operation was affected? Do not copy repair documents and personal details into logs indiscriminately. Identifiers and limited context often suffice to locate the source record under proper access controls.
Translation does not grant permission to read the data. If an integration can reach several organisations' cases, the portal must still restrict results to the authorised customer. An identifier supplied in a request is not sufficient authority to retrieve a document. A convenient internal contract must preserve access boundaries rather than hide them with the provider's quirks.
Exercise awkward responses before migration
Build authorised test examples: only one task completed, no inspection, an identifier reused by another source, an unknown state. Include a lost response after a successful write. For each case, agree on what the customer sees and what work continues.
Isolated mapping tests are useful but do not prove the provider still returns those examples. Contract tests can connect consumer expectations to provider behaviour when both sides participate. An independent external provider may instead require suitable integration checks and monitoring of changed responses.
When replacing the system, compare the old and new translations against equivalent scenarios. Do not send mutating commands to two providers merely to compare results; that can perform the action twice. Even read-only comparisons need appropriate permissions and data-handling constraints.
The migration may retire the layer if the semantic difference disappears, or retain it as a permanent boundary with an external service. For repair tracking, success means distinguishing a finished task from permission to release equipment, without scattering a new provider's numeric codes across every screen. Effortless replacement of any provider is not part of the promise.