DEVBLUEPRINTS

Blog

  • Sobre o blog
  • Arquivo
  • Newsletter
  • RSS

Legal

  • Termos e Privacidade
  • Contato
  • Sobre mim

Inscreva-se na Newsletter

Autorizo o envio de comunicações por e-mail ou qualquer outro meio e concordo com os Termos e Política de Privacidade

 

Blog
  • Sobre o blog
  • Arquivo
  • Newsletter
  • RSS
Legal
  • Termos e Privacidade
  • Contato
  • Sobre mim
© 2026 Todos os direitos reservados — Desenhado e construido comFooter Heartpor Ednaldo Luiz
Blog/System Design

Anti-Corruption Layer: isole sua aplicação de modelos externos

Contratos, status e erros de terceiros se espalham pelo código aos poucos. Veja como uma Anti-Corruption Layer isola esse acoplamento e quando ela compensa.

software architecture
integration patterns
best practices
ddd
Anti-Corruption Layer: isole sua aplicação de modelos externos
Ednaldo Luiz
Ednaldo Luiz
Nível: Intermediário
Nível:
Publicado: 02 de agosto de 2026
Última atualização: 02 de agosto de 2026
16 min de leitura
visualização: - visualização

Introdução

Sabe aquela integração que começa com uma chamada HTTP, um DTO de resposta e uma verificação de status?

A aplicação precisa cobrar uma assinatura. O gateway retorna SETTLED, o código ativa o plano e tudo parece resolvido.

Só que a integração cresce. Entram Pix, boleto, cobrança recorrente, cancelamento, estorno e webhooks. Aos poucos, respostas do fornecedor começam a aparecer nos casos de uso, exceções específicas são tratadas em vários pontos e status como AWAITING_PAYMENT, OVERDUE e REFUNDED, que nem fazem parte da linguagem da aplicação, passam a orientar decisões importantes do domínio.

O problema não é depender de um sistema externo. É natural, e muitas vezes necessário, usar APIs de terceiros.

O problema começa quando a aplicação deixa de apenas conversar com esse sistema e passa a pensar como ele.

Uma mudança no contrato externo agora exige alterações em diferentes partes do código. Trocar de fornecedor deixa de ser apenas substituir uma integração. É preciso encontrar todos os pontos que passaram a conhecer seus nomes, formatos, códigos e regras.

A Anti-Corruption Layer cria uma fronteira entre esses modelos. Em vez de permitir que contratos externos atravessem a aplicação, ela traduz status, dados, erros e operações para conceitos que façam sentido internamente e estejam alinhados à linguagem que a aplicação já usa.

O padrão foi descrito originalmente no contexto do Domain-Driven Design, mas o problema que ele resolve aparece em qualquer sistema que precise se integrar com gateways, APIs de terceiros, sistemas legados, SDKs ou serviços de outras equipes.

Neste artigo, vamos entender como essa fronteira funciona, por que ela é mais do que um simples mapper e quando seu custo realmente compensa.

TL;DR

Uma Anti-Corruption Layer pertence ao contexto consumidor que deseja preservar seu próprio modelo.

Ela traduz contratos, status, erros e operações externas para conceitos internos, evitando que detalhes de fornecedores, sistemas legados ou outros serviços se espalhem pela aplicação.

Use uma ACL quando existir uma diferença semântica relevante. Quando os dois lados já falam praticamente a mesma linguagem, um client ou adapter simples pode ser suficiente.

A ACL concentra o acoplamento, mas não o elimina. Em troca dessa proteção, exige traduções, testes e manutenção da fronteira.


O que é uma Anti-Corruption Layer

Uma Anti-Corruption Layer, ou ACL, é uma fronteira de tradução entre a aplicação e um modelo externo.

Ela permite que dois sistemas se comuniquem sem obrigar um deles a adotar os contratos, nomes e regras do outro.

ACL também pode significar Access Control List, a lista de permissões usada em segurança e redes. Aqui, porém, significa sempre Anti-Corruption Layer.

