¿Qué es una capa anticorrupción y cómo se usa?


151

Estoy tratando de descubrir qué significa realmente la capa anticorrupción. Sé que es una forma de hacer la transición / evitar código heredado o API incorrectas. Lo que no entiendo es cómo funciona y qué lo hace una separación limpia de la capa indeseable.

He realizado algunas búsquedas, pero no puedo encontrar ejemplos o explicaciones simples, así que estoy buscando a alguien que lo entienda y pueda explicarlo con ejemplos simples. Una respuesta que satisfaga mi pregunta debe ser simple (no necesariamente corta) y proporcionar ejemplos comprensibles de implementación y uso.

Vea esta pregunta , para mi caso de uso.

Respuestas:


147

Imagine que tiene que usar el código de otra persona que está diseñado como se muestra a continuación:

    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) { /* ... */ }
    }

Ahora imagine que descubre que su código que depende de él se parece a lo siguiente:

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?
}

... y que desea facilitar su uso, en particular, para deshacerse del uso repetitivo de parámetros que simplemente no son necesarios para su aplicación.

Bien, entonces comienzas a construir una capa anticorrupción.

  1. Lo primero es asegurarse de que su "código principal" no se refiera Messydirectamente. Por ejemplo, organiza la gestión de dependencias de tal manera que al intentar acceder Messyno se compila.

  2. En segundo lugar, crea un módulo de "capa" dedicado que es el único que accede Messyy lo expone a su "código principal" de una manera que tenga más sentido para usted.

El código de capa se vería así:

    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, su "código principal" no se mete con Messy, utilizando en su Reasonablelugar, aproximadamente lo siguiente:

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");
}

Tenga en cuenta que todavía hay un poco de desorden con Messyesto, pero ahora está oculto razonablemente en el fondo Reasonable, haciendo que su "código principal" sea razonablemente limpio y libre de corrupción que se llevaría allí por el uso directo de Messycosas.


El ejemplo anterior se basa en cómo se explica la capa anticorrupción en c2 wiki:

Si su aplicación necesita tratar con una base de datos u otra aplicación cuyo modelo no es deseable o no es aplicable al modelo que desea dentro de su propia aplicación, use un AnticorruptionLayer para traducir a / desde ese modelo y el suyo.

El ejemplo de la nota se hace intencionalmente simple y condensado para mantener la explicación breve.

Si tiene un desorden de API más grande para cubrir detrás de la capa anticorrupción, se aplica el mismo enfoque: primero, asegúrese de que su "código principal" no acceda a cosas corruptas directamente y segundo, exponga de una manera que sea más conveniente en su contexto de uso.

Al "escalar" su capa más allá de un ejemplo simplificado anterior, tenga en cuenta que hacer que su API sea conveniente no es necesariamente una tarea trivial. Invierta un esfuerzo para diseñar su capa de la manera correcta , verifique su uso previsto con pruebas unitarias, etc.

En otras palabras, asegúrese de que su API sea realmente una mejora sobre la que oculta, asegúrese de no solo introducir otra capa de corrupción.


En aras de la exhaustividad, observe la diferencia sutil pero importante entre este y los patrones relacionados Adaptador y Fachada . Como lo indica su nombre, la capa anticorrupción supone que la API subyacente tiene problemas de calidad (está "corrupta") y tiene la intención de ofrecer una protección de los problemas mencionados.

Puede pensarlo de esta manera: si puede justificar que el diseñador de la biblioteca estaría mejor exponiendo su funcionalidad en Reasonablelugar de Messy, esto significaría que está trabajando en la capa anticorrupción, haciendo su trabajo, reparando sus errores de diseño.

A diferencia de eso, Adapter y Facade no hacen suposiciones sobre la calidad del diseño subyacente. Estos podrían aplicarse a una API que está bien diseñada para comenzar, simplemente adaptándola a sus necesidades específicas.

En realidad, incluso podría ser más productivo suponer que patrones como Adaptador y Fachada esperan que el código subyacente esté bien diseñado. Puede pensarlo de esta manera: el código bien diseñado no debería ser demasiado difícil de modificar para un caso de uso particular. Si resulta que el diseño de su adaptador requiere más esfuerzo de lo esperado, esto podría indicar que el código subyacente está, de alguna manera, "dañado". En ese caso, puede considerar dividir el trabajo en fases separadas: primero, establezca una capa anticorrupción para presentar la API subyacente de una manera adecuadamente estructurada y luego, diseñe su adaptador / fachada sobre esa capa de protección.


1
¿Cómo se escala esto si hay una estructura completa de clases de API dependientes? ¿Es aún más manejable que la capa de la que protege el resto de la aplicación?
conocidoasilya

1
@Knownasilya eso es una muy buena pregunta, la respuesta se amplió para abordar ese
mosquito

44
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.Toda esa sección es digna de una etiqueta en negrita.
Lilienthal

19
Las capas anticorrupción no tienen nada que ver con lidiar con API de baja calidad. Se trata de lidiar con desajustes conceptuales, adaptando dominios que solo podríamos usar al "corromper" nuestro código a dominios que podemos usar más fácilmente.
Ian Fairman

