O que é uma camada Anticorrupção e como é usada?


151

Estou tentando descobrir o que realmente significa a camada anticorrupção. Eu sei que é uma maneira de fazer a transição / contornar código legado ou APIs incorretas. O que não entendo é como funciona e o que a torna uma separação limpa da camada indesejável.

Eu fiz algumas pesquisas, mas não consigo encontrar exemplos ou explicações simples, então estou procurando alguém que entenda e possa explicar com exemplos simples. Uma resposta que satisfaça minha pergunta deve ser simples (não necessariamente curta) e fornecer exemplos compreensíveis de implementação e uso.

Veja esta pergunta , para o meu caso de uso.

Respostas:


147

Imagine que você precise usar o código de outra pessoa que é projetado como mostrado abaixo:

    class Messy {
        String concat(String param, String str) { /* ... */ }
        boolean contains(String param, String s) { /* ... */ }
        boolean isEmpty(String param) { /* ... */ }
        boolean matches(String param, String regex) { /* ... */ }
        boolean startsWith(String param, String prefix) { /* ... */ }
    }

Agora imagine que você descubra que seu código que depende dele se parece com o seguinte:

String process(String param) {
    Messy messy = new Messy();
    if (messy.contains(param, "whatever")) {
        return messy.concat(param, "-contains");
    }
    if (messy.isEmpty(param)) {
        return messy.concat(param, "-empty");
    }
    if (messy.matches(param, "[whatever]")) {
        return messy.concat(param, "-matches");
    }
    if (messy.startsWith(param, "whatever")) {
        return messy.concat(param, "-startsWith");
    }
    return messy.concat(param, "-whatever");
    // WTF do I really need to repeat bloody "param" 9 times above?
}

... e que você deseja facilitar o uso, em particular, para se livrar do uso repetitivo de parâmetros que simplesmente não são necessários para o seu aplicativo.

Ok, então você começa a criar uma camada anticorrupção.

  1. A primeira coisa é garantir que o seu "código principal" não se refira Messydiretamente. Por exemplo, você organiza o gerenciamento de dependências de tal maneira que a tentativa de acessar Messyfalha na compilação.

  2. Segundo, você cria um módulo de "camada" dedicado, que é o único que acessa Messye o expõe ao seu "código principal" de uma maneira que faça mais sentido para você.

O código da camada teria a seguinte aparência:

    class Reasonable { // anti-corruption layer
        String param;
        Messy messy = new Messy();
        Reasonable(String param) {
            this.param = param;
        }
        String concat(String str) { return messy.concat(param, str); }
        boolean contains(String s) { return messy.contains(param, s); }
        boolean isEmpty() { return messy.isEmpty(param); }
        boolean matches(String regex) { return messy.matches(param, regex); }
        boolean startsWith(String prefix) { return messy.startsWith(param, prefix); }
    }

Como resultado, o seu "código principal" não mexe Messy, usando em Reasonablevez disso, da seguinte maneira:

String process(String param) {
    Reasonable reasonable = new Reasonable(param);
    // single use of "param" above and voila, you're free
    if (reasonable.contains("whatever")) {
        return reasonable.concat("-contains");
    }
    if (reasonable.isEmpty()) {
        return reasonable.concat("-empty");
    }
    if (reasonable.matches("[whatever]")) {
        return reasonable.concat("-matches");
    }
    if (reasonable.startsWith("whatever")) {
        return reasonable.concat("-startsWith");
    }
    return reasonable.concat("-whatever");
}

Note que ainda há um pouco de confusão, Messymas isso agora está razoavelmente escondido no fundo Reasonable, tornando seu "código principal" razoavelmente limpo e livre de corrupção que seria trazida para lá pelo uso direto de Messycoisas.


O exemplo acima é baseado em como a Camada Anticorrupção é explicada no c2 wiki:

Se seu aplicativo precisar lidar com um banco de dados ou outro aplicativo cujo modelo seja indesejável ou inaplicável ao modelo que você deseja em seu próprio aplicativo, use um AnticorruptionLayer para converter de / para esse modelo e o seu.

O exemplo de nota é intencionalmente simplificado e condensado para manter a explicação breve.

