¿Qué es la arquitectura centrada en el dominio?

Javiera Laso
14 min readAug 4, 2021

Basado en la presentación de XConf 2020: ¿Qué es la arquitectura centrada en el dominio y por qué lo necesitas en tu negocio? Yerko Aguirre — Javiera Laso

La arquitectura es difícil

Conway establece que los diseños de sistemas son el fiel reflejo de como esta estructurada una organización, si una organización presenta una estructura de silos donde cada equipo esta aislado del resto, el diseño y arquitectura de los sistemas de esa organización van a presentar los mismos síntomas,

Por ejemplo, un sistema que esta dividido en equipos de frontend backend y administradores de base de datos donde existen silos y problemas de comunicación, van a producir sistemas aislados y fuertemente acoplados al contexto del equipo.

Ley de Conway representada en dibujo.

Es por esto, que debemos armar el negocio y los equipos de tal forma que represente lo que se necesita, por ejemplo, equipos de proyecto a equipos de producto, y veremos la justificación de esta decisión a medida que avances en el artículo.

Tipos de arquitectura en el desarrollo ágil

El software por su naturaleza es cambiante, cuando iniciamos en un proyecto ágil algunas veces no vemos o no nos preocupamos por conceptos de arquitectura que siempre están presentes, por lo cual el producto se vuelve difícil de cambiar en el futuro

Ciclo de desarrollo en un equipo ágil.

Sabemos además, que la arquitectura no esta escrita en piedra y no es algo rígido, mas bien es algo que va evolucionando a medida que el producto se desarrolla y no es trivial identificar dónde debería ir cierta lógica de negocios sin una arquitectura bien definida o una arquitectura mala.

Existen varios tipos de arquitectura, las cuales buscan resolver distintos problemas, y las cuales varían en complejidad, entre estos tipos no existe el concepto de mejor arquitectura, ya que todo “depende” del contexto y del problema que queremos resolver. Existen distintos tipos de arquitectura, donde podemos destacar a grandes rasgos los monolitos y las arquitecturas distribuidas.

Representación de distintos tipos de arquitectura.

Monolitos

Los monolitos son aquellos que combinan la capa de interfaz del usuario, la capa de negocios y la base de datos en un solo sistema, es decir, es responsable por todos los pasos necesarios para una función en particular. En los monolitos podemos encontrar:

  • Arquitectura por capas
  • Arquitecturas modulares
  • Micro Kernels

Arquitecturas distribuídas

Las arquitecturas distribuidas son aquellas que al contrario del monolito sus procesos son distribuidos, es decir si realizamos una consulta en la base de datos, vamos a dividir todos los procesos en distintos nodos, lo que mejorará el performance final de la aplicación. En esta arquitectura podemos encontrar:

  • Microservicios
  • Arquitectura orientada a servicios
  • Arquitectura orientada a eventos

Como vemos existen varios tipos de arquitectura, las cuales buscan resolver distintos problemas, y que varían en complejidad, entre estos tipos no existe el concepto de mejor arquitectura, ya que todo “depende” del contexto y del problema que queremos resolver.

Diseño guiado por el dominio

El diseño basado en dominios es un lenguaje y enfoque de software centrado en el diseño de los dominios para modelar problemas complejos. El término fue acuñado por Eric Evans en su libro Domain Driven Design. Consiste en una colección de patrones, principios y prácticas que permiten que los equipos se centren en lo que es fundamental para el éxito del negocio mientras se elabora software que gestiona la complejidad en los espacios técnicos y comerciales.

Adaptación del diseño guiado por el dominio. Fuente: https://github.com/ddd-crew/ddd-starter-modelling-process

