Arquitecturas Orientadas a Eventos (Event-Driven)

Clase 15 de 24Curso de Fundamentos de Arquitectura de Software

Resumen

Las arquitecturas orientadas a eventos representan una evolución fascinante en el diseño de sistemas modernos, permitiéndonos abordar escenarios complejos con un enfoque distribuido y reactivo. Estos modelos arquitectónicos transforman la manera en que concebimos la comunicación entre componentes, estableciendo un paradigma donde el foco está en "qué ha sucedido" en lugar de "qué debe suceder". A través de este enfoque, conseguimos sistemas más desacoplados, escalables y adaptables a las necesidades empresariales actuales.

¿Qué son las arquitecturas orientadas a eventos y por qué son relevantes?

Las arquitecturas orientadas a eventos son modelos de diseño que permiten abordar sistemas complicados o complejos basándose en la transmisión de mensajes (eventos) que representan acciones ya ocurridas en el sistema. Este paradigma establece una clara separación entre dos tipos de actores fundamentales: productores de eventos (componentes que ejecutan comandos o acciones que modifican el estado del sistema) y consumidores (componentes que necesitan ser notificados de los cambios ocurridos).

La clave de estas arquitecturas reside en la implementación de buses de eventos o buffers que actúan como intermediarios, almacenando los eventos emitidos por los productores para luego notificarlos a uno o varios consumidores. Esta capa intermedia proporciona una de las ventajas más significativas de este modelo: la capacidad de mantener los eventos incluso cuando no hay consumidores disponibles para procesarlos.

El Domain-Driven Design (DDD) es una técnica frecuentemente utilizada en conjunto con estas arquitecturas, establecida desde principios del siglo XXI. El DDD facilita la creación de lenguajes ubicuos y comunicaciones fluidas, permitiendo identificar claramente:

  • Qué dominios emiten eventos
  • Qué dominios necesitan escuchar y reaccionar a esos eventos
  • Cómo se relacionan estos dominios en una línea temporal

¿Cómo funciona un sistema basado en eventos en la práctica?

Para comprender mejor el funcionamiento de una arquitectura orientada a eventos, podemos visualizarla como una cadena de acciones y reacciones. El flujo comienza cuando un productor ejecuta una acción, la cual genera una consecuencia directa: la emisión de uno o varios eventos.

Estos eventos son notificados a diversos consumidores, quienes pueden estar suscritos directamente al productor o, más comúnmente, a un bus de eventos que actúa como intermediario. Esta estructura intermedia proporciona robustez al sistema, garantizando que los eventos se mantengan disponibles incluso cuando no hay consumidores activos para procesarlos.

Un ejemplo práctico sería un sistema de facturación donde cada vez que se emite una factura correctamente, se genera un evento "factura_emitida". Este evento no necesariamente contiene toda la información detallada de la factura y sus anexos, sino los datos esenciales para identificar que la "factura x" fue emitida correctamente en el momento "t1".

Los consumidores de este evento pueden ser múltiples sistemas:

  • Un servicio de notificación por email
  • Una entidad gubernamental que registra transacciones
  • Un sistema de inventario que actualiza existencias

Cada consumidor procesará el evento en su propio tiempo y de acuerdo a sus capacidades, lo que genera diferentes líneas temporales y posibles colisiones, aumentando la complejidad del sistema a medida que resuelve problemas complicados.

¿Cuáles son los retos y consideraciones al implementar estas arquitecturas?

Diseñar una arquitectura orientada a eventos requiere un entendimiento profundo del contexto del dominio del problema. Los problemas complejos suelen requerir su división en diferentes contextos, lo que inevitablemente lleva a identificar conceptos de dominio comunes a varios de estos contextos.

Por ejemplo, en un sistema con contextos de ventas y soporte, conceptos como "cliente" y "producto" pueden ser comunes a ambos, pero requerirán tratamientos diferentes cuando se cierra una venta o cuando se gestiona un ticket de soporte. Estas "colisiones" en el dominio son frecuentes y exigen:

  • Un lenguaje ubicuo bien definido
  • Comunicación abierta y consistente entre los miembros del equipo
  • Clara diferenciación de cómo se utiliza cada concepto en su contexto específico

Uno de los retos más interesantes en estas arquitecturas son las diferentes líneas temporales que pueden surgir. Retomando el ejemplo anterior, imaginemos que el evento "factura_emitida" es recibido por una entidad pública que procesa millones de notificaciones similares y por un sistema de correo electrónico. Si la entidad pública experimenta una sobrecarga y reduce su nivel de servicio, podría darse el caso de que el cliente reciba la notificación por correo antes que la confirmación oficial de la entidad estatal.

Estas inconsistencias temporales requieren que el arquitecto diseñe líneas temporales coherentes según:

  • El contexto del problema
  • El nivel de servicio de cada componente
  • Las transacciones distribuidas que involucran múltiples sistemas

La transaccionalidad adquiere un nuevo significado en estos entornos, pasando de operaciones atómicas tradicionales a transacciones distribuidas que implican diversos componentes potencialmente desconectados entre sí.

Las arquitecturas orientadas a eventos suelen implementarse apoyándose en microservicios como sus componentes fundamentales, aunque también es posible utilizar microservicios sin necesariamente adoptar un enfoque basado en eventos.

El diseño de arquitecturas orientadas a eventos requiere un profundo entendimiento de conceptos como mensajería, procesamiento asíncrono y consistencia eventual. Dominar estos principios nos permite construir sistemas más resilientes, escalables y adaptables a cambios, características esenciales en el panorama tecnológico actual. ¿Has implementado alguna vez este tipo de arquitecturas? Comparte tu experiencia y los retos que enfrentaste en los comentarios.