Se você tem uma bagunça de API maior para cobrir a camada anticorrupção, aplica-se a mesma abordagem: primeiro, verifique se o seu "código principal" não acessa diretamente itens corrompidos e depois, exponha-o de uma maneira que seja mais conveniente no seu contexto de uso.

Ao "escalar" sua camada além do exemplo simplificado acima, leve em consideração que tornar sua API conveniente não é necessariamente uma tarefa trivial. Invista um esforço para projetar sua camada da maneira correta , verifique seu uso pretendido com testes de unidade etc.

Em outras palavras, verifique se a sua API é realmente uma melhoria sobre a que oculta, e não apenas introduza outra camada de corrupção.


Por uma questão de integridade, observe uma diferença sutil, mas importante, entre este e os padrões relacionados Adapter e Facade . Conforme indicado pelo nome, a camada anticorrupção pressupõe que a API subjacente tenha problemas de qualidade (está "corrompida") e pretende oferecer uma proteção dos problemas mencionados.

Você pode pensar dessa maneira: se você puder justificar que o designer da biblioteca seria melhor expor sua funcionalidade com, em Reasonablevez de Messy, isso significa que você está trabalhando na camada anticorrupção, realizando seu trabalho, corrigindo seus erros de design.

Ao contrário disso, o Adapter e o Facade não fazem suposições sobre a qualidade do design subjacente. Eles podem ser aplicados à API bem projetada para começar, apenas adaptando-a às suas necessidades específicas.

Na verdade, pode ser ainda mais produtivo supor que padrões como o Adapter e o Facade esperam que o código subjacente seja bem projetado. Você pode pensar desta maneira: código bem projetado não deve ser muito difícil de ajustar para um caso de uso específico. Se o design do seu adaptador demorar mais do que o esperado, isso pode indicar que o código subjacente está, de alguma forma, "corrompido". Nesse caso, você pode considerar a divisão do trabalho em fases separadas: primeiro, estabeleça uma camada anticorrupção para apresentar a API subjacente de uma maneira adequadamente estruturada e, a seguir, projete seu adaptador / fachada sobre essa camada de proteção.


1
Como isso é dimensionado se houver toda uma estrutura de classes de API dependentes? Ainda é mais gerenciável do que a camada da qual está protegendo o restante do aplicativo?
knownasilya

1
@Knownasilya isso é uma boa pergunta, resposta expandida para resolver essa
mosquito

4
In other words, make sure that your API is indeed an improvement over one it hides, make sure that you don't just introduce another layer of corruption.Essa seção inteira é digna de uma marca em negrito.
Lilienthal

19
As camadas anticorrupção não têm nada a ver com lidar com APIs de baixa qualidade. Eles tratam de incompatibilidades conceituais, adaptando domínios que só poderíamos usar "corrompendo" nosso código a domínios que podemos usar com mais facilidade.
precisa

8
Ian Fairman acertou, enquanto o autor desta resposta definitivamente não o fez. Se você for para a fonte do conceito (o livro DDD), encontrará pelo menos duas coisas que contradizem essa resposta: 1) uma camada anticorrupção é criada para evitar a corrupção do novo modelo de domínio que estamos desenvolvendo com elementos do modelo de um sistema externo existente; não é que o outro sistema esteja "corrompido"; de fato, ele pode ser perfeitamente bom e bem projetado; 2) uma camada anticorrupção geralmente contém várias classes, geralmente incluindo Fachadas e Adaptadores , além de Serviços .
Rogério

41

Para citar outra fonte:

Crie uma camada de isolamento para fornecer aos clientes funcionalidade em termos de seu próprio modelo de domínio. A camada se comunica com o outro sistema através de sua interface existente, exigindo pouca ou nenhuma modificação no outro sistema. Internamente, a camada é traduzida nas duas direções conforme necessário entre os dois modelos.

Eric Evans, Domain Driven Design, 16ª impressão, página 365

O mais importante é que termos diferentes sejam usados ​​em cada lado da camada anticorrupção. Eu estava trabalhando em um sistema de logística de transporte. Rodadas tiveram que ser planejadas. Você tinha que equipar o veículo em um depósito, dirigir para diferentes locais de clientes, atendê-los e visitar outros lugares, como uma parada de tanque. Mas, do nível superior, tudo isso era sobre planejamento de tarefas. Portanto, fazia sentido separar os termos mais gerais de planejamento de tarefas dos termos muito específicos da logística de transporte.