En resumen, para llevar a cabo un buen diseño guiado por el dominio debemos seguir algunos pasos:

  1. El alineamiento es la parte fundamental donde debemos entender el modelo de negocios (que hace la empresa) y cuales son las necesidades de los usuarios
  2. Al descubrir podemos llevar iniciativas como el event storming para poder entender los dominios, los contextos y cuales pueden ser divididos para el proceso siguiente.
  3. Al entender los dominios, podemos descomponer en sub dominios, y comenzar a definir nuestros bounded contexts (de los cuales hablaremos después), además
  4. Debemos saber cómo conectar los sub-dominios ya que una arquitectura débilmente acoplada permite a los equipos trabajar en paralelo sin ser bloqueados.
  5. Al tener una estrategia de dominios centrales, podemos tener un lenguaje común entre el negocio y la parte técnica, a modo de definir routemaps e invertir la maniobra de Conway.
  6. Al organizarnos, debemos considerar que la maniobra de Conway no es lo mejor, ya que puede bloquearnos en etapas superiores.
  7. Al definir los roles y responsabilidades logramos que cada bounded context pueda evolucionar de forma óptima.
  8. Utilizar los patrones que mejor se ajusten a tu negocio y comienza a programar !

Lenguaje común entre negocio y tecnología

Es importante mantener un lenguaje común entre los expertos de negocio y expertos de tecnología, para lograr trasladar estos conceptos al código fuente, de forma tal de que nuestro producto de software refleje los conceptos que son hablados comúnmente por el negocio.

Representación del lenguaje ubicuo.

Ejemplos: Los acrónimos de negocio tienen que estar documentados en un lugar accesible, como confluence u otra wiki que haya sido creado en conjunto con las áreas involucradas.

Bounded Context

Los bounded context son el patrón principal en Domain-Driven Design. Un Bounded Context es un espacio delimitado donde un elemento del negocio tiene un significado perfectamente definido.

Bounded context en un e-commerce.

El contexto es definido por los términos usados en las charlas documentación, reuniones, etc.

Adaptación del detalle de un ejemplo de bounded context.

En la imagen podemos ver que un producto conceptualmente es completamente distinto de acuerdo a su contexto. Un producto en el contexto de envío es diferente a un producto en el contexto de inventario. Aquí es donde toma más fuerza la idea de que el significado varia de acuerdo del contexto, pero también podemos observar que podría verse afectado el código (por una posible duplicación), pero podemos compararlo con la disminución de un alto acoplamiento. Además tenemos la libertad de evolucionar de acuerdo al contexto.

Ahora que conocemos los los principios de DDD podemos hablar un poco sobre las arquitecturas clásicas y sus diferencias.

Arquitectura por capas v/s orientada al dominio

Representación de distintas arquitecturas, izquierda por capas, derecha orientada al dominio.

En la arquitectura por capas, la dependencia va desde la capa de presentación hasta la capa de persistencia, lo cual está bien para aplicaciones cuyo grado de complejidad es bajo, pero a medida que el producto crece y su complejidad aumenta, las reglas de negocio quedan agrupadas a otras capas y es difícil de cambiar y mantener.

Por otra parte, en la arquitectura centrada en el dominio, las dependencias se invierten y es el dominio el centro de todo, por lo cual las entidades, casos de uso o reglas de negocio no dependen de tecnología y tampoco de agentes externos, por lo cual es más fácil adaptarse al cambio y evolucionar

Si llevamos esto a la vida real podemos encontrar lo siguiente:

Representación de un caso real sobre las diferencias entre arquitectura por capas y centrada en el dominio.

Al mirar la imagen, y centrarnos en la arquitectura por capas podemos intentar “adivinar” sin mucho éxito, que es lo que hace la aplicación, quizás podemos decir: -“Tiene que ver con una clínica veterinaria”, pero si miramos la descrita por una arquitectura centrada en el dominio, es más “intuitivo” saber que es lo que está haciendo nuestra aplicación, vemos por ejemplo que si bien es sobre una clínica veterinaria, además es capaz de confirmar citas, agendar nuevas y buscar a los veterinarios disponibles (además de un sin número más de cosas que hace, por lo que se ve).

Podemos concluir que la estructura tradicional quiebra la encapsulación, al paso que la arquitectura por dominios la refuerza.

De la teoría a la realidad: Aplicación en proyectos reales

Arquitectura hexagonal en un e-commerce