Diagrama: um sistema externo, com modelo e linguagem próprios, comunica-se com o domínio da aplicação através de uma ACL, que traduz, adapta e protege.

Um gateway pode retornar SETTLED, enquanto a aplicação trabalha com PAID. A ACL conhece os dois significados e faz a tradução entre eles.

O modelo externo não precisa estar errado ou ser mal projetado. Ele pode ser perfeitamente adequado ao contexto em que foi criado e, ainda assim, não representar o problema da forma que faz sentido dentro da nossa aplicação.

A ACL não tenta criar um modelo universal. Ela permite que cada lado continue falando sua própria linguagem, enquanto a fronteira traduz o necessário para que ambos consigam se comunicar.

O que significa “corrupção”

Nesse contexto, corrupção não tem relação com segurança, fraude ou dados danificados.

Ela acontece quando um conceito que faz sentido do outro lado passa a determinar como o nosso modelo deve ser estruturado.

Na prática, isso começa pequeno:

Repare no detalhe: SETTLED é um status do fornecedor, não um conceito da nossa aplicação. Ele pode fazer sentido para o gateway, mas não necessariamente para o domínio de assinaturas.

if ("SETTLED".equals(payment.status())) {
	subscription.activate();
}
if ("SETTLED".equals(payment.status())) {
	subscription.activate();
}

Agora a regra de ativação da assinatura depende diretamente do vocabulário do fornecedor.

Com a tradução:

if (payment.isPaid()) {
	subscription.activate();
}
if (payment.isPaid()) {
	subscription.activate();
}

Nesse ponto é justo desconfiar: isPaid() não apareceu do nada, e isso não é apenas esconder a mesma comparação dentro de outro método.

A diferença está em onde permanece o conhecimento de que SETTLED significa um pagamento concluído para este contexto.

O vocabulário externo fica na tradução feita pela ACL:

private PaymentStatus translateStatus(String externalStatus) {
	return switch (externalStatus) {
			case "SETTLED", "RECEIVED" -> PaymentStatus.PAID;
			case "AWAITING_PAYMENT" -> PaymentStatus.PENDING;
			case "OVERDUE" -> PaymentStatus.PAST_DUE;
			case "REFUNDED" -> PaymentStatus.REFUNDED;
			default -> throw new UnsupportedProviderStatusException(
					externalStatus
			);
	};
}
private PaymentStatus translateStatus(String externalStatus) {
	return switch (externalStatus) {
			case "SETTLED", "RECEIVED" -> PaymentStatus.PAID;
			case "AWAITING_PAYMENT" -> PaymentStatus.PENDING;
			case "OVERDUE" -> PaymentStatus.PAST_DUE;
			case "REFUNDED" -> PaymentStatus.REFUNDED;
			default -> throw new UnsupportedProviderStatusException(
					externalStatus
			);
	};
}

Esse switch pertence ao translator da ACL. É nele que o vocabulário do fornecedor é convertido para o modelo interno; o caso de uso não precisa conhecer esses status externos.

O comportamento isPaid() pertence ao modelo interno PaymentResult. Ele consulta o PaymentStatus que já foi convertido pela ACL:

PaymentResult.java
public boolean isPaid() {
	return status == PaymentStatus.PAID;
}
PaymentResult.java
public boolean isPaid() {
	return status == PaymentStatus.PAID;
}

Repare que isPaid() não esconde uma comparação com SETTLED: ele nem sabe que essa string existe.

A ACL interpreta o vocabulário externo. O modelo interno decide o comportamento associado a PAID.

Se outro fornecedor chama o mesmo resultado de SUCCEEDED, ele recebe sua própria tradução. O restante da aplicação continua trabalhando com PaymentStatus.PAID.

Dois fornecedores, dois vocabulários e um conceito interno.

A corrupção não está no modelo externo.

Ela acontece quando um conceito criado para outro contexto passa a determinar a linguagem e as decisões da nossa aplicação.

A ACL pertence ao consumidor

Uma ACL é construída do ponto de vista do contexto que deseja preservar seu modelo.

