Artículo

Arquitectura de Software

Por qué existen las arquitecturas orientadas a eventos

Las llamadas directas entre servicios son simples hasta que dejan de serlo. La arquitectura orientada a eventos responde a una falla concreta de los sistemas fuertemente acoplados: este es el problema que realmente resuelve.

Casi todos los sistemas empiezan con una instrucción honesta: cuando pase esto, haz aquello. Se crea un pedido, así que cobra la tarjeta, reserva el stock y envía el recibo. Escrito como llamadas directas a funciones, se lee como una lista de tareas. Y durante un tiempo funciona de maravilla.

Luego la lista crece. Marketing quiere un correo de bienvenida. Analítica quiere el evento. Prevención de fraude quiere una puntuación de riesgo. Cada nuevo requisito añade otra línea dentro del mismo bloque de código, y el bloque que antes describía crear un pedido se convierte poco a poco en el lugar donde vive la lógica de toda la empresa.

La arquitectura orientada a eventos existe para romper esa gravedad.

El problema: un acoplamiento que se acumula

En un diseño de llamadas directas, el servicio de pedidos debe importar, referenciar y llamar a cada servicio posterior. Conoce la API de facturación, la de inventario, la de correo y la forma de cada una. Cuando alguna cambia, el servicio de pedidos cambia también. Cuando alguna es lenta, el pedido es lento. Cuando alguna se cae, el pedido falla.

Un módulo debería saber lo menos posible del resto del mundo. Cada dependencia que sostiene es una promesa que deberá cumplir cuando esa dependencia cambie.

Esto es acoplamiento, y se acumula. Diez servicios conectados directamente entre sí producen una red de conexiones que ningún ingeniero abarca en su cabeza. Un cambio se vuelve una negociación entre equipos. El sistema se vuelve rígido justo cuando el negocio necesita que sea flexible.

Por qué importa

El acoplamiento no es una queja estética. Tiene un costo que puedes medir:

  • Amplificación del cambio: una función nueva obliga a editar muchos servicios.
  • Propagación de fallos: una dependencia lenta se convierte en la lentitud de todos.
  • Fricción de despliegue: los servicios deben liberarse juntos y en orden.
  • Carga cognitiva: nadie puede razonar sobre un flujo sin leerlo entero.

Los equipos que más lo sufren son los que tienen éxito: el crecimiento es lo que convierte tres servicios ordenados en treinta enredados.

El modelo mental: anunciar, no ordenar

El cambio es pequeño de describir y enorme en sus consecuencias. En lugar de que el servicio de pedidos ordene cada acción posterior, anuncia un hecho y continúa:

«Se creó un pedido.» — dicho una vez, a nadie en particular.

Quien se interese por ese hecho se suscribe a él. Facturación reacciona. Inventario reacciona. Correo reacciona. El servicio de pedidos no sabe que existen y no los espera. Declara lo que ocurrió; las partes interesadas deciden qué hacer.

DIAGRAMA

Inversión del acoplamiento: a la izquierda un servicio de pedidos llama directamente a facturación, inventario, correo y analítica, acoplándose a cada uno; a la derecha anuncia un solo evento pedido.creado a un broker y los consumidores se suscriben de forma independiente.ANTES · LLAMADAS DIRECTASPEDIDOSSERVICIOFACTURACIÓNINVENTARIOCORREOANALÍTICADESPUÉS · ORIENTADO A EVENTOSPEDIDOSpedido.creadoBROKERFACTURACIÓNINVENTARIOCORREOANALÍTICASE SUSCRIBEN SOLOS
El mismo flujo de pedido, dos arquitecturas: a la izquierda el servicio de pedidos llama directamente a cada servicio posterior y se acopla a cada uno; a la derecha anuncia un solo evento a un broker, y los consumidores se suscriben de forma independiente sin que el productor sepa siquiera que existen.

Explicación central

Definición

Evento

Una declaración de un hecho sobre algo que ya ocurrió: emitido una vez, dirigido a nadie en particular. Un evento se nombra en pasado (pedido.creado), lleva los datos que describen lo que sucedió y nunca indica a nadie qué hacer al respecto. La reacción es decisión del suscriptor, no del evento.

