Introducción a Domain Driven Design (DDD): Parte 2
Carlos Morera de la Chica

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.

Referencias

Eric Evans – Domain-driven design

Quizá también te interese…

Cómo modularizar una Aplicación Android

Cómo modularizar una Aplicación Android

Cómo modularizar una aplicación Android En este artículo, vamos a hablar sobre la modularización de aplicaciones Android. La modularización es un proceso que consiste en dividir una aplicación en varios módulos, para facilitar su mantenimiento y escalabilidad. La...

Las reglas FIRST de los tests

Las reglas FIRST de los tests

Las reglas FIRST son un conjunto de principios que se utilizan para diseñar y escribir tests de software de manera efectiva. Las siglas FIRST significan: F - Fast: Un test debe ser rápido de ejecutar. I - Independent: Un test debe ser independiente de otros tests y...

¿Qué son los dobles de test?

¿Qué son los dobles de test?

Los dobles de prueba (también conocidos como "doubles" o "fakes") son herramientas comunes en la programación y en particular en el testing de software. Se utilizan para simular el comportamiento de una dependencia de una aplicación en un entorno de pruebas, sin tener...

13 Comentarios

  1. Carlos Morera de la Chica

    Hola Antonio. Tengo pendiente hacer una tercera parte y como dices un ejemplo de código creo que sería muy útil. Saludos

    Responder
    • Mati Beltramone

      Esta la tercera parte? Se agradece Saludos!

      Responder
  2. Jhon Alex Yovera Ramos

    Muy bueno … sería excelente si realizas un ejemplo en java

    Responder
  3. Manuel Calero Solis

    No vale para nada si ejemplos, no me gustó nada.

    Responder
    • Fernando

      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.

      Responder
  4. DevexPoser

    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.

    Responder
  5. Juan Esteban Castaño Rincón

    Buenos días, excelentes artículos muchas gracias por compartir, pregunta: tienes algún ejemplo de implementacion? Saludos

    Responder
  6. Alexis

    creo que te falto hablar sobre aggregate root ( es un concepto importante a mi entender en DDD)

    Responder
  7. YekMX

    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?

    Responder
  8. YekMX

    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?

    Responder

Enviar un comentario

Los datos personales que proporciones a través de este formulario quedarán registrados en un fichero de DevExpert, S.L.U., con el fin de gestionar los comentarios que realizas en este blog. La legitimación se realiza a través del consentimiento de la parte interesada. Si no se acepta, no podrás comentar en este blog. Los datos que proporciona solo se utilizan para evitar el correo no deseado y no se usarán para nada más. Puede ejercer los derechos de acceso, rectificación, cancelación y oposición en contacto@devexperto.com.

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Acepto la política de privacidad *