Introduccion
En artículos anteriores, identificamos el alcance del enfoque y examinamos los principios metodológicos básicos del diseño dirigido por dominio .
En este artículo, me gustaría describir los principales enfoques modernos para construir la arquitectura de los sistemas corporativos: Supple, Screaming, Clean y darles mi interpretación clara en forma de una solución completa llave en mano.

En el futuro, consideraremos cada patrón de diseño en detalle: indicamos el alcance, damos ejemplos de código, destacamos las prácticas recomendadas. Como resultado, escribiremos un microservicio listo para usar.
Arquitectura flexible
En el último artículo, nos centramos en el hecho de que DDD incluye la práctica de implementación a través del modelo. El área temática debe describirse a través de su código. Intentemos descubrir cómo hacer esto.
En su libro, Eric Evans proporciona una serie de patrones de diseño recomendados y designa este enfoque como flexible:
En nombre de la flexibilidad de la arquitectura, se acumularon muchas construcciones innecesarias en los programas. Los niveles excesivos de abstracción y vinculación indirecta tienen más probabilidades de interferir que ayudar en este asunto. Mire la arquitectura que realmente inspira a los programadores a refinarla, y generalmente verá algo muy simple. Pero simple no significa fácil de ejecutar. Para crear elementos que puedan ensamblarse en sistemas complejos y al mismo tiempo que sea fácil de entender, es necesario combinar la "dedicación" al diseño de acuerdo con el modelo con un estilo de arquitectura bastante estricto. Se necesita una cierta habilidad de diseño no solo para crear algo, sino incluso para usar el acabado.
Eric Evans, Diseño impulsado por dominio: abordar la complejidad en el corazón del software
El conjunto presentado de patrones de diseño no es una arquitectura estricta o una solución preparada, sino más bien una reflexión.
Arquitectura llamativa
Pensamientos similares surgieron en la mente de muchos desarrolladores y diseñadores de sistemas complejos.
En 2011, se publicó un artículo de Robert Martin - Screaming Architecture , que dice que su código no solo debe describir el área temática, sino gritar al respecto, preferiblemente obscenamente.
Entonces, ¿qué grita la arquitectura de su aplicación? Cuando observa la estructura de directorios de nivel superior y los archivos de origen en el paquete de nivel más alto; ¿gritan: sistema de salud o sistema de contabilidad o sistema de gestión de inventario? ¿O gritan: Rails, Spring / Hibernate o ASP?
Robert C. Martin, 30 de septiembre de 2011
Robert dice que el código de su aplicación debe reflejar la actividad de la aplicación, en lugar de adaptarse a las reglas del marco. La estructura del marco no debe limitar su arquitectura. La aplicación, a su vez, no debe adjuntarse a la base de datos o al protocolo http, estos son solo mecanismos de almacenamiento y entrega. El cuadro delimitador es una herramienta. No debe convertirse en un adherente del marco. Las pruebas de su aplicación son pruebas de la lógica de su funcionamiento y no prueban el protocolo http.
Arquitectura limpia
Un año después, el siguiente artículo de Robert Martin - The Clean Architecture . En él, el autor dice cómo hacer que el código grite. Después de estudiar varias arquitecturas, identifica los principios básicos:
- Marco de independencia. La arquitectura no depende de ninguna biblioteca existente. Esto le permite usar marcos como herramientas, en lugar de las restricciones que unen sus manos.
- Testabilidad Las reglas comerciales se pueden probar sin una interfaz de usuario, base de datos, servidor web o cualquier otro medio técnico.
- UI independencia. La interfaz de usuario se puede cambiar fácilmente sin cambiar el resto del sistema. Por ejemplo, la interfaz web se puede reemplazar con la interfaz de la consola sin cambiar la lógica empresarial.
- Independencia de la base de datos. Puede intercambiar Oracle o SQL Server por Mongo, BigTable, CouchDB u otra cosa. La lógica de su aplicación no debe estar vinculada a la base de datos.
- Independencia de las influencias ambientales. De hecho, sus reglas comerciales simplemente no saben nada sobre el mundo exterior.
En un habr ya se publicó un muy buen artículo Conceptos erróneos Clean Architecture . Su autor, Jeevuz , masticó muy bien las complejidades de comprender este enfoque. Le recomiendo que se familiarice con él y con los materiales originales.
Arquitectura variable
La descripción del enfoque anterior no parece tan sencilla. Como parte del desarrollo de la arquitectura de varios sistemas corporativos complejos, mis colegas y yo hemos desarrollado una interpretación bastante clara de los enfoques descritos, que tengo la intención de presentar a continuación.
Antes del advenimiento de las computadoras y los lenguajes de programación, el flujo de trabajo en papel se usaba para construir y administrar sistemas con lógica empresarial compleja. El resultado de cualquier proceso fue un documento que finalmente describía un objeto comercial particular. Como resultado, el papeleo se redujo a tres acciones simples:
- Creación de documentos
- Procesamiento de documentos
- Trabaja con el archivo de documentos
- Envío de documentos
Documento: registro de información sobre actividades económicas de un objeto comercial real en particular.
Tenga en cuenta que el documento en sí no es un objeto comercial real, sino solo su modelo . Actualmente, los documentos en papel están siendo reemplazados por documentos electrónicos. Un documento puede ser un registro en una tabla, una imagen, un archivo, una carta enviada o cualquier otra información.
No me gustaría usar el documento de Word en el futuro, ya que será más confuso, usaremos el concepto de Entidad de la terminología DDD. Pero puede imaginar que ahora todo su sistema es un sistema de gestión de documentos electrónicos que realiza cuatro acciones simples.
- Coleccionar
- Procesamiento
- Almacenamiento
- Representacion
Acción: una unidad estructural de actividad de un modelo de negocio; un acto separado relativamente completo de un objetivo consciente, la arbitrariedad e intencionalidad de la actividad individual de un objeto comercial, distinguido por el usuario final.
Un buen ejemplo de acción es un acto teatral. El teatro modela eventos de la vida real. El acto es una parte significativa de la obra. Pero, para completar la historia, debes interpretar varios actos en un orden estrictamente designado. Tal orden en nuestra arquitectura lo llamaremos Modo .
Modo (conducción): un conjunto de acciones en un cierto orden, que tiene un significado completo, beneficioso para el usuario final.