Em uma integração com um gateway:

Contexto consumidor(downstream)Sistema fornecedor(upstream)Aplicação de assinaturasGateway de pagamentos
A aplicação de assinaturas consome o contrato oferecido pelo gateway; upstream e downstream descrevem a posição relativa de cada sistema na integração.

O sistema upstream define o contrato oferecido. O downstream consome esse contrato, mas não precisa copiá-lo para dentro de seu próprio modelo.

A ACL pertence ao lado consumidor:

Modelo do gateway
ACL
Modelo de assinaturas
upstream
→
tradução
→
downstream
Modelo do gateway
upstream
→
ACL
tradução
→
Modelo de assinaturas
downstream

Embora possa traduzir informações nos dois sentidos, ela não é uma fronteira neutra. Sua função é proteger o modelo downstream.

A tradução acontece sempre que a fronteira é atravessada:

FluxoACL recebeACL entrega
Aplicação → GatewayPaymentRequest internoRequisição esperada pelo gateway
Gateway → AplicaçãoResposta externaPaymentResult interno
Gateway → AplicaçãoErro do fornecedorFalha compreensível pela aplicação
Gateway → AplicaçãoWebhook externoEvento interno

Depois de cada travessia, o restante da aplicação continua trabalhando apenas com sua própria linguagem.

Imagine que a aplicação precise apenas do identificador e do estado de uma cobrança:

PaymentResult.java
public record PaymentResult(
	PaymentId id,
	PaymentStatus status
) {}
PaymentResult.java
public record PaymentResult(
	PaymentId id,
	PaymentStatus status
) {}

O gateway, porém, pode retornar um contrato muito maior:

ProviderAPaymentResponse.java
public record ProviderAPaymentResponse(
	String id,
	String status,
	String billingType,
	String invoiceUrl,
	String receiptUrl,
	String estimatedCreditDate,
	String providerAccount
) {}
ProviderAPaymentResponse.java
public record ProviderAPaymentResponse(
	String id,
	String status,
	String billingType,
	String invoiceUrl,
	String receiptUrl,
	String estimatedCreditDate,
	String providerAccount
) {}

A aplicação não precisa reproduzir tudo isso.

A ACL seleciona o que é relevante e impede que o modelo interno se transforme em uma cópia da API externa. Por isso, além de traduzir, ela também funciona como um filtro.

Como a ACL protege o modelo

A tradução pode ser técnica ou semântica, e cada uma resolve um problema diferente:

TipoExemploO que muda
TécnicaJSON → XMLFormato da mensagem.
TécnicaREST → SOAPProtocolo ou estilo de comunicação.
TécnicaHTTP → mensageriaForma como a informação é transportada.
SemânticaSETTLED → PAIDSignificado usado dentro da aplicação.
Semânticacustomer → subscriberLinguagem usada para representar o conceito.
Semânticacódigo B → conta bloqueadaInterpretação de um valor externo.

Uma ACL pode realizar as duas.

Ela pode receber XML por SOAP, converter o payload para objetos Java e, depois, interpretar o código A como CustomerStatus.ACTIVE.

Mas a tradução técnica, sozinha, não caracteriza necessariamente uma ACL. Um também pode converter protocolos.

O papel central da ACL é proteger o significado usado pelo modelo interno.

Na prática, essa fronteira pode ser formada por:

  • um contrato definido pela aplicação;
  • um client que conhece o sistema externo;
  • um adapter que conecta os dois lados;
  • translators ou mappers;
  • DTOs específicos do fornecedor;
  • tradução de erros, eventos e referências.

Esses componentes não são obrigatórios nem precisam existir em classes separadas.

Em uma integração pequena, o adapter pode fazer também a tradução. Em uma integração extensa, separar client, adapter e translator pode melhorar a clareza.

A complexidade da estrutura deve acompanhar a complexidade real do problema.

