Vamos a comenzar un pequeño proyecto para aprender y profundizar en Domain Driven Design.
En este blog suelo tratar todo tipo de temas relacionados con desarrollo de software. Hasta ahora me he interesado especialmente por el testing y el refactoring, tocando algunos aspectos de buenas prácticas en el camino. Dado que he ido abordando temas sueltos según mis intereses en cada momento no puedo decir que exista una unidad, aunque, con el tiempo, hayan ido surgiendo oportunidades de agruparlos, por ejemplo en los libros que hemos publicado.
Ahora quiero profundizar en Domain Driven Design, pero de una forma un poco más sistemática. Es el tema que ha empezado a estar más presente en mi cabeza en los últimos tiempos. A eso hay que unir la demanda, que algunas personas me han comentado, de mostrar una visión aplicada de los distintos temas en proyectos concretos. Así que, esto es lo que me propongo:
- Entender el Domain Driven Design
- Conocer las herramientas de diseño e implementación que nos proporciona para el desarrollo de software
- Explorar las relaciones de DDD con otras metodologías y paradigmas, como la arquitectura hexagonal, BDD, patrones de diseño, etc.
- Aplicar este conocimiento en un proyecto práctico real
Mis materiales de referencia serán fundamentalmente:
- Domain Driven Design, el libro original de Eric Evans.
- Implementing DDD y DDD Distilled, los dos libros de Vaughn Vernon
- DDD in PHP, el libro de Carlos Buenosvinos, Christian Soronellas y Keyvan Akbary.
- Diversos blogs y libros de otros autores.
El proyecto práctico tendrá que ver con algunos trabajos que realicé en el pasado en mi antiguo sector laboral, el educativo. Así que el objetivo será desarrollar algún ejemplo de aplicación útil para un colegio. Es un dominio en el que tengo experiencia, lo que facilitará toda la parte que tiene que ver, precisamente, con el modelado y su traslación a un sistema de software.
Así que empecemos por lo primero, ¿qué es Domain Driven Design?
Una introducción a DDD
Domain Driven Design es un paradigma de diseño de software que parte del modelado del espacio problema mediante la identificación de conceptos y procesos clave y su representación en un modelo a través de la colaboración entre los así llamados expertos del dominio y los desarrolladores.
DDD comienza con un proceso de knowledge crunching, es decir de adquisición masiva de conocimiento sobre el dominio. Se trata de aprender todo lo posible sobre el problema que vamos a modelar con el objetivo de comprenderlo y, por tanto, poder generar un modelo que lo represente correctamente. Esto se puede hacer principalmente a través de la conversación con los expertos de dominio, pero también con otras técnicas.
Pero, ¿qué es el dominio?
El Dominio
El dominio es el espacio del problema, es aquello de lo que trata el negocio y, por tanto, de lo que tratará la aplicación. Forman parte del dominio los conceptos que se manejan, sus relaciones y los procesos que operan en él. El objetivo del DDD es representar el dominio en un modelo que luego se implementará en forma de software.
Normalmente, no debemos considerar el dominio de una forma genérica, sino que depende del contexto. El modelo del dominio para una empresa específica será distinto del de otra empresa. Obviamente habrá muchísimos elementos comunes, pero también existirán suficientes diferencias como para que no sean intercambiables. Esto no impida que se pueda utilizar el paradigma del Domain Driven Design en desarrollar productos genéricos, pero en ese caso hay que pensar no tanto en el dominio genérico, sino en el de las soluciones de software para ese dominio.
Antes hemos mencionado a los expertos de dominio, que son, ni más ni menos, las personas que trabajan día a día en ese negocio y, por tanto, conocen y manejan los conceptos, los entienden y saben explicar cómo se relacionan. Estas personas utilizan un lenguaje para hablar sobre ellos, nombrarlos, describirlos y accionarlos. El Domain Driven Design requiere que sea este lenguaje el que todos los implicados en el desarrollo utilicen y que se utilice como base para nombrar los modelos y expresarlos en el código. A esto le llamamos Lenguaje Ubicuo porque se pretende que se use y esté presente en todas partes: en las conversaciones sobre el dominio, en la documentación, en los diagramas y en el código. Por así decir, un experto del dominio debería poder observar el código e incluso hacerse una idea de lo que se ha expresado ahí.
Para poder comenzar a modelar el dominio, los desarrolladores tienen que adoptar el lenguaje ubicuo y la mejor manera de hacerlo es a través de la conversación con los expertos de dominio. En esta conversación se irán definiendo, pero también descubriendo, conceptos y procesos. De hecho, el diálogo facilita el aprendizaje por las dos partes. Con frecuencia, esta conversación ayuda a los propios expertos de dominio a descubrir, y solucionar, conceptos representados de forma ambigua o que necesitan un término que los represente de forma precisa.
Por ejemplo, en un sistema de información académica para un colegio será necesario dedicar un tiempo a representar correctamente los muchos conceptos distintos que se manejan al usar la palabra “curso”, como año académico, nivel educativo, grupo de clase, etc.
Una de las formas de afrontar esta conversación consiste en hablar acerca de los llamados Eventos de dominio, a través de una técnica conocida Event Storming. En esencia, consiste en identificar las cosas interesantes que pasan en el dominio y, a partir de ellas, extraer y describir los conceptos que intervienen y cómo se relacionan.
Así, siguiendo con el ejemplo del sistema académico, un evento interesante sería que un alumno recibe una calificación, lo que implica al alumno, la calificación en sí, la actividad sobre la que recibe la calificación, la materia o curso, el periodo de evaluación, etc. Ese evento implica que han sucedido otras cosas anteriores, como que el alumno se ha matriculado en el curso correspondiente, que el profesor ha programado una actividad evaluable y un largo etcétera de acontecimientos y conceptos que están implicados.
En el dominio hay un tema central que lo articula y da sentido: el core domain o núcleo del dominio. Es lo que hace único e irremplazable el negocio, lo que no se puede traspasar o subcontratar.
El core domain de un colegio es el aprendizaje, la formación de los estudiantes, su educación y todo lo que la hace posible. Muchas otras partes de su funcionamiento y estructura son necesarios para dar soporte a ese núcleo central y hacer posible que funcione.
Dentro de un dominio es posible identificar subdominios. Estos están formados por aquellos conceptos y procesos que están estrechamente relacionados entre sí. Los subdominios suelen corresponderse con las divisiones propias de una organización y están relativamente aislados entre sí, pero participan igualmente del dominio.
Los subdominios pueden ser clasificados como de soporte y genéricos. Los subdominios de soporte contribuyen al core domain facilitando que se pueda llevar a cabo. Son necesarios y tienen sentido en relación con el core y en ese sentido son específicos.
Los subdominios genéricos, por su parte, son aspectos que no son centrales del negocio, de hecho son comunes a muchos tipos de negocio, y podrían incluso ser subcontratados o externalizados.
Por tanto, el dominio, estructurado en subdominios, configura el espacio del problema.
Bounded Contexts
El subtítulo del libro fundamental del DDD es “Abordando la complejidad en el corazón del software” y como se desprende del ejemplo anterior, la complejidad de un dominio puede llegar a ser apabullante y es fácil sentirse sobrepasados por ella.
Uno de los primeros pasos para mantener esa complejidad bajo control es identificar los llamados bounded contexts o contextos acotados. Un bounded context es una parte de un dominio en la que viven conceptos y procesos propios, que no participan en otras partes, y en la que los conceptos generales, compartidos entre varios contextos, pueden tener un significado distinto. Los bounded contexts son la representación de los subdominios en el espacio de la solución.
Veámoslo con el ejemplo escolar. El concepto Alumno en un colegio tiene varios significados según el contexto que estemos considerando:
- En el contexto académico adquiere conocimientos, realiza actividades, es evaluado por ellas, estudia una serie de materias, etc.
- En el contexto de secretaría, el alumno se matricula, se da de baja, tiene un expediente, recibe una titulación.
- En el contexto administrativo, los servicios que utiliza tienen un coste, el cual se cobra a través de los correspondientes recibos.
- En el contexto de servicios, puede ser usuario del comedor escolar, de las actividades extraescolares, etc.
Estos diferentes contextos son los que llamamos contextos acotados o bounded contexts. En cada uno de ellos, el concepto alumno lo consideramos con distintas propiedades, formando parte de distintos procesos e incluso tiene un ciclo de vida diferente. Se llaman acotados porque existe una frontera entre ellas, una frontera que podríamos considerar de significado.
La identificación de los bounded contexts es posible mediante diversas estrategias. A veces es fácil porque la propia estructura organizativa ya nos permite discriminar estos contextos: las divisiones de una empresa, por ejemplo, nos están dando una pista acerca de posibles contextos. En nuestro ejemplo escolar, es fácil ver que el departamento de administración y el departamento pedagógico son contextos separados. Sin embargo, la secretaría escolar mantiene muchas relaciones conceptuales con el departamento pedagógico, ¿hasta qué punto son contextos separados?.
Elementos básicos: entidades, value objects y servicios
Para poder responder a esta pregunta tenemos que cambiar un poco de foco.
Hemos dicho que al hablar sobre el dominio identificamos conceptos y procesos. Vamos a ser un poco más precisos:
Algunos de estos conceptos se caracterizan porque conllevan una identidad. El objeto representado (frecuentemente una persona, pero puede ser cualquier cosa) mantiene una individualidad a lo largo de su ciclo de vida y a pesar de los cambios que pueda sufrir en sus propiedades. Por ejemplo, un alumno de un colegio se matricula en distintas asignaturas, pasa por distintos niveles, etc., pero sigue siendo el mismo alumno. Lo mismo podríamos decir de un profesor, de una asignatura, etc.
A estos conceptos que tienen identidad y ciclo de vida los denominamos Entidades.
Otros de estos conceptos se caracterizan por sus propiedades, no nos preocupa su identidad y no cambian a lo largo de su ciclo de vida. Como ejemplos, nos pueden servir una calificación (la nota en sí: notable, aprobado, suspenso), el precio de un servicio, y otros muchos. Son los Value Objects.
Ambos tipos de objetos tienen su propio comportamiento. Es decir: pueden hacer cosas relevantes para el dominio, Sin embargo, es frecuente que ciertas acciones necesiten coordinar de alguna manera varios de estos conceptos. Estamos hablando, entonces, de Servicios.
Identificación de bounded contexts y módulos
¿Cómo nos ayuda lo anterior a identificar bounded contexts? Tenemos varios tipos de indicios:
- Si un conjunto de Entidades, Value Objects y Servicios, tienden a aparecer juntos y cohesionados. Esto también nos podría estar anunciando la existencia de un Módulo, el cual tiene sentido como unidad de agrupación dentro de un bounded context. Sin embargo, para hablar de módulo no debe darse ninguna de las circunstancias siguientes:
- Si en ciertos momentos nos interesan unas propiedades de las entidades y en otros momentos otras diferentes, tendríamos una indicación de que existirían al menos dos bounded contexts.
- Puede ocurrir que una entidad deje de interesarnos como tal entidad y la podamos considerar como un Value Object. Y lo mismo en el otro caso, un Value Object que en ciertos momentos necesita una identidad. Ese cambio nos señalaría la presencia de un nuevo bounded context.
Intentemos verlo a través de ejemplos:
En nuestro sistema escolar, la entidad alumno aparece asociada con curso, materia, asignatura, profesor, notas, calificaciones, etc, entidades y valores con los que interactúa en diversos procesos. Parece claro que todos ellos formarían un contexto acotado, que bien podría ser el contexto académico.
Por su parte, la misma entidad alumno forma parte del contexto de administración, junto con conceptos como recibos, domiciliaciones, tasas, seguro escolar, etc.
Sin embargo, en el contexto académico son importantes algunas propiedades de la entidad, como puede ser la edad o el historial académico, que en el contexto administrativo resultan ser poco o nada relevantes. En este contexto, interesan propiedades como un número de cuenta, que son irrelevantes en el contexto académico.
En cierto modo, podrían modelarse como entidades distintas en cada uno de los contextos, relacionándose solo a través de su identidad porque representan a la misma persona real.
Estas relaciones entre contextos se conocen como Context Maps y permiten que los bounded contexts puedan, por así decir, hablar entre ellos acerca de las entidades que manejan.
Por otro lado, para el contexto del mantenimiento escolar, los alumnos no interesan por su identidad, sino por su número y alguna propiedad como la edad o si vive cerca o lejos del colegio, que nos sirve para determinar cosas como cuántas sillas y mesas se necesitarán, o cuántas plazas de autobús o de comedor tendríamos que disponer. En este contexto, el alumno no se modelaría como entidad, sino como value object: nos da igual qué persona concreta representa.
Dentro del contexto académico, por otra parte, podemos ver que ciertas entidades y valores aparecen estrechamente relacionados y, por tanto, pueden formar Módulos. Así, el módulo de alumnos puede agrupar a estos, con los grupos de clase y sus tutores. El módulo de asignaturas, con los cursos, niveles y profesores. Esta división en módulos nos aporta manejabilidad del modelo, pero no implica una separación funcional estricta de los conceptos.
Agregados
A medida que aprendemos sobre el dominio nos daremos cuenta que ciertas entidades y value objects viven tan estrechamente relacionadas que, de hecho, mantienen una relación de inclusión y dependencia. Un ejemplo muy claro es todo lo que tiene que ver con el historial académico de un alumno: calificaciones, actividades, títulos, etc., no tienen sentido ni identidad por sí solos, sino y siempre con relación a un estudiante, de modo que cualquier interacción en ellas debe pasar necesariamente por él. Este tipo de relación forma lo que conocemos como Agregado. Agregado es, por tanto, un conjunto de entidades y value objects que forman un todo cohesionado que se maneja a través de una de las entidades, llamada Raíz del agregado, la cual gestiona todo lo que tiene que ver con las entidades y valores que incluye.
Recapitulando
En este primer artículo hemos visto algunos de los elementos característicos que nos permiten articular el modelo de un dominio: bounded context, módulos, entidades, value objects, servicios y agregados.
En el próximo, desarrollaremos algunas implicaciones y cómo se concreta en el planteamiento de una aplicación.