8
Ian Fairman acertó, mientras que el autor de esta respuesta definitivamente no lo hizo. Si va a la fuente del concepto (el libro DDD), encontrará al menos dos cosas que contradicen esta respuesta: 1) se crea una capa anticorrupción para evitar corromper el nuevo modelo de dominio que estamos desarrollando con elementos del modelo de un sistema externo existente; no es que el otro sistema esté "dañado", de hecho puede ser perfectamente bueno y estar bien diseñado; 2) una capa anticorrupción generalmente contendrá varias clases, a menudo incluyendo Fachadas y Adaptadores , así como Servicios .
Rogério

41

Para citar otra fuente:

Cree una capa de aislamiento para proporcionar a los clientes funcionalidad en términos de su propio modelo de dominio. La capa se comunica con el otro sistema a través de su interfaz existente, lo que requiere poca o ninguna modificación al otro sistema. Internamente, la capa se traduce en ambas direcciones según sea necesario entre los dos modelos.

Eric Evans, Diseño dirigido por dominio, 16a impresión, página 365

Lo más importante es que se utilizan diferentes términos a cada lado de la capa anticorrupción. Una vez estuve trabajando en un sistema de logística de transporte. Las rondas tuvieron que ser planificadas. Debía equipar el vehículo en un depósito, conducir a diferentes sitios de clientes y darles servicio y visitar otros lugares, como una parada de tanques. Pero desde el nivel superior, todo se trataba de planificación de tareas. Por lo tanto, tenía sentido separar los términos más generales de planificación de tareas de los términos logísticos de transporte muy específicos.

Por lo tanto, un aislamiento de capas anticorrupción no se trata solo de protegerlo del código desordenado, sino de separar diferentes dominios y asegurarse de que permanezcan separados en el futuro.


66
¡Esto es muy importante! Una ACL no solo debe usarse con código desordenado, sino como un medio para comunicarse entre contextos acotados. Se traduce de un contexto a otro, de modo que los datos en cada contexto reflejan el lenguaje y la forma en que ese contexto piensa y habla sobre los datos.
Didier A.

29

Adaptador

Cuando tiene interfaces incompatibles, que realizan una lógica similar, para adaptarse una a la otra, de modo que pueda usar implementaciones de una con cosas que esperan la otra.

Ejemplo:

Tiene un objeto que quiere un automóvil, pero solo tiene una clase 4WheelVehicle, por lo que crea un CarBuiltUsing4WheelVehicle y lo usa como su automóvil.

Fachada

Cuando tiene una API compleja / confusa / gigantesca y desea simplificarla / aclararla / reducirla. Creará una Fachada para ocultar la complejidad / confusión / extras y solo expondrá una nueva API simple / clara / pequeña.

Ejemplo:

Está utilizando una biblioteca que tiene 100 métodos, y para realizar cierta tarea necesita hacer un montón de inicialización, conexión, apertura / cierre de cosas, solo para finalmente poder hacer lo que quería, y todo lo que quería es 1 característica de los 50 que puede hacer la biblioteca, por lo que crea una Fachada que solo tiene un método para esa característica que necesita y que realiza toda la inicialización, limpieza, etc.

Capa anticorrupción

Cuando tiene un sistema que está fuera de su dominio, sin embargo, las necesidades de su negocio requieren que trabaje con ese otro dominio. No desea introducir este otro dominio en el suyo propio, por lo tanto, corromperlo, por lo que traducirá el concepto de su dominio, a este otro dominio, y viceversa.

Ejemplo:

Un sistema ve al cliente que tiene un nombre y una lista de cadenas, una para cada transacción. Usted ve los Perfiles como clases independientes que tienen un nombre, y las Transacciones como clases independientes que tienen una cadena, y el Cliente tiene un Perfil y una colección de Transacciones.

Por lo tanto, crea una capa de ACL que permitirá traducir entre su Cliente y el Cliente del otro sistema. De esta manera, nunca tiene que usar el Cliente del otro sistema, simplemente debe decirle a la ACL: "deme el Cliente con el Perfil X, y la ACL le dice al otro sistema que le dé un Cliente con el nombre X.name, y devuelve usted un cliente con perfil X.

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

Los tres son relativamente similares, porque todos son patrones de indirección. Pero abordan diferentes estructuras, clases / objetos versus API versus módulos / subsistemas. Podrías combinarlos todos si fuera necesario. El subsistema tiene una API compleja, por lo que construye una FACHADA para él, utiliza un modelo diferente, por lo que para cada representación de datos que no se ajuste a su modelo, VOLVERÁ A TRADUCIR esos datos a la forma en que lo modela. Finalmente, tal vez las interfaces también sean incompatibles, por lo que usaría ADAPTADORES para adaptarse de uno a otro.


12

Muchas respuestas aquí dicen que las ACL "no son solo" acerca de envolver código desordenado. Yo iría más lejos y diría que no se trata de eso en absoluto, y si lo hacen, eso es un beneficio adicional.

Una capa anticorrupción se trata de mapear un dominio sobre otro para que los servicios que usan el segundo dominio no tengan que estar "corrompidos" por los conceptos del primero. Las ACL son para modelos de dominio lo que los adaptadores son para las clases, simplemente está sucediendo en un nivel diferente. Podría decirse que el adaptador es el patrón de diseño más importante, lo uso todo el tiempo, pero juzgar que la clase envuelta es desordenada o no es irrelevante. Es lo que es, solo necesito que tenga una interfaz diferente.

Centrarse en el desorden es engañoso y se pierde el punto de lo que se trata DDD. Las ACL tratan sobre desajustes conceptuales, no de baja calidad.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.