Port, adapter e ACL não são sinônimos. No exemplo abaixo, o PaymentGateway define o contrato interno; o ProviderAPaymentAdapter o implementa contra o fornecedor; e a ACL é a fronteira arquitetural formada por essas peças e pela tradução semântica.

Elemento no exemploPapelRelação com a ACL
PaymentGatewayPortDefine o contrato que a aplicação quer consumir.
ProviderAPaymentAdapterAdapterImplementa o port usando o contrato do fornecedor.
ProviderAPaymentTranslatorTranslator semânticoConverte contratos, status e erros externos em conceitos internos.
Anti-Corruption LayerFronteira arquiteturalReúne essas peças para isolar o contrato externo.

Criar uma interface e um adapter não significa automaticamente criar uma ACL.

Um adapter que devolve ProviderAPaymentResponse para o caso de uso continua permitindo que o contrato externo atravesse a aplicação.

A diferença está na intenção arquitetural e na proteção semântica.

Alguns sinais mostram que a fronteira está vazando:

// Tipo do fornecedor vazando na assinatura
public ProviderAPaymentResponse createSubscription(...) {
	// ...
}

// Exceção externa tratada dentro do caso de uso
catch (ProviderAException exception) {
	// ...
}

// Código externo decidindo uma regra interna
if ("PAYMENT_SETTLED".equals(event.status())) {
	// ...
}
// Tipo do fornecedor vazando na assinatura
public ProviderAPaymentResponse createSubscription(...) {
	// ...
}

// Exceção externa tratada dentro do caso de uso
catch (ProviderAException exception) {
	// ...
}

// Código externo decidindo uma regra interna
if ("PAYMENT_SETTLED".equals(event.status())) {
	// ...
}

Tipos, enums, códigos e exceções do fornecedor não deveriam aparecer em controllers, entidades ou casos de uso internos.

Afinal, eles representam regras e detalhes do provedor externo, não conceitos que a nossa aplicação deveria conhecer.

Isso não elimina o acoplamento. A ACL continua conhecendo o contrato externo.

O ganho está em concentrar esse acoplamento em uma fronteira controlada, em vez de deixá-lo se espalhar.

Assim como na Lei de Deméter, buscamos limitar o conhecimento entre as partes. Aqui, porém, a fronteira está entre modelos e sistemas, não entre objetos.

Uma ACL não remove a dependência externa. Ela impede que essa dependência determine como o restante da aplicação deve pensar.


Casos de uso

ACL não aparece apenas em sistemas legados ou projetos que adotam DDD formalmente.

Ela pode ser útil sempre que dois sistemas precisam colaborar, mas representam o problema de formas diferentes.

Exemplos de Anti-Corruption Layer em gateways, migração de legado e comunicação entre serviços

Gateways e fornecedores

Gateways de pagamento são um cenário comum.

Cada fornecedor pode ter contratos, status, exceções, webhooks e capacidades diferentes. A ACL traduz essas diferenças antes que elas cheguem à aplicação.

Os status abaixo são fictícios e simplificados. Gateways reais possuem ciclos de vida próprios e não devem ser forçados a equivalências que o negócio não reconhece.

Nosso modeloGateway AGateway B
PAIDSETTLED, RECEIVEDSUCCEEDED, COMPLETED
PENDINGAWAITING_PAYMENTPROCESSING
PAST_DUEOVERDUEPAST_DUE
REFUNDEDREFUNDEDREVERSED

Neste contexto de assinaturas, PAID significa que o pagamento atingiu o estado necessário para liberar o acesso.

Um contexto de conciliação financeira poderia preservar diferenças mais detalhadas entre confirmação, captura e liquidação.

Isso mostra um ponto importante: a ACL não traduz o dado de forma universal. Ela traduz de acordo com a pergunta que o contexto consumidor precisa responder.

Um novo fornecedor pode ser adicionado sem alterar o caso de uso enquanto o contrato interno continuar representando corretamente as capacidades exigidas pelo negócio.

A ACL concentra as diferenças, mas não transforma fornecedores semanticamente diferentes em alternativas perfeitamente intercambiáveis.