La arquitectura hexagonal es conocida también como la arquitectura de puertos y adaptadores y tiene la misión de desacoplar las capas de la aplicación. Se describe como puerto, la definición de una interfaz pública y adaptador a la especialización de un puerto para un contexto en específico.

Ejemplo de una arquitectura hexagonal.

La elección de esta arquitectura se basa en sus características:

  • Independiente del framework
  • Testables
  • Independientes de la UI
  • Independientes de la base de datos
  • Independiente de agentes externos
  • Más tolerantes al cambio
  • Reutilizable
  • Mantenible
Descripción de una promesa de entrega aplicado a un e-commerce

Un enfoque popular es el empaquetado por cuestiones técnicas. Pero este enfoque tiene algunos inconvenientes. En su lugar, podemos empaquetar por característica y crear paquetes autónomos e independientes. El resultado es una base de código que es más fácil de entender y menos propensa a errores.

Arquitectura Limpia en una inmobiliaria

La arquitectura limpia es una filosofía de diseño de software que separa los elementos de un diseño en niveles de anillo. La regla principal de la arquitectura limpia es que las dependencias de código sólo pueden provenir de los niveles externos hacia adentro. El código de las capas internas no puede tener conocimiento de las funciones de las capas externas.

Ejemplo de una arquitectura limpia.

En este caso, la elección de este tipo de arquitectura se realiza debido a sus características:

  • Independiente del Framework y la DB
  • UI puede cambiar fácilmente
  • Fácil testeo
  • Reutilizable
  • Mantenible

Un ejemplo interesante de uso de este tipo de arquitectura se da cuando tratamos de cambiar un framework como Spring (que tiene su propia complejidad) a otro sin tantas funcionalidades pero que se ajusta a lo que necesitamos en ese momento para el negocio llamado SparkJava.

Representación del resultado de un cambio de framework gracias a la arquitectura limpia.

Caso: Alto tiempo de arranque al utilizar un framework robusto como Spring, sin necesitarlo. Solución: Cambiar el framework. Como funcionó esto: El desarrollo fue a nivel de framework con un par de líneas de código que logrando hacer un cambio “limpio” sin mayor impacto a las capas inferiores. Al no contar con spring security como librería dentro del framework, se necesitó implementar un middleware, además de generar un archivo de configuración de rutas, pues spring boot trae incorporada esta funcionalidad. Al hacer las pruebas de arranque en un estado de latencia, vimos que nuestro cambio disminuyó el tiempo de arranque de la aplicación de 21s a 4.4s

¿Cómo comenzar en la arquitectura centrada en el dominio?

Desenredando el monolito, es importante ver si podemos pasar de un monolito modular a microservicios, pero no siempre nuestro monolitos están descritos de forma limpia.

Representación de la expectativa de monolito modular a la realidad de una “big ball of mud”.

La expectativa es tener un monolito ordenado en torno a las capacidades de negocio, pero la realidad es que tenemos dependencias por múltiples lugares mucho acoplamiento que es difícil de evolucionar o cambiar, ya que un cambio en un lugar puede afectar el comportamiento de otra funcionalidad, lo que dificulta el proceso de cambios y de extracción de capacidades de negocio del monolito a microservicios.

Representación de un monolito modular de un e-commerce.

Una estrategia para lograr evitar dependencias y acoplamiento es el uso de monolitos modulares donde encapsulamos en módulos los distintos bounded context o dominios de nuestra aplicación, una estrategia para tener dominios aislados es lograr la comunicación entre módulos mediante bus de eventos en memoria, de esta forma logramos evitar acoplamiento entre módulos, y a futuro es más fácil transicionar a microservicios.

Representación de microservicios en un e-commerce.

Utilizando event storming y bounded context podemos definir microservicios, aunque no siempre vamos a tener una relación de 1 a 1 con respecto a microservicios/bounded context, y es posible que en un bounded context existan múltiples sub-dominios que se pueden traducir en otros microservicios.

Aquí es normal preguntarse ¿cuáles son los principios para trazar los límites del servicio?, y bueno, existe un par que debemos considerar:

Ejemplos de los principios para trazar los límites del servicio.

Lenguaje: Usa bounded context para trazar fronteras.

Autoridad: Ten autonomía para tomar decisiones.

Tamaño: Divide el servicio cuando un equipo no sea capaz de dar soporte a ese servicio.

Frecuencia de cambios: Considera agrupar conceptos con distinta tasa de cambio por ejemplo servicios de inventario v/s servicios de reporte anuales.

Transaccionalidad: Separa responsabilidades de operaciones v/s reportes ejemplo: Proyección de demanda vs reporte histórico de ventas anuales.

Cohesion: Agrupa conceptos que tengan relación entre sí, para así asegurar mantener la experiencia del negocio.

Orientado al consumidor: Organiza alrededor de capacidades de negocio no alrededor de sistemas.

Pero como elegimos el mejor, es decir, ¿Cómo saber si necesito un monolito o microservicios?

Elige monolito cuando:

  • No existe una cultura de DevOps, es importante que las personas sean capaces de desarrollar esta habilidad antes de migrar del monolito
  • Estás prototipando una idea y necesitas llevarla a producción de forma rápida
  • Código existente presente en una sola unidad de despliegue

Elige microservicios cuando

  • Tu equipo es maduro en el negocio y la empresa tiene una cultura de DevOps
  • Las personas desarrolladoras de tu equipo tienen experiencia en microservicios y entienden los conceptos de DDD (a veces adoptamos lo que está de moda sin leer los fundamentos, lo que puede llevar a equivocaciones de base que pueden impactar el negocio)
  • Cuando necesitas unidades de despliegue independientes y escalar de forma horizontal

Mantener la arquitectura en el tiempo

Cuando parte el proyecto, todos se sienten a gusto con la arquitectura, pero si recordamos hoy las decisiones que tomamos ayer puede haber algunas diferencias significativas, por eso es importante mantener visibilidad de las decisiones que tomaron en el pasado, que nos ayude a guiar y verificar que la arquitectura no se desvíe a medida que pasa el tiempo. A continuación me gustaría destacar algunas prácticas:

Visualiza tu arquitectura utilizando modelos C4

Las 4 fases del modelo son: contexto del sistema, diagrama del contenedor, diagrama de componentes y el código

Representación de un modelo C4 aplicado a una bicicleta. Contexto del sistema (ciclista), diagrama del contenedor (bicicleta), diagrama de componentes (zoom a una rueda), código (estructura molecular del caucho).

Los diagramas de arquitectura C4, son modelos que ayudan a explicar las aplicaciones y sus sistemas desde lo general a lo particular. Esto quiere decir que un sistema podemos explicarlo en 5 minutos, en 1 hora o en 5 horas.

Como ven en el ejemplo de arriba, podemos hablar tanto de un ciclista, llegando a la estructura molecular del caucho, lo importante es al menos tener documentado hasta el diagrama de contenedores o componentes. Aquí surge la pregunta ¿Cómo podemos hacer esa documentación?

ADRs

Los ADRs o Architectural Decision Records, son la forma en la que podemos documentar las decisiones que tomamos en cuanto a la arquitectura u otros temas, estos se almacenan en el código fuente y existen diversas formas de escribirlos, a continuación se presenta una forma popular:

Ejemplo de un ADR relacionado a la persistencia de la información.

Entonces, ¿ Qué forma práctica tenemos de mantener nuestra arquitectura y que además le entregue valor al negocio? considerando que ya documentamos en los ADR…

Testea tu arquitectura

Es importante tener test automatizados que aseguren que tu definición de arquitectura no se desvíe en el tiempo por ejemplo, test para mantener las capas aisladas de tecnología por ejemplo inyección de dependencias por constructor vs setter o reflection.

Representación de un test de arquitectura utilizando ArchUnit.

Los objetivos principales son:

  • Evitar dependencia a nivel de ciclos.
  • Evitar que la definición de arquitectura se desvíe en el tiempo.
  • Fijar lineamientos de arquitectura en el equipo
  • Test automatizados con los acuerdos técnicos a nivel de equipo

