Introducción
Este es el segundo artículo sobre las lecciones aprendidas aplicando Domain Driven Design en el equipo de desarrollo de Jerónimo Palacios & Associates.
En la anterior entrada, te hablé sobre el mapeado del dominio en el modelo. En esta ocasión, te contaré cómo realizamos el segundo paso, la implementación del modelo en el diseño.
Creando el diseño: ida y vuelta.
Los técnicos estamos acostumbrados a transformar modelos en diseños. Formalicemos o no el modelo en un documento, cuando nos describen un problema, inmediatamente nos ponemos a pensar solución en código. Es nuestra forma de razonar. No podemos evitarlo.
Una de los aprendizajes más difíciles e importantes para un técnico es oponerse a este instinto. Cuando estamos construyendo el modelo debemos evitar contaminarlo con detalles de diseño para que sea útil como herramienta de comunicación con negocio. Pero esto no significa que el modelo esté aislado del diseño. No es una entidad abstracta que esté por encima y domine al diseño. Todo lo contrario, el modelo debe ser realista e implementable.
Es totalmente normal y esperable que, como consecuencia de su trabajo, el equipo de desarrollo encuentre problemas en el modelo. Estos problemas pueden tener su origen en la implementación o errores en el modelado del dominio puestos de manifiesto en la práctica. Sea cual sea el caso, los cambios en el modelo se evalúan con negocio (Product Owner, Business Analyst) para garantizar su consistencia.
Este proceso de realimentación mejora el modelo y, sobre todo, proporciona transparencia a negocio sobre su implementación. El conocimiento de la realidad del código por parte de negocio les permite comprender las limitaciones de la solución. Este conocimiento “técnico” es tan importante para la evolución de la aplicación como el conocimiento del equipo de desarrollo sobre el dominio del negocio. Y, de nuevo, el modelo va a jugar un papel central en este intercambio de información.
Formalización del Diseño
El diseño es propiedad del equipo de desarrollo y ellos deciden la mejor forma de reflejarlo. En muchas ocasiones no es necesario un documento formal. La documentación de diseño es muy costosa de mantener. Tan pronto como pongo el punto y final en un documento de diseño, queda desactualizado. Las dudas sobre la veracidad de esta documentación nos lleva continuamente a acudir a los artefactos de implementación como origen inequívoco de la verdad del sistema. En muchas ocasiones, el esfuerzo no compensa y es mejor prescindir de documentación e ir directamente a la fuente. Somos técnicos, sabemos leer el código.
Como te comentaba en la serie de entradas sobre diagnóstico de arquitectura , la documentación formalizada de diseño es útil para proporcionar una visión rápida y general sobre la solución. En caso de necesitarla, la documentación debe limitarse a los elementos más estables. Es decir, los más difíciles de modificar.
El nivel de arquitectura (servicios, orquestación, despliegue y componentes) es muy costoso de refactorizar, por lo que suele ser bastante estable. Otro caso son las clases o funciones centrales en la red de dependencias. Son aquellas que reciben más dependencias entrantes y, por lo tanto, son más significativas para la aplicación. Son difíciles de modificar porque tienen un enorme impacto colateral. Ambas vistas del sistema son muy relevantes para su mantenimiento por lo que suelen estar en la documentación formalizada de diseño.
Patrones DDD como piezas de diseño.
DDD propone una serie de patrones bien conocidos para mapear el modelo en el diseño. Por ejemplo: Value Objects, Entities, Factories, etc. En general, las indicaciones sobre su aplicación son muy razonables y se corresponden con el uso conocido de estos patrones. Sin embargo, el catálogo de patrones me resulta un poco reducido y de alto nivel de abstracción. Para algunos casos de uso, hemos recurrido a patrones más especializados como: builder, command, interactors o presenter.
En general, respecto a arquitectura y patrones, somos más de Robert C Martin que de Eric Evans. Particularmente, el modelo de capas en forma de cebolla que propone Uncle Bob, me resulta más natural. Con el dominio en el centro y diana de las dependencias del sistema, frente al apilado de capas sugerido en DDD. En cualquier caso, hay una correspondencia clara entre los niveles de abstracción de uno y otro, por lo que no son incompatibles. En la siguiente figura tienes los niveles identificados en Clean Architecture (rojo) y las correspondencias en DDD (azul)
Tecnologías de Desarrollo
Como describo en el artículo sobre arquitecturas emergentes, debemos centrarnos en lo realmente importante, el dominio, y aplazar al Last Responsible Moment la elección de herramientas concretas como frameworks y middleware.
Me gusta emplear una estrategia oportunista, recurriendo a las herramientas que mejor se adaptan al caso de uso. Pero, como todos, en JPA tenemos preferencias por las tecnologías que dominamos y con las que nos sentimos más cómodos. Algunos ejemplos son el paradigma orientado a objetos y los lenguajes con validación estática de tipos.
Paradigma OO
La programación Orientada a Objetos es una forma natural y directa de implementar la mayoría de los modelos. De los atributos de la programación orientada a objetos: abstracción, polimorfismo, herencia y encapsulamiento; es ésta última la que más me gusta y la que, por tanto, echo más en falta cuando trabajo con otros tecnologías que no le dan soporte directo (como Javascript o Python). Ocultar elementos de la implementación nos hace posible exponer una interfaz clara para dependencias y es la mejor forma de limitar el impacto de los refactoring.
Paradigma Funcional
El funcional se aplica muy bien en las partes del modelo que tienen una naturaleza claramente matemática. Para eso se creó. En nuestra herramienta Metrics, toda la base de cálculo se ha implementado empleando patrones funcionales: funciones de alto nivel, inmutabilidad y librerías de colecciones.
Validación estática de tipos.
Los lenguajes con validación estática de tipos me resultan más cómodos para desarrollar lógica compleja. Anticipar la detección de errores al tiempo de compilación me da mayor seguridad sobre la robustez del resultado. La estrategia Shift-Left DevOps dirige nuestras prácticas. Qué puede anticipar más los chequeos, a que sea el propio IDE quien me corrige errores mientras tecleo.
Por otro lado, tengo menos memoria que Dory. Ir tecleando y que el IDE me sugiera los métodos de una clase o me autocomplete, me da la vida.
Por último, los patrones de refactoring están mejor soportados en este tipo de lenguajes. Si habéis sufrido el refactoring en Javascript, os sugiero probar a disfrutar de la misma experiencia con Java.
Conclusiones
Con este artículo completo mi primera entrada sobre la aplicación de Domain Driven Design en el equipo de desarrollo de JPA. Os he contado algunas prácticas y herramientas que empleamos en JPA para realizar la transformación del modelo al diseño y su implementación.
No cierro el tema, todo lo contrario. Me encanta debatir sobre tecnología. Pon tus comentarios o escríbeme y encontremos juntos mejores soluciones.
Deja una respuesta