Se um oferece estorno parcial, autorização e captura separadas ou split de pagamentos, enquanto outro não oferece, talvez o contrato interno precise refletir essas diferenças.

Esse princípio também vale para serviços de e-mail, armazenamento em cloud, transportadoras, provedores de identidade e provedores de IA com seus SDKs.

Migração gradual do legado

Numa modernização, a ACL permite que o sistema novo trabalhe com o próprio modelo enquanto ainda consulta dados e executa operações no legado.

O legado pode representar clientes assim:

{
	"cod_cli": "1029",
	"sit": "A",
	"tp_cli": "02",
	"fl_pend": "S"
}
{
	"cod_cli": "1029",
	"sit": "A",
	"tp_cli": "02",
	"fl_pend": "S"
}

Um pouco difiícil de lidar com strings e códigos opacos né? Por isso o sistema moderno prefere trabalhar com:

Customer.java
public record Customer(
	CustomerId id,
	CustomerStatus status,
	CustomerType type,
	boolean hasPendingIssues
) {}
Customer.java
public record Customer(
	CustomerId id,
	CustomerStatus status,
	CustomerType type,
	boolean hasPendingIssues
) {}

É aqui onde a ACL brilha e interpreta:

LegadoModelo internoO que a tradução resolve
cod_cli: "1029"CustomerIdUma string solta ganha tipo e significado.
sit: "A"CustomerStatus.ACTIVEUm código opaco vira um estado nomeado.
tp_cli: "02"CustomerType.BUSINESSUm número mágico vira um conceito do domínio.
fl_pend: "S"hasPendingIssues = trueUma flag textual vira booleano.

O sistema novo continua usando seu próprio modelo sem copiar nomes, códigos e limitações históricas.

A ACL também permite que a migração aconteça por partes. Algumas operações continuam no legado enquanto outras já foram assumidas pelo sistema moderno.

Em migrações, essa fronteira pode nascer com um critério explícito de remoção. Quando o legado for completamente substituído, a camada deixa de ter função.

Comunicação entre serviços

Dois serviços internos também podem representar o mesmo processo de formas diferentes.

Imagine um serviço de estoque publicando:

{
	"sku": "ABC-123",
	"availabilityCode": 2,
	"warehouse": "REC-01"
}
{
	"sku": "ABC-123",
	"availabilityCode": 2,
	"warehouse": "REC-01"
}

O contexto de pedidos talvez precise apenas saber se o item pode ser reservado. Na fronteira, o código externo ganha um significado interno:

availabilityCode
ACL
Availability Status
2
→
traduz
→
AVAILABLE
availabilityCode
2
→
ACL
traduz
→
Availability Status
AVAILABLE

A ACL traduz a mensagem antes de entregá-la ao modelo de pedidos.

Essa comunicação pode acontecer por REST, gRPC, eventos ou filas. A tradução de protocolo pode fazer parte da fronteira, mas não substitui a tradução de significado.

Outro contexto pode interpretar os mesmos dados de forma diferente:

Contexto de PedidosContexto de ReposiçãoServiço de EstoqueACL de Estoquepara PedidosProductAvailabilityACL de Estoquepara ReposiçãoReplenishmentPriorityavailabilityCodeavailabilityCode+ warehouse
Dois contextos consomem o mesmo serviço de estoque, mas cada ACL preserva uma interpretação própria dos dados.

Infraestrutura técnica pode ser compartilhada: autenticação, client HTTP, rate limiting e telemetria.

A tradução semântica, porém, costuma permanecer próxima do contexto consumidor, porque diferentes contextos podem interpretar o mesmo dado externo de formas diferentes.

Uma ACL central e compartilhada pode existir, mas precisa possuir linguagem e próprios.

Caso contrário, ela corre o risco de se transformar em um modelo corporativo genérico que impõe o mesmo significado a todos os consumidores.

Também é importante não esconder as consequências reais do modelo de comunicação.

Se o trabalho entra em uma fila, continuam existindo , , retentativas e falhas tardias.

