En el anterior post, Introducción a Domain Driven Design (DDD) parte 1 discutimos uno de los conceptos más importantes en domain-driven design, el Ubiquitous language. También empezamos a describir algunos de los elementos básicos para modelar el dominio del software como son las Entities y los Value Objects. En este post vamos a definir qué son y qué tipos de services existen, y terminaremos describiendo como aislar la capa de dominio del resto del sistema.
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… (Si estás familiarizado con “Clean Architecture” los application services serían equivalentes a los “Interactors”)
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…
Conclusión
El proceso obtención de conocimiento y de construcción de software es complejo y tedioso. Es un proceso iterativo, en el cual iremos descubriendo nuevos conceptos y abstracciones que tendremos que plasmar en el código y en el lenguaje utilizado para comunicarnos.
En muchas ocasiones descubriremos como un conocimiento más profundo del dominio y su inclusión en la base código harán que partes del sistema que a priori parecían complejas o en las cuales teníamos dificultades para modelar o diseñar se vuelvan triviales. Dando paso a la creación de software expresivo, semántico, fácil de entender, manejar y modificar.
Show me your code example!!
Hola Antonio. Tengo pendiente hacer una tercera parte y como dices un ejemplo de código creo que sería muy útil. Saludos
Esta la tercera parte? Se agradece Saludos!
Excelente explicación 🙂
Muy bueno … sería excelente si realizas un ejemplo en java
No vale para nada si ejemplos, no me gustó nada.
El típico copypastero que si no ve código con lo que el necesita exactamente no entiende nada. Esta todo muy bien explicado, y con esos conceptos es fácil bajar todo a código.
Todos sabemos buscar en la wikipedia. No aporta nada a parte de desconocimiento, ampliar deficiones o demostrar utilidad nos daría entender que sabéis de lo que se habla. Pero estáis resumiendo definiciones con más ambigüedades.
Buenos días, excelentes artículos muchas gracias por compartir, pregunta: tienes algún ejemplo de implementacion? Saludos
el ejemplo lo tienen en http://dddsample.sourceforge.net
incluso hay código bajo EE7
creo que te falto hablar sobre aggregate root ( es un concepto importante a mi entender en DDD)
Hola, desde tu vision del DDD, si tengo un servicio de dominio ‘Crear usuario’, tambien deberia tener en un servicio de aplicacion crear usuario? para que la interfaz de usuario no consuma directamente el dominio, si es asi entonces los repositorios deben tambien ser invocados desde un servicio o directamente desde la interfaz?
Hola, unas dudas me surgieron al leer tu vision de DDD,
1. ¿Los repositorios (CRUD) de usuarios, productos, paises, etc, etc deben de estar en un servicio de aplicacion que asu vez llame al repositorio del dominio o que llamen a otro servicio de dominio?
2. ¿La funcionalidad de Login o cambiar password deben estar en un servicio de aplicacion que asu vez orqueste los repositorios a usar o en un servicio de aplicacion alomejor llamado Seguridad y que as u vez llame a un servicio de dominio llamado tambien Seguridad?
3.- ¿Quien orquesta las transacciones (UoW) desde la Capa de aplicacion o desde la capa del dominio?