Portanto, um isolamento de camadas anticorrupção não é apenas proteger você de códigos confusos, é separar domínios diferentes e garantir que eles fiquem separados no futuro.


6
Isto é muito importante! Uma ACL não deve ser usada apenas com o código Messy, mas como um meio de comunicação entre contextos limitados. Ele se traduz de um contexto para o outro, para que os dados em cada contexto reflitam o idioma e a maneira como esse contexto pensa e fala sobre os dados.
Didier A.

29

Adaptador

Quando você possui interfaces incompatíveis, que executam lógica semelhante, para adaptar uma à outra, para que você possa usar implementações de uma com coisas que esperam a outra.

Exemplo:

Você tem um objeto que deseja um carro, mas apenas uma classe 4WheelVehicle, então cria um CarBuiltUsing4WheelVehicle e o usa como seu carro.

Fachada

Quando você tem uma API complexa / confusa / gigantesca e deseja torná-la mais simples / clara / menor. Você criará uma fachada para ocultar a complexidade / confusão / extras e apenas expor uma nova API simples / clara / pequena.

Exemplo:

Você está usando uma biblioteca que possui 100 métodos e, para executar determinadas tarefas, é necessário executar várias tarefas de inicialização, conexão, abertura / fechamento, apenas para finalmente poder fazer o que você queria, e tudo o que você queria era um recurso do todas as 50 bibliotecas podem fazer, então você cria uma Fachada que possui apenas um método para o recurso 1 necessário e que faz toda a inicialização, limpeza etc. para você.

Camada anticorrupção

Quando você tem um sistema fora do seu domínio, as necessidades da sua empresa exigem que você trabalhe com esse outro domínio. Você não deseja introduzir esse outro domínio em seu próprio país, corrompendo-o, portanto, converterá o conceito de seu domínio nesse outro domínio e vice-versa.

Exemplo:

Um sistema exibe o cliente com um nome e uma lista de cadeias, uma para cada transação. Você vê Perfis como classes independentes com um nome e Transações como classes independentes com uma cadeia de caracteres e Customer como tendo um Perfil e uma coleção de Transações.

Então, você cria uma camada ACL que permitirá a conversão entre o cliente e o cliente do outro sistema. Dessa forma, você nunca precisará usar o Cliente do outro sistema, basta informar à ACL: "dê-me o Cliente com o Perfil X, e a ACL instrui o outro sistema a fornecer a um Cliente com o nome X.name e retorna você é um cliente com perfil X.

====================

Todos os três são relativamente semelhantes, porque são todos padrões de indireção. Mas eles abordam diferentes estruturas, classes / objetos versus APIs versus módulos / subsistemas. Você poderia combiná-los todos, se necessário. O subsistema possui uma API complexa; portanto, você cria um FACADE para ele, usa um modelo diferente; portanto, para cada representação de dados que não se encaixa no seu modelo, você TRANSLATE esses dados de volta para a forma como o modela. Finalmente, talvez as interfaces também sejam incompatíveis, portanto você usaria ADAPTERS para se adaptar de um para o outro.


12

Muitas respostas aqui dizem que as ACLs "não são apenas" sobre quebra de código confuso. Eu iria além e diria que eles não têm nada a ver com isso, e se o fizerem, esse é um benefício colateral.

Uma camada anticorrupção é sobre o mapeamento de um domínio para outro, para que os serviços que usam o segundo domínio não precisem ser "corrompidos" pelos conceitos do primeiro. As ACLs são para modelos de domínio o que são adaptadores para classes, isso está acontecendo em um nível diferente. O adaptador é sem dúvida o padrão de design mais importante - eu o uso o tempo todo -, mas julgar a classe finalizada como desarrumada ou não é irrelevante. É o que é, eu só preciso que ele tenha uma interface diferente.

Concentrar-se na bagunça é enganoso e perde o objetivo do DDD. As ACLs tratam de incompatibilidades conceituais, não de baixa qualidade.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.