A ACL traduz o fluxo. Ela não transforma uma mensagem assíncrona em uma chamada síncrona.

Antes de criar uma ACL entre serviços internos, verifique se existe realmente uma incompatibilidade de modelos.

Às vezes, o problema é apenas um contrato instável, ausência de compatibilidade retroativa ou uma relação mal definida entre as equipes.


Quando uma ACL realmente compensa

Uma ACL deve proteger uma diferença concreta, não hipotética.

Criá-la apenas porque existe uma integração pode produzir mais código sem reduzir a complexidade do sistema.

A pergunta mais importante é:

O que exatamente estamos tentando proteger?

Se o time não consegue responder, talvez a camada esteja sendo criada apenas porque parece “arquiteturalmente elegante”. E é aí que mora o perigo do : adicionar estrutura para resolver um problema que ainda não existe.

Uma ACL tende a fazer sentido quando:

  • os modelos usam linguagens diferentes;
  • conceitos externos não representam bem o negócio interno;
  • o fornecedor muda sem controle da equipe;
  • vários fornecedores precisam ser normalizados;
  • uma migração exige a convivência entre legado e sistema novo;
  • tipos e exceções externas já estão se espalhando;
  • o modelo interno é importante para a evolução do produto.

Quanto maior a diferença semântica, maior o valor da fronteira:

  • Diferença pequena: client ou adapter simples.
  • Diferença localizada: tradução pontual.
  • Diferença profunda: ACL explícita.

A existência de uma API externa, sozinha, não é justificativa suficiente.

Quando aceitar o modelo externo

Nem sempre precisamos manter um modelo próprio.

Se o sistema oferece um contrato estável, com compatibilidade retroativa, e os dois lados usam praticamente os mesmos conceitos, aceitar esse modelo pode ser uma escolha consciente.

No do DDD, essa relação é conhecida como Conformist.

  • Anti-Corruption Layer: preserva um modelo próprio e traduz o upstream.
  • Conformist: aceita conscientemente o modelo do upstream.
  • Adapter simples: ajusta a interface ou a comunicação sem sustentar uma separação semântica relevante.

Considere dois contratos em que id, name, email, active e createdAt possuem exatamente o mesmo significado.

Criar um externo, outro interno, um mapper, uma interface e testes para transformações idênticas pode apenas duplicar estruturas.

Preservar um modelo próprio tem valor quando existe algo relevante para preservar.

Aceitar um contrato externo não significa ausência de arquitetura.

Em alguns cenários, significa reconhecer que o custo da tradução seria maior que o benefício.

Custos e sinais de excesso

Uma ACL oferece proteção, mas essa proteção não é gratuita.

AspectoO que podemos ganharO que precisamos pagar
Modelo internoLinguagem mais clara e independente.Novos tipos e traduções.
Mudanças externasImpacto concentrado na fronteira.Manutenção quando qualquer lado muda.
TestesCasos de uso isolados do fornecedor.Testes de tradução e contrato.
Múltiplos fornecedoresContratos internos estáveis.Adapters específicos e limites de capacidade.
Migração de legadoModernização gradual.Coexistência e sincronização entre sistemas.
ACL remotaOperação ou escala independentes.Rede, deploy e outro ponto de falha.

Também existe o risco de perder informação durante a tradução.

Se o fornecedor possui dez estados e a aplicação reduz todos para três, essa simplificação pode ser útil. Mas também pode esconder diferenças que serão necessárias depois.

Outro sinal de alerta aparece quando vários serviços internos precisam criar ACLs para se proteger de um mesmo sistema.

Pode existir:

  • contrato instável;
  • ausência de compatibilidade retroativa;
  • ownership confuso;
  • mudanças sem coordenação;
  • serviços divididos de forma inadequada;
  • pouca confiança entre os times.

Nesse cenário, adapters e DTOs adicionais aliviam o impacto localmente, mas não resolvem a causa.

A arquitetura pode estar escondendo outro problema

Às vezes, a ACL protege uma incompatibilidade real de modelos.

