Mostrando entradas con la etiqueta DDD. Mostrar todas las entradas
Mostrando entradas con la etiqueta DDD. Mostrar todas las entradas

DSN_XP y Diseño guiado por el Dominio

 Domain Driver Design

DSN_XP entra en contacto con este marco de trabajo para diseño de software que considera un concepto que nos impactó mucho y se trata de la noción de DOMINIO y la presencia de "objetos del negocio" existentes dentro de un lenguaje organizacional tanto transversalmente como verticalmente, capacidad de información que  la denominaron como "lenguaje ubicuo".

Dan Haywood, Haywood Associates Ltd

Introducción al diseño basado en dominios

Las aplicaciones empresariales de hoy son sin duda sofisticadas, dependen de algunas tecnologías especializadas (persistencia, AJAX, servicios web, etc.) para hacer lo que hacen. 
Como desarrolladores, es comprensible que tendamos a centrarnos en estos detalles técnicos. Pero la verdad es que un sistema que no resuelve las necesidades comerciales..., no le sirve a nadie, sin importar lo bonito que se vea o lo bien que esté diseñada su infraestructura.

Filosofía de diseño DDD

La filosofía del diseño impulsado por dominios (DDD), descrita por primera vez por Eric Evans en su libro [1] del mismo nombre, consiste en colocar nuestra atención en el corazón de la aplicación, centrándose en la complejidad intrínseca del dominio empresarial. sí mismo. También distinguimos el dominio central (exclusivo de la empresa) de los subdominios de soporte (generalmente de naturaleza genérica, como dinero o tiempo) y colocamos apropiadamente más de nuestros esfuerzos de diseño en el núcleo.

El diseño dirigido por dominios consta de un conjunto de patrones para crear aplicaciones empresariales a partir del modelo de dominio. En su carrera de software, es posible que ya se haya encontrado con muchas de estas ideas, especialmente si es un desarrollador experimentado en un lenguaje OO. Pero aplicarlos juntos le permitirá crear sistemas que realmente satisfagan las necesidades de la empresa.

En este artículo voy a repasar algunos de los patrones principales de DDD, recoger algunas áreas donde los novatos parecen tener dificultades y destacar algunas herramientas y recursos (uno en particular) para ayudarlo a aplicar DDD en su trabajo.

De código y modelos

Con DDD buscamos crear modelos de un dominio de problemas. La persistencia, las interfaces de usuario y la mensajería pueden llegar más tarde, es el dominio lo que debe entenderse, porque esa es la parte del sistema que se está construyendo que distingue el negocio de su empresa de sus competidores. (Y si eso no es cierto, considere comprar un producto empaquetado).
Por modelo no nos referimos a un diagrama o conjunto de diagramas; Claro, los diagramas son útiles pero no son el modelo, solo diferentes vistas del modelo (ver Figura). No, el modelo es el conjunto de conceptos que seleccionamos para ser implementados con el software, representados en código y cualquier otro artefacto de software utilizado para construir el sistema entregado. 
En otras palabras, el código es el modelo

Los editores de texto proporcionan una forma de trabajar con este modelo, aunque las herramientas modernas también proporcionan muchas otras visualizaciones (diagramas de clases UML, diagramas entidad-relación, Spring beandocs [2], flujos Struts / JSF, etc.).

Modelo frente a perspectivas del modelo

Diseño basado en modelos

Este es el primero de los patrones DDD: un diseño basado en modelos . Significa poder mapear, idealmente de manera bastante literal, los conceptos del modelo con los del diseño / código. Un cambio en el modelo implica un cambio en el código; cambiar el código significa que el modelo ha cambiado. 

DDD no exige que se modele el dominio utilizando la orientación a objetos; podríamos construir modelos utilizando un motor de reglas, por ejemplo, pero dado que los lenguajes de programación empresarial dominantes están basados ​​en OO, la mayoría de los modelos serán de naturaleza OO. Después de todo, OO se basa en un paradigma de modelado
Los conceptos del modelo se representarán como clases e interfaces, las responsabilidades como miembros de la clase.

Hablar el idioma

Veamos ahora otro principio fundamental del diseño impulsado por dominios. En resumen: queremos construir un modelo de dominio que capture el dominio del problema del sistema que se está construyendo y vamos a expresar esa comprensión en artefactos de código / software
Para ayudarnos a hacer eso, DDD aboga por que los expertos en el dominio y los desarrolladores se comuniquen conscientemente utilizando los conceptos dentro del modelo. Por lo tanto, los expertos en dominios no describen una nueva historia de usuario en términos de un campo en una pantalla o un elemento de menú, sino que hablan sobre la propiedad o el comportamiento subyacente que se requiere en un objeto de dominio. De manera similar, los desarrolladores no hablan de nuevas variables de instancia de una clase o columnas en una tabla de base de datos.
Haciendo esto de forma rigurosa conseguimos desarrollar un lenguaje ubicuo. Si una idea no se puede expresar fácilmente, indica un concepto que falta en el modelo de dominio y el equipo trabaja en conjunto para descubrir cuál es ese concepto que falta. Una vez que esto se ha establecido, el nuevo campo en la pantalla o columna en la tabla de la base de datos sigue a eso.

