¿Buscas nuestro logo?
Aquí te dejamos una copia, pero si necesitas más opciones o quieres conocer más, visita nuestra área de marca.
Conoce nuestra marca.¿Buscas nuestro logo?
Aquí te dejamos una copia, pero si necesitas más opciones o quieres conocer más, visita nuestra área de marca.
Conoce nuestra marca.dev
José Alberto Ruiz Casarrubios 13/07/2023 Cargando comentarios…
Hace unos días os contamos en qué consisten las arquitecturas EDA y qué hay que tener en cuenta para trabajar con ellas. Ahora, toca dejar a un lado esa teoría para ver un caso práctico. Usaremos el ejemplo de un proceso (light) de alta de un cliente u onboarding en una entidad financiera en la que se necesita un proceso de validación de la información.
Veremos cómo pasar del caso de uso de Negocio a un diseño de eventos y servicios, publicando los contratos y esquemas utilizando herramientas como AsyncAPI o Apicurio.
Para aplicar la teoría, vamos a modelar un proceso de alta de clientes que tiene la peculiaridad de que la información debe ser verificada antes de que el usuario pueda acceder al sistema de forma normal.
Para entender bien el problema, decidimos hablar con las personas de Negocio para que nos cuenten de primera mano el proceso, el cual podemos ver en la siguiente imagen:
Los pasos que se realizan son los siguientes:
En ese momento, si la resolución es OK, se disparan una serie de acciones para dar el alta por finalizada:
Estos pasos, aunque los enumeramos de forma secuencial, se realizan en paralelo.
Cuando ambos pasos se completan, se realizan los siguientes pasos:
Asociado al punto 9 (enviar welcome pack), Negocio comenta que en Marketing no se tiene información del cliente y se tiene que consultar cada vez que se necesita hacer una comunicación o envío de cualquier tipo (siendo el welcome pack un ejemplo de ello). Debido a esto, se están produciendo errores al obtener los datos de los clientes cuando el sistema está saturado, perjudicando a esos envíos de información a cliente. También comenta que solo desea tener información de los clientes activos, ya que un porcentaje de clientes no finalizan el proceso de onboarding.
Por otro lado, se comenta que existe un área de Auditoría y Calidad de Procesos que necesita medir los tiempos y calidad del proceso de alta. Para ello, necesita conocer la siguiente información:
Después de trabajar con Negocio, podemos identificar los siguientes eventos de dominio a lo largo del proceso de onboarding de un cliente:
Debemos recordar que estos eventos nos dicen “cómo funciona” un sistema a nivel de Negocio. No todos los eventos son de “interés” de todo el mundo o en todos los contextos.
Por lo tanto, tenemos que dar un paso más para agrupar los eventos por dominio, identificar los comandos que los generan cada evento, las entidades relacionadas y modelar las interacciones. El resultado es el siguiente:
Dentro del problema de “onboarding”, en la imagen anterior hemos identificado tres contextos importantes, como son:
Después podemos ver otros dominios secundarios o de soporte, como son “Notificaciones”, “Documentación” y “Seguridad”. En este post, los vamos a tratar como una caja negra y no vamos a entrar en detalles de los mismos.
Por otro lado, observando la imagen podemos ver cómo interactúan los contextos. Si recordamos el post anterior, en la imagen podemos ver cierto acoplamiento funcional. Veamos un par de ejemplos muy claros de este acoplamiento funcional que nos podría traer problemas en el futuro:
Por otro lado, si recordamos el caso de Negocio, se necesita informar al área de Auditoría sobre el inicio y fin del proceso de alta y el inicio y fin de la validación de documentación. Según está diseñado en este punto, también tendríamos que “incluir” lógica de los dominios de “Alta de Clientes” y “Calidad de información” en el área de Auditoría para que esta pueda saber cuándo se producen los hechos que quiere observar.
Como es un escenario mejorable, vamos a hacer una iteración más y para incluir otros tipos de eventos que faciliten la interacción entre contextos:
Como se puede ver en la imagen, hemos incluido una serie de eventos para relacionar los dominios:
Como trade-off a la hora de incluir estos eventos de notificación, puede ser necesario que el origen proporcione un endpoint (puede ser síncrono o asíncrono) para que el receptor de la notificación pueda preguntar por los detalles del hecho indicado en el evento. Esto es así porque los eventos de notificación son eventos muy ligeros, incluyendo solo la información necesaria para poder realizar esa consulta posterior a demanda, si fuera necesario. Por ejemplo, cuando se notifica “Onboarding iniciado” se incluye el identificador de cliente en el evento. Con este identificador, si algún consumidor necesita conocer los detalles de ese cliente puede realizar la petición usando ese identificador.
Ahora ya tenemos un diseño más aterrizado, pero todavía queda pendiente satisfacer el requisito de que, ahora mismo, Marketing necesita consultar siempre los datos de la base de datos de clientes utilizando un servicio para ello, queriendo minimizar estas consultas. Para ello, lo que haremos será crear una vista de clientes propia de Marketing, solo con la información que necesite. Esta vista se refrescará cada vez que haya un cambio en la información de un cliente.
Como por requisito está que solo se quiere alimentar la vista con clientes completos, el evento “Datos de cliente actualizados” solo se emite cuando el cliente queda activado, no antes.
En problemas más complejos, es mejor identificar primero las relaciones entre dominios y contextos y, después, identificar servicios y sus relaciones. En este caso, al ser un ejemplo sencillo, nos saltamos algún paso y vamos a realizar ya una primera identificación de servicios, estableciendo relaciones entre ellos:
Como podemos ver en la imagen, identificamos tres servicios que corresponden a su vez con los contextos identificados. Debemos decir que no es algo absoluto y que se puede pensar en otro tipo de divisiones. En este caso, optamos por tres por los siguientes motivos:
Además, hemos marcado con puntos las E/S de cada servicio:
Aunque la interacción con eventos suele ser de naturaleza asíncrona y la de comandos de naturaleza síncrona, no siempre es así y tenemos que evaluar los pros y contras en cada caso. Por ejemplo, el servicio de Marketing necesita interactuar con el servicio de notificaciones para comunicar al cliente que ya es un cliente real y que tiene disponible el welcome pack (se envíe por correo electrónico o correo postal). En este caso, puede ser conveniente que la ejecución del comando sea de forma asíncrona.
Vamos a dar otro paso más y vamos a realizar un diseño lógico de la solución por cada servicio.
Empecemos por el servicio de clientes:
Como podemos observar en la imagen, la parte central corresponde a la parte de dominio como tal (al Negocio) y las partes rojas serían los puntos de E/S, siendo los de la parte superior de entrada y los de la parte inferior de salida. Partiendo de este punto, es relativamente fácil ir hacia una arquitectura hexagonal o de ports & adapters.
Además, como se puede ver, lo que queda dentro del servicio, como son las entidades y los eventos que se publican, son responsabilidad del propio servicio. Lo que queda fuera, como los eventos que consume, no son responsabilidad del servicio, sino de los productores.
La siguiente tabla resume estas capacidades de E/S del servicio:
Tipo | Publica/expone o consume/accede | Nombre | Contenido |
---|---|---|---|
Comando (escritura) | Expone | Iniciar alta | - Datos del cliente (personales y contacto) - Documentación requerida - Password deseada |
Evento de Notificación | Publica | Onboarding iniciado | Identificador de cliente |
Comando (query) | Expone | Obtener datos cliente | - Datos del cliente (personales y contacto) |
Evento de Notificación | Consume | Validación finalizada | - Identificador del cliente - Resultado (OK/KO) |
Evento de cambio de contenido (ecst) | Publica | Datos de cliente actualizados | - Datos del cliente (personales y contacto) |
Evento de Notificación | Publica | Onboarding finalizado | - Identificador de cliente |
El siguiente servicio es el de Calidad de Información. Como hemos comentado se encarga de interactuar con el sistema externo, evitando que lo haga directamente el servicio de Clientes y, de este modo, proporcionar capacidades de evolución futura que no afecten al core. El servicio queda de la siguiente manera:
De forma similar al servicio anterior, la parte central es la que representa al dominio como tal mientras que las partes superiores e inferiores, representan los puntos de E/S. La siguiente tabla resume estas capacidades de E/S:
Tipo | Publica/expone o consume/accede | Nombre | Contenido |
---|---|---|---|
Evento de Notificación | Consume | Onboarding iniciado | - Identificador de cliente |
Comando (query) | Consume | Obtener datos cliente | - Datos del cliente (personales y contacto) |
Evento de Notificación | Publica | Validación iniciada | - Identificador del cliente |
Evento de Notificación | Publica | Validación finalizada | - Identificador del cliente - Resultado (OK/KO) |
Por último, el Servicio de Marketing queda de la siguiente forma:
La siguiente tabla resume estas capacidades de E/S:
Tipo | Publica/expone o consume/accede | Nombre | Contenido |
---|---|---|---|
Evento de cambio de contenido (ecst) | Publica | Datos de cliente actualizados | - Datos del cliente (personales y contacto) |
Evento de Notificación | Expone | Onboarding finalizado | - Identificador del cliente |
En los apartados anteriores hemos identificado los eventos que se van a intercambiar mediante el broker de mensajería, pero debemos definir cómo se van a intercambiar, es decir, qué canales o topics se van a usar. Para definir los topics vamos a fijarnos en la semántica del evento y al grupo lógico al que pertenecen, teniendo también en cuenta el orden de los eventos dentro de un marco temporal.
Podemos agrupar los eventos de forma semántica de la siguiente manera:
Una vez que hemos evaluado la distribución de los eventos en tópicos vamos a ponerlos nombre. Como ya comentamos, vamos a establecer un patrón de nombrado general. En este caso, adoptamos el siguiente patrón:
<dominio>.<tipo>.<clasificación>.<nombre>
Por lo tanto, nuestros topics serán:
Por último, vamos a diseñar los contratos de los servicios. Nos vamos a centrar en lo relativo a eventos, mediante AsyncAPI, no haciendo foco en los contratos basados en OpenAPI.
Si recuerdas el post anterior, hablábamos de un contrato operacional y de un contrato informacional. Prácticamente, con el desarrollo que hemos hecho en los apartados anteriores los tenemos prácticamente definidos ya a alto nivel, quedando únicamente declararlos usando AsyncAPI y esquemas AVRO.
Si quieres ir directo al final, los contratos y los esquemas los puedes encontrar en el siguiente repositorio, dentro de las carpetas “contracts” y “schemas”:
Hemos separado los esquemas en Avro de los ficheros de AsyncAPI, de forma que pueden evolucionar por separado. La referencia la hacemos al propio repositorio de código:
Finalmente, vamos a publicar los contratos en Apicurio para que estén disponibles para productores y consumidores de modo que puedan empezar los desarrollos de forma independiente.
Sigue las instrucciones del Readme del repositorio para levantar un entorno con Apicurio. Una vez arrancado, puedes acceder a Apicurio con la siguiente url: http://localhost:8080
Para publicar los contratos y los esquemas puedes hacerlo a mano, con el botón “Upload Artifact” o bien ejecutar el script “upload.sh” que encontrarás en el repositorio. Simplemente ejecuta:
sh upload.sh
Y si refrescas la consola de Apicurio verás los diferentes esquemas y contratos cargados:
Si hacemos click en cualquiera de ellos, podemos ver sus detalles:
Ya tenemos los contratos publicados. A partir de este momento, publicadores y consumidores pueden desarrollar de forma independiente sus servicios con la garantía de que no habrá problemas de integración.
Como puedes ver en la imagen anterior, en el contrato se incluye tanto las cabeceras, como el payload y como la clave. En nuestro caso, como clave siempre incluimos en identificador de cliente. Aunque pueda parecer redundante incluirlo también en el payload, creemos que es interesante incluirlo porque la key se utiliza principalmente para efectos de particionado y, en un caso real, sería más compleja.
Otra herramienta interesante para publicar los contratos es Event Catalog. No la incluimos en este post debido a que en el momento de creación existe un bug no resuelto a la hora de importar ficheros AsyncAPI con referencias a esquemas Avro.
Espero que os haya gustado el post. Hemos visto cómo aterrizar un caso de uso mediante una orientación a eventos y cómo llegar a diseñar y definir los contratos de los servicios y eventos. Como hemos comentado, este post tiene carácter divulgativo, buscando incluir conceptos relacionados con EDA. Se podría hacer perfectamente con otro tipo de orientación y diseño.
Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.
Cuéntanos qué te parece.