Em outras, ela apenas compensa contratos instáveis ou uma relação mal definida entre equipes.

Antes de adicionar outra camada, vale perguntar se o contrato upstream deveria ser estabilizado, simplificado ou redesenhado.

A pergunta prática é:

A fronteira reduz mais complexidade do que adiciona?

Quando a resposta é não, um client simples, uma tradução localizada ou uma relação conformista podem ser escolhas melhores.


Onde a ACL vive e por quanto tempo

Uma ACL pode viver dentro da própria aplicação ou como um serviço separado. O ponto de partida mais comum é mantê-la interna: isso reduz latência, infraestrutura e deixa o ownership mais simples.

Separá-la por rede só costuma fazer sentido quando vários consumidores compartilham a mesma tradução, existe um time responsável por ela ou há uma necessidade operacional concreta de isolamento e escala independente.

Mesmo assim, compartilhar a fronteira exige compartilhar significado. Se assinaturas, cobrança e conciliação interpretam o fornecedor de formas diferentes, uma ACL central pode impor mais um modelo externo em vez de proteger cada contexto.

Também vale decidir por quanto tempo essa camada deve existir. Em uma migração gradual, ela pode nascer com data para desaparecer. Em integrações permanentes com gateways, transportadoras ou outros fornecedores, tende a continuar como uma fronteira estável.


Antes de criar uma ACL

Se a fronteira se justifica, estes são os pontos que merecem uma decisão explícita:

  1. Defina qual contexto e qual modelo precisam ser protegidos.
  2. Identifique claramente quem é upstream e quem é downstream.
  3. Compare os significados dos dois lados, não apenas os nomes dos campos.
  4. Comece pelo contrato que a aplicação gostaria de consumir.
  5. Traduza significado, erros, referências e eventos — não apenas estruturas.
  6. Restrinja DTOs, enums, códigos e exceções externas à integração.
  7. Não coloque regras centrais de negócio dentro da fronteira.
  8. Trate valores desconhecidos e possíveis perdas de informação explicitamente.
  9. Não prometa intercambiabilidade onde os fornecedores possuem capacidades diferentes.
  10. Verifique se a proteção reduz mais complexidade do que adiciona.

Não use uma ACL apenas porque existe uma integração.

Use quando aceitar o modelo externo prejudicaria a linguagem, as regras ou a evolução da aplicação.


Antes de fechar, cinco perguntas rápidas sobre a fronteira e sobre quando ela compensa:

Questão1/5

No contexto de uma ACL, o que significa "corrupção"?


Conclusão

Contratos, códigos e exceções externas raramente invadem uma aplicação de uma vez. Eles entram um if por vez, cada um pequeno demais para justificar uma camada inteira.

A Anti-Corruption Layer concentra esse conhecimento em uma fronteira controlada, para que cada lado continue falando sua própria linguagem.

Ela cobra por isso: novos tipos, adapters, traduções e testes.

Quando os modelos já dizem a mesma coisa, a camada pode apenas duplicar estrutura. E, quando fornecedores possuem capacidades realmente diferentes, ela não os torna intercambiáveis por mágica.

Uma boa integração permite que dois sistemas conversem.

Uma boa Anti-Corruption Layer permite que eles conversem sem obrigá-los a pensar da mesma forma.

Agora abra a integração mais antiga do seu projeto e procure um status, um DTO ou uma exceção do fornecedor fora da camada de integração.

Se encontrar, você achou uma fronteira que merece ser revista.

Nesta página

Compartilhe

Referências

Guias e leituras sobre Anti-Corruption Layer, DDD e integração entre contextos.

Ednaldo Luiz
GitHubLinkedInPortfólio

Ednaldo Luiz

Arquiteto e Engenheiro de Software | Java & IA

Engenheiro de Software focado em arquitetura e performance. Trabalho com Java/Spring Boot, SQL bem estruturado, serviços escaláveis na AWS e soluções GenAI com RAG (LangChain + bases vetoriais). Valorizo código legível e decisões bem justificadas.