Para tales modos de operación, se inventó un conductor selectivo o selector. Más precisamente, "Mecanismo de temporización para conducir uno seleccionado de una pluralidad de secuencias de operación", para el cual se obtuvo la patente US2870278A . Conocemos este dispositivo como el "giro" de la lavadora. El giro arquitectónico se da al comienzo del artículo.
La variabilidad del enfoque se manifiesta en el hecho de que con esta arquitectura puede elegir cualquiera de los cuatro modos , pasando el cual no realizará acciones innecesarias.
Al iniciar la lavadora, puede seleccionar el modo: lavado, enjuague o centrifugado. Si elige lavar, su máquina aún enjuagará la ropa y luego la exprimirá. Con el enjuague en el kit, seguramente obtendrá un giro. Spin - la acción final en el proceso de lavado, es la más "simple". En nuestra arquitectura, la acción más simple es la representación , y comenzaremos con ella.
Representación
Si hablamos de una presentación pura sin recurrir a una base de datos o una fuente externa, entonces damos información estática: una página html, un archivo, un directorio en forma de json. Incluso podemos dar solo la respuesta del Código - 200:
Escribamos el "Comprobador de salud" más simple
module Health class Endpoints < Sinatra::Base get '/check' do; end end end
En su forma más primitiva, nuestro esquema se verá así:

Digresión líricaLe pido que tenga en cuenta que en el marco de Sinatra, la clase Endpoints combina el enrutador y el controlador en una clase. ¿Esto viola el principio de responsabilidad exclusiva? De hecho, Endpoints no es una clase, sino una capa expresada a través de una clase, y su área de responsabilidad en un nivel superior.
Ok, ¿qué pasa con el enrutador y el controlador ? No están representados por un conjunto de clases, sino por el nombre y la implementación de una función. Un archivo estático es generalmente un archivo. Una clase es responsable de una responsabilidad, pero no intente expresar cada responsabilidad a través de una clase. Use practicidad, no dogmatismo.
Trabajar con sistema de almacenamiento
Las empresas exigen la disponibilidad de su aplicación. ¿Por qué alguien necesitaría su servicio si no podemos usarlo en el momento adecuado? Para garantizar la integridad de los datos, registramos un cambio en el estado de un objeto comercial después de cada procesamiento.
Para recuperar un objeto del almacenamiento no se requiere acceso a la lógica empresarial. Imagine que automatizamos las actividades de una cadena de hoteles y tenemos una revista para invitados en la recepción. Decidimos ver información sobre el visitante.
module Reception class Endpoints < Sinatra::Base
Trabaje con el sistema de almacenamiento en forma de diagrama gráfico:

Como podemos ver, la comunicación entre la capa responsable del almacenamiento y la capa responsable de la presentación de datos se implementa a través del modelo de respuesta. Este modelo no pertenece a ninguna de estas capas. De hecho, este es un objeto comercial y está ubicado en la capa responsable de la lógica comercial.
Procesamiento
Si se trata del hecho de que el modelo de objetos cambia en función de sus propiedades sin introducir datos nuevos, recurrimos directamente a la capa de interacción . La capa de interacción es la clave en nuestra aplicación, describe toda la lógica empresarial en forma de casos de uso separados, y es en ella donde cambian las entidades .
Considere este caso de uso. El visitante ya está registrado en nuestro hotel, pero celebramos su llegada o salida.
module Reception class Endpoints < Sinatra::Base
Paremos un poco. ¿Por qué no hacer que la implementación sea un método único con el parámetro de status
? Los interactores de Arrival
y Departure
son fundamentalmente diferentes. Si un invitado viene a nosotros, entonces debemos verificar si la limpieza ha terminado, si ha habido nuevos mensajes para él, etc. Con su partida, por el contrario, debemos iniciar la limpieza si es necesario. A su vez, ni siquiera recordamos los mensajes, porque si él hubiera estado en el hotel, lo habríamos llamado de inmediato. Es toda esta lógica de negocios que prescribimos en la capa de Interactor .

Pero, ¿qué debemos hacer si tenemos datos del exterior? Aquí la acción de Data Collection está conectada.
Recolectando datos
Durante el registro inicial de un huésped en el hotel, completa el formulario de registro. Este formulario está siendo verificado. Si los datos son correctos, se lleva a cabo el proceso comercial de registro. El proceso devuelve datos: el modelo de negocio "inquilino" creado. Presentamos este modelo al invitado en forma legible:
module Reception class Endpoints < Sinatra::Base
Esquemáticamente, se ve así:

Reglas del juego (Reglas)
- El sistema variativo desde el punto de vista de los procesos se divide en Acciones .
- La secuencia de acciones está determinada por el modo .
- Los modos son incrementales.
- Un modo más "complejo" complementa uno más "simple" para una acción estrictamente.
- Cada acción tiene lugar en el marco de una capa .
- Cada capa está representada por una clase .
- Dentro de una capa, puede haber clases de capa y clases de responsabilidad .
- La comunicación se lleva a cabo solo entre la capa y la clase de capa intermedia .
- Los modelos de representación son excepciones.
- El manejo de errores debe tener lugar en el nivel de capa de clase .

Esquema general
Este enfoque tiene un umbral de entrada alto. Su aplicación requiere una gran experiencia del diseñador para una comprensión clara de las tareas a resolver. La complejidad también representa la variedad de opciones de la herramienta requerida. Pero, a pesar de la complejidad de la estructura, la implementación a nivel de código es increíblemente simple y expresiva. Aunque contiene una serie de convenciones y poderes notariales. En el futuro, analizaremos cada plantilla de diseño individualmente, describiremos cómo crearla, probarla y designar el alcance. Y para no confundirse en su diversidad, se ofrece un mapa completo:

Mapa de alta resolución