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

138

Estou tentando descobrir o que a camada Anticorrupção realmente significa. Eu sei que é uma maneira de fazer a transição / trabalhar com código legado ou APIs ruins. O que eu não entendo é como funciona e o que faz dele uma separação clara 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 isso com exemplos simples. Uma resposta que satisfaria minha pergunta deveria 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.

    
por knownasilya 22.01.2013 / 17:14
fonte

4 respostas

138

Imagine que você precisa usar o código de outra pessoa projetado conforme 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 depende do 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ê quer 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, você começa a criar uma camada anticorrupção.

  1. A primeira coisa é garantir que o seu "código principal" não se refira a Messy diretamente. Por exemplo, você organiza o gerenciamento de dependências de tal forma que tente acessar Messy falha na compilação.

  2. Em segundo lugar, você cria um módulo "camada" dedicado que é o único que acessa Messy e o expõe ao seu "código principal" de uma maneira que faz mais sentido para você.

O código da camada seria semelhante ao seguinte:

    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, seu "código principal" não é confundido com Messy , usando Reasonable da seguinte forma:

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á uma bagunça mexendo com Messy , mas isso está escondido razoavelmente dentro de Reasonable , tornando seu "código principal" razoavelmente limpo e livre de corrupção que seria trazido para lá pelo uso direto de Messy stuff.

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

If your application needs to deal with a database or another application whose model is undesirable or inapplicable to the model you want within your own application, use an AnticorruptionLayer to translate to/from that model and yours.

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

Se você tem uma grande confusão de API para cobrir a camada anticorrupção, a mesma abordagem se aplica: primeiro, certifique-se de que seu "código principal" não acesse material corrompido diretamente e segundo, exponha-o de uma maneira que seja mais conveniente em seu contexto de uso.

Quando "dimensionar" sua camada além de um exemplo simplificado acima, leve em consideração que tornar sua API conveniente não é necessariamente uma tarefa trivial. Invista um esforço para projete sua camada da maneira certa , verifique se uso pretendido com testes unitários etc.

Em outras palavras, certifique-se de que sua API seja de fato uma melhoria sobre a que ela oculta. Certifique-se de não introduzir apenas outra camada de corrupção.

Por uma questão de completude, observe a diferença sutil, mas importante, entre este e os padrões relacionados Adaptador e Facade . Como indicado pelo nome, a camada anticorrupção assume que a API subjacente tem problemas de qualidade (é" corrompido ") e pretende oferecer uma proteção dos problemas mencionados.

Você pode pensar desta forma: se você puder justificar que o designer de bibliotecas seria melhor expor sua funcionalidade com Reasonable em vez de Messy , isso significaria que você está trabalhando na camada anticorrupção, fazendo trabalho deles, corrigindo os erros de design deles .

Ao contrário disso, Adaptador e Fachada não fazem suposições sobre a qualidade do design subjacente. Isso pode ser aplicado à API que foi bem projetada para começar, apenas adaptando-a para suas necessidades específicas.

Na verdade, pode até ser mais produtivo supor que padrões como Adaptador e Fachada esperem que o código subjacente seja bem projetado. Você pode pensar assim: 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 exigir mais esforço do que o esperado, isso pode indicar que o código subjacente está, de alguma forma, "corrompido". Nesse caso, você pode considerar dividir o trabalho em fases separadas: primeiro, estabelecer uma camada anticorrupção para apresentar a API subjacente de maneira adequadamente estruturada e, em seguida, projetar seu adaptador / fachada sobre essa camada de proteção.

    
por 22.01.2013 / 18:19
fonte
34

Para citar outra fonte:

Create an isolating layer to provide clients with functionality in terms of their own domain model. The layer talks to the other system through its existing interface, requiring little or no modification to the other system. Internally, the layer translates in both directions as necessary between the two models.

Eric Evans, Design dirigido por domínio, 16ª impressão, página 365

O mais importante é que termos diferentes sejam usados em cada lado da camada anti-corrupção. Eu já trabalhei em um sistema de logística de transporte. Rodadas tinham que ser planejadas. Você tinha que equipar o veículo em um depósito, dirigir para diferentes locais do cliente e atendê-los e visitar outros lugares, como uma parada de tanques. Mas a partir do nível mais alto, isso era tudo sobre planejamento de tarefas. Então, fazia sentido separar os termos de planejamento de tarefas mais gerais dos termos muito específicos de logística de transporte.

Portanto, um isolamento de camadas anti-corrupção não é apenas proteger você do código confuso, mas sim separar domínios diferentes e garantir que eles permaneçam separados no futuro.

    
por 26.01.2013 / 16:52
fonte
28

Adaptador

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

Exemplo:

Você tem um objeto que quer um carro, mas só tem uma classe 4WheelVehicle, portanto crie um CarBuiltUsing4WheelVehicle e use-o como seu carro.

Fachada

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

Exemplo:

Você está usando uma biblioteca que tem 100 métodos, e para executar determinada tarefa você precisa fazer um monte de inicialização, conectar, abrir / fechar coisas, para finalmente poder fazer o que você queria, e tudo que você quer é 1 característica de todos os 50 que a biblioteca pode fazer, então você cria um Fachada que tem apenas um método para aquele recurso que você precisa e que faz toda a inicialização, limpeza, etc. para você.

Camada anti-corrupção

Quando você tem um sistema fora do seu domínio, as necessidades da sua empresa exigem que você trabalhe com outro domínio. Você não quer introduzir este outro domínio no seu próprio, portanto corrompendo-o, assim você traduzirá o conceito do seu domínio para este outro domínio, e vice-versa.

Exemplo:

Um sistema visualiza o cliente com um nome e uma lista de strings, uma para cada transação. Você visualiza os Perfis como classes independentes que possuem um nome e Transações como classes independentes que possuem uma cadeia e o Cliente como tendo um Perfil e uma coleta de Transações.

Assim, você cria uma camada de ACL que permite a conversão entre o seu cliente e o cliente do outro sistema. Dessa forma, você nunca precisará usar o cliente do outro sistema, basta avisar a ACL: "me dê o cliente com o perfil X, e a ACL informará ao outro sistema para fornecer um cliente com nome X.name e 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 / sub-sistemas. Você poderia tê-los todos combinados se você precisasse. O sub-sistema tem uma API complexa, então você constrói um FACADE para ele, ele usa um modelo diferente, então para cada representação de dados que não se encaixa em seu modelo, você deveria TRADUZIR os dados de volta para a forma como você os modelou. Finalmente, talvez as interfaces também sejam incompatíveis, então você usaria ADAPTADORES para se adaptar de um para o outro.

    
por 14.11.2014 / 04:08
fonte
11

Muitas respostas dizem que as ACLs "não são apenas" sobre envolver código confuso. Eu iria mais longe e diria que eles não são nada disso, e se eles fizerem isso, isso é um benefício colateral.

Uma camada anticorrupção tem a ver com o mapeamento de um domínio para outro, de forma que os serviços que usam o segundo domínio não precisem ser "corrompidos" pelos conceitos do primeiro. ACLs são para modelos de domínio o que adaptadores são para classes, está acontecendo apenas em um nível diferente. O adaptador é indiscutivelmente o padrão de design mais importante - eu o uso o tempo todo - mas julgar a classe envolvida como sendo confusa ou não é irrelevante. É o que é, eu só preciso de uma interface diferente.

Focar na bagunça é enganoso e deixa de lado o objetivo do DDD. ACLs são sobre lidar com incompatibilidades conceituais, e não má qualidade.

    
por 10.06.2016 / 12:09
fonte