Como gran parte de DDD, esta idea de desarrollar un lenguaje ubicuo no es realmente una idea nueva: los XPers lo llaman un "sistema de nombres" y los DBA durante años han elaborado diccionarios de datos
Pero el lenguaje ubicuo es un término evocador y algo que se puede vender tanto a los empresarios como a los técnicos. También tiene mucho sentido ahora que las prácticas ágiles de "todo el equipo" se están generalizando.

Modelos y contextos

Siempre que hablamos de un modelo, siempre está dentro de algún contexto. Este contexto generalmente se puede inferir del conjunto de usuarios finales que utilizan el sistema. Por lo tanto, tenemos un sistema comercial de atención al público implementado para los comerciantes o un sistema de punto de venta utilizado por los cajeros en un supermercado. Estos usuarios se relacionan con los conceptos del modelo de una manera particular y la terminología del modelo tiene sentido para estos usuarios, pero no necesariamente para cualquier otra persona fuera de ese contexto. 
DDD llama a esto el contexto acotado (BC) . Cada modelo de dominio vive precisamente en un BC, y un BC contiene precisamente un modelo de dominio.

Debo admitir que cuando leí por primera vez sobre los BC no entendí el sentido: si los BC son isomórficos a los modelos de dominio, ¿por qué introducir un nuevo término? Si solo los usuarios finales interactuaran con los BC, entonces quizás no habría necesidad de utilizar este término. Sin embargo, diferentes sistemas (BC) también interactúan entre sí, enviando archivos, pasando mensajes, invocando API, etc. Si sabemos que hay dos BC interactuando entre sí, entonces sabemos que debemos tener cuidado de traducir entre los conceptos en un dominio y los del otro.

Poner un límite explícito alrededor de un modelo también significa que podemos comenzar a discutir las relaciones entre estos CB. De hecho, DDD identifica un conjunto completo de relaciones entre BC, de modo que podamos racionalizar lo que debemos hacer cuando necesitamos vincular nuestros diferentes BC juntos:

Lenguaje publicado 

Los BC que interactúan acuerdan un lenguaje común (por ejemplo, un grupo de esquemas XML sobre un bus de servicio empresarial) mediante el cual pueden interactuar entre sí;

Servicio de host abierto 

Un BC especifica un protocolo (por ejemplo, un servicio web RESTful) mediante el cual cualquier otro BC puede utilizar sus servicios;

Kernel compartido 

Dos BC usan un kernel común de código (por ejemplo, una biblioteca) como una lengua franca común, pero por lo demás hacen sus otras cosas de una manera específica;

Cliente / proveedor 

Un BC utiliza los servicios de otro y es un interesado (cliente) de ese otro BC. Como tal, puede influir en los servicios prestados por ese BC;

Conformista 

Un BC utiliza los servicios de otro pero no es un interesado de ese otro BC. Como tal, utiliza "tal cual" (se ajusta a) los protocolos o API proporcionados por ese BC;

Capa anticorrupción 

Un BC utiliza los servicios de otro y no es un interesado, pero tiene como objetivo minimizar el impacto de los cambios en el BC del que depende mediante la introducción de un conjunto de adaptadores: una capa anticorrupción.

A medida que avanzamos en esta lista, puede verse que el nivel de cooperación entre los dos CB se reduce gradualmente (consulte la Figura 2). Con un lenguaje publicado partimos de los BC que establecen un estándar común mediante el cual pueden interactuar; ninguno de los dos posee este idioma, sino que es propiedad de la empresa en la que residen (incluso podría ser un estándar de la industria). Con el host abierto todavía lo estamos haciendo bastante bien; el BC proporciona su funcionalidad como un servicio en tiempo de ejecución para que cualquier otro BC lo invoque, pero (presumiblemente) mantendrá la compatibilidad con versiones anteriores a medida que el servicio evolucione.

Espectro de relaciones contextuales limitadas

Sin embargo, para cuando nos volvemos conformistas, simplemente estamos viviendo con nuestra suerte; un BC está claramente subordinado al otro. Si tuviéramos que integrarnos con el sistema de contabilidad general, comprado por ACME, esa podría ser la situación en la que viviríamos. 

Y si usamos una capa anticorrupción, generalmente nos estamos integrando con un sistema heredado, pero introducimos un capa extra para aislarnos lo mejor que podamos de ella. Eso cuesta dinero para implementar, por supuesto, pero reduce el riesgo de dependencia. Una capa anticorrupción también es mucho más barata que volver a implementar ese sistema heredado, algo que, en el mejor de los casos, distraería nuestra atención del dominio central y, en el peor, terminaría en falla.

