DDD Diseño Guiado por Dominios, Conceptos clave
Arquitectura de Software

Conceptos Clave del Domain Driven Design
Continuando con nuestra introducción al Domain Driven Design (DDD), a continuación describimos sus principales conceptos que se aplican bajo el principio de ubiquidad del lenguaje.
Se debe rcordar que DDD no define implementaciones, define conceptos y ‘reglas de implementación’. Por tanto es independiente de cualquier framework y lenguaje, pero si tiene un enfoque orientado a los microservicios.
Entities
Las entidades son objetos del modelo que se caracterizan por tener identidad en el sistema, los atributos que contienen no son su principal característica. Representan conceptos con una identidad que se mantienen en el tiempo, y que con frecuencia también se mantienen bajo distintas representaciones de la entidad. Deben poder ser distinguidas de otros objetos aunque tengan los mismos atributos. Tienen que poder ser consideradas iguales a otros objetos aún cuando sus atributos difieren.
Por ejemplo, imaginemos un objeto Persona con nombre y apellidos como atributos de una clase en un sistema donde dos objetos que representan a dos personas diferentes con los mismos nombres y apellidos deberían ser considerados diferentes.
Como vemos, en este caso no podemos describir el objeto persona primariamente por sus atributos, si no que debemos de asignarle una identidad que se mantenga para cualquier representación de esa persona. Si nuestro sistema trabaja únicamente con personas de nacionalidad españolas podríamos considerar como identidad el DNI, en cambio si manejamos personas de cualquier nacionalidad quizás debamos de autogenerar este ID dentro de nuestro sistema (Muchos países no tiene documento nacional de identidad). Cabe destacar que en un sistema, Persona puede ser considerado una entidad, mientras que en otro sistema donde no necesitemos identificar a una persona por su identidad podría no serlo.
La identidad tiene que ser declarada de tal manera que podemos rastrear la entidad de manera eficaz. Los atributos, responsabilidades y relaciones deben ser definidas en relación a la identidad que representa la entidad más que en los atributos que la componen.
Como podemos observar, el hecho de que necesitemos identificar y distinguir distintos objetos a lo largo de su ciclo de vida hace que la complejidad para manejarlos y diseñarlos sea bastante mayor que la de los que no la necesitan. Por este motivo debemos usar entidades únicamente para objetos que realmente lo requieran, lo cual tiene dos ventajas importantes. Por un lado, no incluiremos complejidad innecesaria en objetos que no requieran ser identificados, por otro lado al reducir el número de entidades en el sistema seremos capaces de identificarlas rápidamente.
Value objects
Al contrario que las entidades los value objects representan conceptos que no tienen identidad. Simplemente describen características. Por lo tanto solo nos interesan sus atributos.
Los value object representan elementos del modelo que se describen por el QUÉ son, y no por QUIÉN o CUÁL son.
Pongamos por ejemplo, un objeto Color representado por su composición RGB (Red, Green, Blue). Si tuviéramos dos objetos representando el mismo color podríamos usar cualquiera de ellos, ya que nos interesa qué color es por sus atributos, no por cuál instancia estamos usando. Otros ejemplos de value objects podrían ser String o Integer, ya que no nos importa que ¨C¨ o que ¨3¨ estamos usando. Aunque estos ejemplos son simples los value objects no tienen porque serlo.
Esto conlleva una serie de diferencias a la hora de modelar value objects respecto a las entidades. Los value objects suelen ser modelados como inmutables y son menos complejos de diseñar, ya que podremos usarlos y descartarlos según nos interese, pues no tenemos que preocuparnos por la instancia que estemos utilizando (siempre y cuando sus atributos sean los correctos).
Tanto las entidades como los value objects representan conceptos, por tanto suelen ser nombrados con sustantivos.
Services
Los servicios representan operaciones, acciones o actividades que no pertenecen conceptualmente a ningún objeto de dominio concreto. Los servicios no tienen ni estado propio ni un significado más allá que la acción que los definen.
Al contrario que las entidades y los value objects, los servicios son definidos en términos de lo que pueden hacer por un cliente, y por tanto tienden a ser nombrados como verbos. Los verbos utilizados para nombrar a los servicios deben pertenecer al ubiquitous language, o ser introducidos en el en caso de que aún no lo sean. A la hora de implementarlos tanto sus parámetros como resultados deben ser objetos pertenecientes al dominio.
Un servicio debe de cumplir tres características principales:
- La operación que lo define está relacionada con un concepto de dominio, pero no es natural modelarlo como una entidad o un value object.
- Su interfaz se especifica usando otros elementos del modelo de dominio.
- La operación no tiene estado, por lo que cualquier cliente podría usar cualquier instancia del servicio sin tener en cuenta las operaciones que se han realizado con anterioridad en esa instancia.
Podemos dividir los servicios en tres tipos diferentes según su relación con el núcleo del dominio.
Domain services
Son responsables del comportamiento más específico del dominio, es decir, realizan acciones que no dependen de la aplicación concreta que estemos desarrollando, sino que pertenecen a la parte más interna del dominio y que podrían tener sentido en otras aplicaciones pertenecientes al mismo dominio.Por ejemplo, crear un usuario, actualizar los detalles de un cliente, etc…
Application services
Son responsables del flujo principal de la aplicación, es decir, son los casos de uso de nuestra aplicación. Son la parte visible al exterior del dominio de nuestro sistema, por lo que son el punto de entrada-salida para interactuar con la funcionalidad interna del dominio. Su función es coordinar entidades, value objects, domain services e infrastructure services para llevar a cabo una acción.Por ejemplo, realizar un pago, añadir un producto al carrito de la compra, realizar una transferencia a otra cuenta, etc…
Infrastructure services
Declaran comportamiento que no pertenece realmente al dominio de la aplicación pero que debemos ser capaces de realizar como parte de este. Por ejemplo, enviar un email de confirmación tras realizar un pago, loguear transacciones, etc…
Diferentes aplicaciones tienen diferentes niveles de complejidad en sus dominios y eso puede hacer que diferenciar entre domain y application services no sea siempre trivial. Como idea general podríamos considerar que, si después de recibir una orden el sistema este necesita realizar varios pasos, la coordinación de dichos pasos se realizaría en un application service. Si por otro lado, recibimos una orden simple que está relacionada con un concepto de dominio este comportamiento probablemente deba de ser modelado como un domain service.
Para aclarar la diferencia entre los diferentes servicios y sus responsabilidades pongamos el ejemplo de un application service que dados unos productos en el carrito de la compra realiza el pago. Vamos a nombrar nuestro application service como MakePaymentService.
MakePaymentService tendrá que validar el usuario, aplicar descuentos, verificar que tenemos los productos disponibles stock, realizar una llamada a un servicio de pago externo, notificar al servicio de paquetería para el envío, enviar un email de confirmación al usuario, etc…
La responsabilidad de MakePaymentService es la coordinación del flujo para realizar un pago. Por otro lado, para realizar la acción de validar el usuario utilizariamos un ValidateUserService que sería un domain service y que tendría la responsabilidad de validar que el usuario es válido, ya que a priori es una orden simple que está relacionada con un concepto de dominio. En cambio, para la acción de enviar un email de confirmación al usuario, utilizariamos SendEmailService que en este caso sería un infrastructure service, ya que es una acción que nuestro dominio debe ser capaz de realizar pero que no pertenece al mismo. Por tanto, sería especificado en nuestro dominio como una interface (en el caso de Java), que como veremos a continuación sería implementada dentro de otra capa de nuestro sistema (infrastructure).
Layered architecture
Un sistema software está compuesto por muchas partes, de las cuales, la parte que resuelve problemas para el dominio es una porción pequeña, aunque su importancia es desproporcionada a su tamaño.
Para ser capaces de trabajar con el dominio sin perdernos en otros detalles presentes en el software necesitamos desacoplar los objetos de dominio de otras funciones del sistema. Tendremos que aislar nuestro dominio del resto del sistema para asi evitar confundir conceptos pertenecientes al dominio con conceptos que solo están relacionado con la tecnología utilizada.
Podemos utilizar cualquiera de las muchas arquitecturas que existen para aislar las distintas partes del sistema, pero la opción que elijamos debería dividir nuestro sistema en al menos cuatro capas: presentación, aplicación, dominio e infraestructura.
Presentation
Capa responsable de mostrar la información al usuario e interpretar los eventos de entrada del usuario. Cabe destacar que el usuario puede ser un ser humano u otro sistema que se comunica con el nuestro.
Application
Capa que declara las funcionalidades que el software tiene que llevar a cabo y orquesta los objetos de dominio para resolver los distintos problemas. Esta capa no contiene reglas de negocio o conocimiento, solamente coordina y delega el trabajo a la colaboración de los objetos de dominio que se encuentran en la la siguiente capa.
Domain
Capa donde se encuentran los conceptos del dominio y las reglas de negocio. Es la capa más importante del sistema y es la que realmente aporta valor y resuelve los problemas para los que un determinado software es creado.
Infrastructure
Capa que provee las implementaciones que apoyan a las capas definidas anteriormente. Aquí se encapsulan la mayoría de las decisiones tecnológicas adoptadas para un sistema, por ejemplo: el envío del email de confirmación tras un pago, persistencia para el dominio, comunicación con otros sistemas, etc…
Artículos relacionados
Descubre los cientos de artículos en nuestro blog