Un sistema orientado a eventos tiene tres roles. Un productor emite eventos. Un broker —Kafka, NATS, RabbitMQ, una cola en la nube— los almacena y los entrega. Los consumidores se suscriben y reaccionan. El productor y el consumidor nunca se referencian; el broker es lo único que comparten.

Compara ambas formas directamente.

servicio-pedidos.ts
// Estilo de órdenes: el servicio de pedidos posee todo el flujo.
async function crearPedido(pedido: Pedido): Promise<void> {
await facturacion.cobrar(pedido);
await inventario.reservar(pedido);
await correo.enviarRecibo(pedido);
await analitica.registrar(pedido); // …y sigue creciendo
}
// Estilo de eventos: el servicio declara un hecho y se detiene.
async function crearPedido(pedido: Pedido): Promise<void> {
await guardar(pedido);
await eventos.publicar("pedido.creado", pedido);
}

En la segunda versión, añadir puntuación de fraude significa escribir un consumidor nuevo que se suscribe a pedido.creado. El servicio de pedidos no se toca, no se redepliega, ni siquiera se entera. El comportamiento nuevo se agrega por adición, no por edición: la propiedad que permite que los sistemas grandes sigan avanzando. (Hacer que ese guardar-y-luego-publicar sea confiable cuando una caída puede colarse entre ambos es su propio problema: el patrón outbox es la respuesta estándar.)

Asíncrono por naturaleza

Como el productor no espera, el trabajo ocurre en paralelo y en segundo plano. El cliente recibe una confirmación en el instante en que se guarda el pedido; el correo del recibo se genera unos cientos de milisegundos después, en un consumidor que se tomó su tiempo. Un proveedor de correo lento ya no ralentiza el checkout, porque el checkout ya no espera al correo.

El broker se gana su lugar

El broker no es una tubería que toleras: es donde viven las garantías. Retiene los eventos para que un consumidor que estuvo caído pueda ponerse al día. Reintenta la entrega cuando un consumidor falla. Te permite añadir un consumidor totalmente nuevo que reproduce meses de historia para construir una vista fresca: la misma idea de reproducir el registro que está en el corazón de event sourcing. Esas capacidades son el verdadero producto de la arquitectura.

Repositoriobitkode/event-driven-playbookProductores, un broker y consumidores ejecutables para cada patrón de este artículo: clónalo y observa cómo un solo pedido se abre hacia facturación, inventario y correo.TypeScriptVer en GitHub

Compensaciones

Los eventos no son gratis, y fingir lo contrario es como los equipos se queman.

ComparaciónLlamadas directas vs. orientado a eventos

Aspecto Llamadas directas Orientado a eventos
AcoplamientoAlto: todos conocen a todosBajo: solo se comparte el evento
ConsistenciaInmediataEventual: las reacciones se retrasan
Depurar un flujoLeer una funciónRastrear entre consumidores
Añadir un consumidorEditar el productorDesplegar un suscriptor nuevo
Radio de un falloSe propaga de forma síncronaContenido, reintentado por el broker

El segundo costo es la observabilidad. Un flujo que antes leías de arriba abajo ahora está repartido entre consumidores independientes. Sin identificadores de correlación y buen trazado, «¿qué le pasó al pedido 4182?» se vuelve un trabajo de detective.

Ideas clave

  • La arquitectura orientada a eventos resuelve el acoplamiento, no la velocidad. Recúrrela cuando el cambio y la propagación de fallos duelan, no por defecto.
  • Los productores anuncian hechos; los consumidores deciden cómo reaccionar. Ninguno sabe que el otro existe.
  • Ganas evolución independiente y aislamiento de fallos; pagas con consistencia eventual y depuración más difícil.
  • Si tus servicios son pocos y tus necesidades de consistencia son estrictas, una llamada directa sigue siendo la respuesta correcta y honesta.

El objetivo nunca fue usar eventos. El objetivo era permitir que cada parte de un sistema en crecimiento cambiara sin pedir permiso al resto. Los eventos son, simplemente, la forma más duradera que conocemos de concederlo.

// seguir explorando

Seguir explorando