Además de estos test que logran mantener nuestra arquitectura debemos considerar otras formas de testear nuestra aplicación frente a lo inesperado y esperado, por un lado tenemos nuestro ciclo de desarrollo normal que describe una pirámide de pruebas convencional y por otro las fitness functions.

Representación de un ciclo completo de pruebas que considera la pirámide de pruebas tradicional junto con las fitness functions.

Observamos en la imagen que tenemos las típicas pruebas que tratamos de aplicar en todos los proyectos, en el desarrollo usamos generalmente TDD (en mi caso) por lo tanto tratamos de seguir la pirámide de pruebas, donde verificamos que las características se ajusten a los resultados comerciales deseados. En las fitness functions podemos escribir pruebas que midan la alineación de un sistema con los objetivos arquitectónicos.

Por ejemplo, existe el chaos monkey, creado por Netflix y responsable de terminar aleatoriamente las instancias en producción para garantizar que nosotros las personas programadoras implementamos los servicios para que sean resistentes a las fallas de las instancias. Algunas fitness functions interesantes que utilizamos y no sabíamos lo que eran:

  • Calidad de código: coverage sobre el 90%
  • Pruebas de Resilencia: como una prueba podría ejecutar una carga continua en un servicio mientras se implementa una nueva versión de ese servicio en un entorno de pre-producción.
  • Pruebas de Observabilidad: métricas que indican baja conversión o volumen de usuarios utilizando splunk (fitness functions en base a métricas de negocio)
  • Pruebas de Performance: Por ejemplo cuando queremos que una transacción se realice en máximo 10 segundos, la cual es una métrica definida por la experiencia y el negocio
  • Análisis de seguridad: Los típicos de OWASP (como evitar compartir secretos en un deploy a git), pero también que no vaya a existir información sensible en logs, entre otros

Luego de todas estas definiciones vemos que además, las fitness functions se pueden incorporar para monitorear la alineación con las características” arquitectónicas críticas. A medida que la organización y la tecnología evolucionan, estas fitness functions pueden ayudar a las empresas a evitar quedar con una arquitectura o pruebas obsoletas que a menudo resulta en una complejidad heredada o innecesaria que limita la entrega de valor.

¿Por qué necesitas una arquitectura centrada en el dominio en tu negocio?

Luego de toda la información que hemos revisado nos damos cuenta que la maniobra de Conway de por si no es suficiente, sino que debemos crear equipos de productos; a esta forma de trabajo se le llama maniobra inversa de Conway, donde equipos de productos son capaces de manejar la operación completa de ese producto siendo multidisciplinarios, encargados de sus propios roadmaps pero que pueden conversar entre ellos de ser necesario.

Representación de la maniobra inversa de Conway

Otro punto que aprendimos es que si te demoras en adaptarte le das ventaja a la competencia, por esto, estar preparados para el cambio nos ayuda a reaccionar de forma rápida. Por ejemplo, cuando la pandemia de covid19 llegó muchos comercios debieron adaptar sus infraestructuras a una cantidad anormal de público online, muchos no lo lograron, pero otros salieron victoriosos.

Finalmente, el tener una arquitectura centrada en el dominio te da una visión técnica y del negocio. Si subes la montaña y ves la ciudad desde lejos, puede entender las zonas en las que se organiza la ciudad. Haciendo analogía con la arquitectura centrada en el dominio, en el cual sabes donde esta la lógica de negocio y entiendes el leguaje tienes una vision global de como esta construido tu producto.

Algunas lecturas recomendadas

A continuación algunos libros con los que se construyó este artículo y presentación:

Libros recomendados y en los que está basado este articulo/presentación.

Espero este artículo haya sido de ayuda y no olvides dejar tus comentarios y feedbacks en la caja de abajo, pronto vendrá la versión en inglés para que compartas con tus amigos más internaciones, muchas gracias por leer y llegar hasta aquí.

--

--

Javiera Laso

Engineer on biotechnology and Software developer. Nerd por excelencia y escritora beginner. Bilingüe y ojalá un día logre aprender alemán