DDD sugiere que elaboremos un mapa de contexto para identificar nuestros CB y aquellos de los que dependemos o dependemos, identificando la naturaleza de estas dependencias. La Figura 3 muestra un mapa de contexto de este tipo para un sistema en el que he estado trabajando durante los últimos 5 años más o menos.

Ejemplo de un mapeo de contexto

Toda esta charla sobre mapas de contexto y BC a veces se denomina DDD estratégico y por una buena razón. Después de todo, averiguar la relación entre los BC es bastante político cuando lo piensas: ¿de qué sistemas ascendentes dependerá mi sistema, es fácil para mí integrarme con ellos, tengo influencia sobre ellos, confío en ellos? Y lo mismo es válido en sentido descendente: ¿Qué sistemas utilizarán mis servicios, cómo expongo mi funcionalidad como servicios, tendrán influencia sobre mí?

No entender esto y su aplicación fácilmente podría ser un fracaso.

Capas y hexágonos

Vayamos ahora hacia adentro y consideremos la arquitectura de nuestro propio BC (sistema). Básicamente, DDD solo está realmente preocupado por la capa de dominio y, en realidad, no tiene mucho que decir sobre las otras capas: presentación, aplicación o infraestructura (o capa de persistencia). Pero sí espera que existan. Este es el patrón de arquitectura en capas (Figura 4).

Arquitectura en capas

Hemos estado construyendo sistemas multicapa durante años, por supuesto, pero eso no significa que seamos necesariamente tan buenos en eso. De hecho, algunas de las tecnologías dominantes del pasado, sí, EJB 2, ¡te estoy mirando! - han sido positivamente perjudiciales para la idea de que un modelo de dominio puede existir como una capa significativa. 
Toda la lógica empresarial parece filtrarse en la capa de aplicación o (peor aún) en la capa de presentación, dejando un conjunto de clases de dominio anémicas [3] como una cáscara vacía de contenedores de datos. De esto no se trata DDD.
Entonces, para ser absolutamente claro, no debería haber ninguna lógica de dominio en la capa de aplicación. En cambio, la capa de aplicación asume la responsabilidad de aspectos como la gestión de transacciones y la seguridad. En algunas arquitecturas, también puede asumir la responsabilidad de garantizar que los objetos de dominio recuperados de la capa de infraestructura / persistencia se inicialicen correctamente antes de interactuar con ellos (aunque prefiero que la capa de infraestructura haga esto en su lugar).
Cuando la capa de presentación se ejecuta en un espacio de memoria separado, la capa de aplicación también actúa como mediador entre la capa de presentación y la capa de dominio. 
La capa de presentación generalmente se ocupa de representaciones serializables de un objeto de dominio o de objetos de dominio (objetos de transferencia de datos o DTO), generalmente uno por "vista". Si se modifican, la capa de presentación devuelve los cambios a la capa de aplicación, que a su vez determina los objetos de dominio que se han modificado, los carga desde la capa de persistencia y luego reenvía los cambios a esos objetos de dominio.

Una desventaja de la arquitectura en capas es que sugiere un apilamiento lineal de dependencias, desde la capa de presentación hasta la capa de infraestructura. Sin embargo, es posible que queramos admitir diferentes implementaciones tanto en la capa de presentación como en la de infraestructura. Ese es ciertamente el caso si (¡como supongo que sí!) Queremos probar nuestra aplicación:
  • por ejemplo, herramientas como FitNesse [4] nos permiten verificar el comportamiento de nuestro sistema desde la perspectiva del usuario final. Pero estas herramientas generalmente no pasan por la capa de presentación, sino que van directamente a la siguiente capa, la capa de aplicación. Entonces, en cierto sentido, FitNesse actúa como un visor alternativo.
  • de manera similar, es posible que tengamos más de una implementación de persistencia. Nuestra implementación de producción probablemente usa RDBMS o tecnología similar, pero para las pruebas y la creación de prototipos podemos tener una implementación liviana (quizás incluso en memoria) para que podamos simular la persistencia.
También podríamos querer distinguir entre las interacciones entre las capas que son "internas" y "externas", donde por interno me refiero a una interacción en la que ambas capas están completamente dentro de nuestro sistema (o BC), mientras que una interacción externa atraviesa los BC.

Entonces, en lugar de considerar nuestra aplicación como un conjunto de capas, una alternativa es verla como un hexágono [5], como se muestra en la Figura 5. Los visores utilizados por nuestros usuarios finales, así como las pruebas de FitNesse, utilizan un cliente interno API (o puerto), mientras que las llamadas procedentes de otros BC (por ejemplo, RESTful para una interacción de host abierta, o una invocación de un adaptador ESB para una interacción de lenguaje publicado) llegan a un puerto de cliente externo. Para la capa de infraestructura de back-end, podemos ver un puerto de persistencia para implementaciones de almacenamiento de objetos alternativos y, además, los objetos en nuestra capa de dominio pueden llamar a otros BC a través de un puerto de servicios externos.