Introducción a Domain Driven Design (DDD)

Hace poco andaba de visita en el centro de formación de la comunidad Skills Matter. En la pared había pegados varios carteles con el reclamo «Fast path to DDD». La verdad es que me sorprende que no lo bautizaran D³, pero, al tema: DDD es el acrónimo de Domain Driven Design, una metodología relativamente nueva para el diseño de sistemas de información. Como en otros posts sobre programación, voy a intentar mantenerme alejado de los detalles técnicos. Ni siquiera voy explicar ordenadamente lo que es DDD, voy a compartir parte de mi experiencia que se intersecta con DDD en algunos puntos. A quien le interese una explicación formal el libro más popular es el de Eric Evans.

A mi juicio, la idea más útil de DDD es que es una mala idea construir un modelo de datos único que almacene todos los datos de la empresa. Se supone que la duplicidad de datos es mala. Entonces, tener el dato en un único sitio una sola vez será bueno ¿no? Pues resulta ser que no.

Empecemos razonando por analogía. Cuando se diseña una base de datos, al principio, se normaliza todo el modelo. Normalizar, para que nos entendamos fácilmente, consiste en que en lugar de repetir la provincia «Madrid» 500.000 veces a los largo y ancho de toda la base de datos, le asignamos un código, digamos 28, y creamos una tabla llamada «provincias» que asocia cada código numérico con una provincia. Cuando ya lo tenemos todo normalizado nos damos cuenta de que para imprimir cualquier dirección hay que leer al menos de dos tablas, la tabla «direcciones», que sólo contiene el código de provincia (28) y la tabla «provincias» que asocia el código con el nombre de la provincia. Entonces pensamos que podría ser una buena idea desnormalizar el modelo y guardar el nombre de la provincia directamente en la tabla de direcciones (a fin de cuentas los nombres de las provincias no cambian tan frecuentemente) eso ocupará más espacio a cambio de reducir el número de lecturas necesarias para cada operación.

Para ver cómo se traslada el equivalente a la desnormalización en DDD pondré un ejemplo con CRM, no porque DDD sea específico de CRM para nada, sino solo porque es lo que mejor conozco. Todas las empresas quieren tener la información de un cliente en un único sitio. Se supone que el sistema debe servir para que la empresa mantenga una conversación consistente, fluida y constante con el cliente independientemente de los canales e interlocutores. Por ello tener la información del cliente dispersa en cincuenta sitios parece, a priori, algo muy poco deseable. Por consiguiente, a alguien se le ocurre diseñar un repositorio centralizado con toda la información de todos los clientes, y como consecuencia de esa decisión es prácticamente seguro que el CRM de la empresa fracasará. La razón es que un cliente tiene demasiadas facetas diferentes como para que se pueda incluir toda su información de forma práctica en un único modelo. Antes de haber comprado nada los clientes son prospectos. Puede haber muchísimos más prospectos que clientes en una base de datos, quizá un ratio de 100 a 1. El diseño ingenuo del sistema es poner un campo «tipo de cliente» que indica en la tabla si el registro es prospecto o es cliente, aunque también podría ser ex-cliente, o incluso haber fallecido. Esto obliga a los usuarios a filtrar todas sus consultas por tipo de cliente. En los informes pueden salir cosas muy raras. En un acercamiento DDD habría dos Contextos Acotados, el contexto de prospección comercial y el contexto de gestión de clientes reales con un procedimiento de conversión del prospecto en cliente. Esto permitirá a los comerciales introducir tanta información sobre los prospectos como necesiten sin perturbar al personal administrativo con detalles irrelevantes para la operativa diaria con gente que ya está comprando cosas regularmente. Cuando el diseño de un sistema falla en mantener la separación entre los Contextos Acotados se convierte en lo que Foote y Yoder describieron en 1999 como un Big Ball of Mud.

Los contextos acotados no tienen porqué modelizar sólo área funcionales, sino que pueden estar creados por razones puramente técnicas. El mejor ejemplo de ello son los datawarehouse donde se almacena la misma información que el contexto transaccional pero con una disposición de datos que es mucho mejor para elaborar informes.

Otra propuesta de DDD es entablar conversaciones con los usuarios para definir un Lenguaje Ubícuo. En el ejemplo anterior el usuario puede decir: «quiero convertir a un prospecto en cliente cuando se cierre una venta». Esa petición así planteada es tan vaga que el programador no puede hacer nada práctico con ella. Pero es el punto de partida para definir con precisión lo que es un prospecto, lo que es un cliente y cuándo y cómo se convierte uno en el otro. DDD pone mucho énfasis en que los programadores aprendan e implementen el Lenguaje Ubícuo con las definiciones y terminología exactamante como las usa el cliente. Cada Contexto Acotado puede tener su propio Lenguaje Ubícuo, o, dicho de otra forma, la misma cosa (o muy parecida) se puede llamar de manera diferente en un contexto que en otro.

Los procesos cuyo flujo de trabajo requiera más de un contexto acotado deben implementarse como Servicios. Un peligro del patrón de diseño Modelo-Vista-Controlador (MVC) es que en sí mismo es insuficiente para dotar a un sistema grande de la arquitectura apropiada. El motivo es que aunque un controlador puede utilizar varios modelos con frecuencia existen procesos comunes a varios controladores. En nuestro ejemplo de CRM, puede que la conversión de prospecto en cliente la haga un usuario desde una aplicación web, pero también podría ser que la conversión se efectuase automáticamente tras recibir una señal de una web externa. Por consiguiente la conversión de prospecto en cliente debe ser un servicio invocable desde cualquier parte y no sólo desde la capa del controlador de la aplicación web. Los servicios, además sirven para colocar en ellos las Reglas Anticorrupción. El servicio garantiza la coherencia de datos y también desacopla el interfaz de alto nivel del SQL o de los mapeadores objeto-relacional (ORM).

Un servicio esencial cuando se tienen contextos acotados es el de comprobación de consistencia y consolidación de datos. No importa lo fiable que parezca el mecanismo de sincronización entre contexto, en algún momento siempre se produce un desajuste entre ellos, y, sin un servicio para restaurar la consistencia de datos la operación diaria del sistema se convierte en un verdadero infierno.

Si es posible mantener todos los contextos dentro de la misma base de datos a mi me gusta mantener la sincronización con disparadores (triggers) y procedimientos almacenados en el SGBDR. Antes se escribía mucho PL/SQL. Los programadores más jovenes tienen tendencia a escribir menos, porque es menos sexy que los modernos lenguajes de programación y el código no es portable entre distintas bases de datos, pero para mover datos de una tabla a otra lo más eficiente sigue siendo el código que se ejecuta 100% dentro del SGBDR sin generar tráfico de red.

No me voy a extender más sobre DDD, espero haber dado las pinceladas necesarias para ilustrar sin llegar a aburrir. El lector interesado puede empezar a encontrar recursos en DDD Community.

Compartir:
  • Twitter
  • Meneame
  • Facebook
  • Google Bookmarks
Esta entrada fue publicada en Organizando la Comunidad. Modelos de Desarrollo. Guarda el enlace permanente.

2 respuestas a Introducción a Domain Driven Design (DDD)

  1. Pingback: Velocidad de programación, tutoriales y podcasts, Pull Request #7 - Webeando - Tecnología y Periodismo digital

  2. Pingback: Microservicios | La Pastilla Roja

Los comentarios están cerrados.