L'arquitectura orientada a esdeveniments (EDA, Event-Driven Architecture) és un estil de disseny en què els components d'un sistema es comuniquen mitjançant la producció i el consum d'esdeveniments, en lloc d'invocar-se directament els uns als altres. Aquest enfocament afavoreix el desacoblament, l'escalabilitat i la capacitat de reaccionar en temps real al que passa en el negoci. En aquesta lliçó assentarem les bases conceptuals que necessitaràs per entendre la resta del mòdul: què és un esdeveniment, en què es diferencia d'una comanda i d'un missatge, quin paper juguen els productors i consumidors, i quines topologies existeixen per connectar-los.
Comprendre bé aquests fonaments és essencial perquè gairebé tots els sistemes moderns de gran escala (banca, e-commerce, streaming, IoT) es recolzen en esdeveniments per integrar microserveis sense que es coneguin entre si.
Contingut
- Què és l'arquitectura orientada a esdeveniments?
- Esdeveniment vs comanda vs missatge
- Productors i consumidors
- Topologia de mediador (mediator)
- Topologia de broker
- Diagrama general de flux d'esdeveniments
- Errors comuns i consells
- Exercicis i solucions
- Conclusió
- Què és l'arquitectura orientada a esdeveniments?
Un esdeveniment representa alguna cosa que ja ha passat en el sistema i que és rellevant per al negoci. Exemples: "ComandaCreada", "PagamentConfirmat", "UsuariRegistrat". L'important és el temps verbal: l'esdeveniment és un fet consumat i immutable.
En una arquitectura orientada a esdeveniments:
- Els components emeten esdeveniments quan canvia el seu estat.
- Altres components reaccionen a aquests esdeveniments sense que l'emissor sàpiga qui els està escoltant.
- La comunicació és típicament asíncrona: l'emissor no espera resposta.
Això contrasta amb l'arquitectura tradicional basada en crides síncrones (REST/RPC), on el client coneix i depèn del servidor.
| Característica | Crida síncrona (REST/RPC) | Arquitectura orientada a esdeveniments |
|---|---|---|
| Acoblament | Fort (el client coneix el servidor) | Feble (l'emissor no coneix el receptor) |
| Temporalitat | Bloquejant (espera resposta) | No bloquejant (fire-and-forget) |
| Escalabilitat | Limitada pel més lent | Alta (consumidors independents) |
| Tolerància a fallades | Si el servidor cau, la crida falla | L'esdeveniment es pot processar més tard |
- Esdeveniment vs comanda vs missatge
Aquests tres termes es confonen sovint. Són tipus de missatges, però amb intencions diferents.
| Concepte | Intenció | Temps verbal | Direcció | Espera resposta? |
|---|---|---|---|---|
| Comanda | Ordenar que alguna cosa passi | Imperatiu: "CrearComanda" | 1 emissor → 1 receptor concret | De vegades |
| Esdeveniment | Notificar que alguna cosa va passar | Passat: "ComandaCreada" | 1 emissor → N receptors desconeguts | No |
| Missatge | Terme genèric que engloba tots dos | — | — | Depèn |
Vegem un exemple en codi per fixar la diferència entre comanda i esdeveniment:
// COMANDA: una instrucció dirigida a un destinatari concret.
// S'espera que ALGÚ l'executi. Nom en imperatiu.
public record CrearPedidoCommand(
String clienteId,
List<LineaPedido> lineas) {
}
// ESDEVENIMENT: el fet que la comanda JA s'ha creat.
// És immutable, porta un identificador i una marca de temps.
// Nom en passat.
public record PedidoCreadoEvent(
String pedidoId,
String clienteId,
BigDecimal total,
Instant ocurridoEn) {
}Explicació detallada del fragment:
recordés una classe Java immutable i concisa (des de Java 16), ideal per representar dades que no canvien, com els esdeveniments.CrearPedidoCommandfa servir un verb en imperatiu perquè expressa una intenció que alguna cosa passi. Normalment el processa un únic component responsable.PedidoCreadoEventfa servir el participi "Creado" perquè descriu un fet passat. InclouocurridoEn(unInstant, marca temporal UTC) perquè tot esdeveniment ha de poder ordenar-se en el temps.- L'esdeveniment conté el
totalja calculat: transporta el resultat, no l'ordre de calcular-lo.
Regla pràctica: si pots rebutjar la petició, probablement és una comanda. Si només estàs informant que va passar i ningú s'hi pot "negar", és un esdeveniment.
- Productors i consumidors
En EDA distingim dos rols fonamentals:
- Productor (Producer / Publisher): el component que detecta un canvi i emet l'esdeveniment. No sap (ni li importa) qui el consumirà.
- Consumidor (Consumer / Subscriber): el component que rep l'esdeveniment i reacciona (actualitza una base de dades, envia un correu, crida un altre servei...).
// PRODUCTOR: publica l'esdeveniment en un canal. No coneix els consumidors.
@Service
public class ServicioPedidos {
private final PublicadorEventos publicador; // abstracció del canal
public ServicioPedidos(PublicadorEventos publicador) {
this.publicador = publicador;
}
public void crearPedido(CrearPedidoCommand cmd) {
// 1. Lògica de negoci: persistir la comanda
String pedidoId = UUID.randomUUID().toString();
// ... desar a la base de dades ...
// 2. Publicar l'esdeveniment del que ha passat
var evento = new PedidoCreadoEvent(
pedidoId, cmd.clienteId(), calcularTotal(cmd), Instant.now());
publicador.publicar("pedidos.creados", evento);
}
}Punts clau:
PublicadorEventosés una abstracció: amaga si per sota fem servir Kafka, RabbitMQ, etc. Això permet canviar la tecnologia sense tocar la lògica de negoci.- Després de desar la comanda, el servei publica al canal lògic
"pedidos.creados". No hi ha cap referència a qui escolta.
// CONSUMIDOR: se subscriu al canal i reacciona a l'esdeveniment.
@Component
public class NotificadorCliente {
@EventListener("pedidos.creados") // se subscriu al mateix canal
public void alCrearPedido(PedidoCreadoEvent evento) {
// Reacció: enviar confirmació al client
enviarEmailConfirmacion(evento.clienteId(), evento.pedidoId());
}
}- El consumidor
NotificadorClientereacciona enviant un correu. Un altre consumidor (per exemple,ServicioFacturacion) podria escoltar el mateix esdeveniment per emetre una factura. Afegir nous consumidors no requereix modificar el productor: aquí rau la potència d'EDA.
- Topologia de mediador (mediator)
Existeixen dues grans topologies per organitzar el flux d'esdeveniments. La primera és la topologia de mediador.
Aquí, un component central (el mediador o orquestrador) rep un esdeveniment inicial, el descompon en passos i coordina la seva execució dirigint el flux de treball.
- Útil quan el procés té diversos passos amb ordre i lògica condicional (per exemple, un alta d'assegurança: validar dades → tarificar → emetre pòlissa → cobrar).
- El mediador coneix el flux complet, la qual cosa centralitza la lògica de coordinació.
- Inconvenient: el mediador es pot convertir en un coll d'ampolla o en un punt únic de fallada, i acobla el coneixement del procés en un sol lloc.
flowchart LR
A[Client] -->|Esdeveniment inicial| M{Mediador / Orquestrador}
M -->|pas 1| S1[Servei Validació]
M -->|pas 2| S2[Servei Tarificació]
M -->|pas 3| S3[Servei Emissió]
S1 -.resposta.-> M
S2 -.resposta.-> M
S3 -.resposta.-> MEn el diagrama, el mediador (M) és qui decideix l'ordre i recull les respostes de cada servei. Els serveis no es coneixen entre si; només parlen amb el mediador.
- Topologia de broker
La segona és la topologia de broker (mediador absent). No hi ha coordinador central: els esdeveniments flueixen lliurement a través d'un broker (canal/cua) i cada servei reacciona de forma autònoma, i pot al seu torn emetre nous esdeveniments que disparen d'altres.
- Ideal per a fluxos simples i altament desacoblats.
- Màxima escalabilitat i resiliència: no hi ha punt central.
- Inconvenient: el flux global queda "repartit" i és més difícil de visualitzar i depurar (no hi ha un lloc on llegir tot el procés).
flowchart LR
P[Servei Comandes] -->|ComandaCreada| B((Broker))
B --> I[Servei Inventari]
B --> F[Servei Facturació]
I -->|StockReservat| B
F -->|FacturaEmesa| B
B --> E[Servei Enviaments]Aquí Servei Inventari reacciona a la ComandaCreada i, al seu torn, emet StockReservat, que dispara el Servei Enviaments. El flux emergeix de la suma de reaccions individuals, sense coordinador.
| Criteri | Mediador | Broker |
|---|---|---|
| Control del flux | Centralitzat | Distribuït |
| Acoblament | Mitjà (tothom coneix el mediador) | Mínim |
| Visibilitat del procés | Alta (un sol lloc) | Baixa (repartit) |
| Resiliència | Punt únic de fallada | Molt alta |
| Casos ideals | Fluxos complexos i condicionals | Fluxos simples i desacoblats |
- Diagrama general de flux d'esdeveniments
Combinant els conceptes, així es veu el flux bàsic productor → canal → consumidors:
sequenceDiagram
participant P as Productor
participant C as Canal d'esdeveniments
participant C1 as Consumidor 1 (Email)
participant C2 as Consumidor 2 (Facturació)
P->>C: publicar(PedidoCreadoEvent)
C-->>C1: entregar esdeveniment
C-->>C2: entregar esdeveniment
Note over C1,C2: Processen en paral·lel i<br/>independentmentEl productor publica una sola vegada; el canal distribueix l'esdeveniment a tots els subscriptors interessats, que treballen en paral·lel i sense conèixer-se.
Errors Comuns i Consells
- Confondre comandes amb esdeveniments. Si anomenes un esdeveniment en imperatiu ("EnviarEmail") estàs disfressant una comanda. Fes servir sempre el passat per als esdeveniments: "EmailSol·licitat" o "ComandaCreada".
- Ficar lògica de negoci del consumidor en el productor. El productor no ha de saber què fan els consumidors. Si ho sap, tornes a acoblar.
- Esdeveniments massa "grassos" o massa "prims". Un esdeveniment ha de portar les dades suficients perquè el consumidor reaccioni sense haver de tornar a cridar el productor (cosa que reintrodueix acoblament), però sense convertir-se en un abocament de tota la base de dades.
- Oblidar la marca temporal i l'identificador. Tot esdeveniment ha de ser traçable i identificable de manera idempotent.
- Consell: comença amb topologia de broker per a fluxos simples i reserva el mediador per a processos amb molts passos condicionals.
Exercicis
- Classifica els següents missatges com a comanda o esdeveniment i justifica-ho: (a) "ReservarHabitacio", (b) "PagamentRebutjat", (c) "ActualitzarPreu", (d) "SessioIniciada".
- Dibuixa (en pseudocodi o paraules) com es veuria un procés d'"alta de client" amb topologia de mediador enfront de topologia de broker. Quina triaries i per què?
- Dissenya un
recordd'esdeveniment en Java per a "FacturaEmesa" que inclogui els camps mínims necessaris perquè un consumidor de comptabilitat pugui reaccionar sense consultar de nou l'emissor.
Solucions
- (a) Comanda (imperatiu, dirigida, es pot rebutjar). (b) Esdeveniment (fet passat, notificació). (c) Comanda (ordre de canviar alguna cosa). (d) Esdeveniment (la sessió ja es va iniciar).
- Amb mediador: un
OrquestadorAltaClienterep la petició i crida en ordre validació → creació → benvinguda, gestionant les fallades. Amb broker:ServicioRegistroemetClienteRegistrado;ServicioEmailiServicioCRMreaccionen de forma independent. Per a un alta simple, el broker és preferible pel seu baix acoblament; si hi hagués molts passos condicionals (verificació d'identitat, scoring), el mediador facilita el control. - Una solució possible:
public record FacturaEmitidaEvent(
String facturaId,
String pedidoId,
String clienteId,
BigDecimal importeTotal,
BigDecimal impuestos,
String divisa,
Instant emitidaEn) {
}Inclou import, impostos i divisa perquè comptabilitat faci l'assentament sense consultar de nou.
Conclusió
Hem vist que l'arquitectura orientada a esdeveniments substitueix les crides directes per l'emissió i el consum de fets del negoci, aconseguint un fort desacoblament. Vam distingir comandes (ordres), esdeveniments (fets passats) i missatges (el terme genèric), i vam entendre els rols de productor i consumidor. Finalment vam comparar les dues topologies clau: mediador (control centralitzat) i broker (màxima autonomia).
En la lliçó següent, "Missatgeria Asíncrona: Cues i Brokers", aprofundirem en la infraestructura que transporta aquests esdeveniments: les cues enfront dels topics, les garanties d'entrega i les tecnologies concretes com RabbitMQ, Kafka i SQS.
Curs d'Arquitectura d'Aplicacions
Mòdul 1: Fonaments de l'Arquitectura d'Aplicacions
- Què és l'Arquitectura d'Aplicacions?
- El Rol de l'Arquitecte de Programari
- Atributs de Qualitat i Requisits No Funcionals
- Decisions Arquitectòniques i Compromisos (Trade-offs)
- Documentació d'Arquitectura: Vistes i el Model C4
Mòdul 2: Principis i Tàctiques de Disseny
- Acoblament, Cohesió i Separació de Responsabilitats
- Principis SOLID Aplicats a l'Arquitectura
- DRY, KISS, YAGNI i Altres Principis de Disseny
- Tàctiques Arquitectòniques per als Atributs de Qualitat
- Gestió del Deute Tècnic
Mòdul 3: Estils i Patrons Arquitectònics
- Arquitectura Monolítica
- Arquitectura en Capes (N-Tier)
- Arquitectura Client-Servidor
- Arquitectura Hexagonal (Ports i Adaptadors)
- Arquitectura Neta i Ceba (Clean & Onion)
Mòdul 4: Arquitectures Distribuïdes i Microserveis
- Introducció als Sistemes Distribuïts
- Arquitectura de Microserveis
- Descomposició de Serveis i Bounded Contexts
- API Gateway, Service Discovery i Comunicació entre Serveis
- Patrons de Resiliència: Circuit Breaker, Retry i Bulkhead
- El Teorema CAP i la Consistència de Dades
Mòdul 5: Arquitectures Dirigides per Esdeveniments i Missatgeria
- Fonaments de l'Arquitectura Orientada a Esdeveniments
- Missatgeria Asíncrona: Cues i Brokers
- Patrons d'Esdeveniments: Event Sourcing i CQRS
- Gestió de Transaccions Distribuïdes: Patró Saga
- Streaming de Dades en Temps Real
Mòdul 6: Disseny Dirigit pel Domini (DDD)
- Conceptes Fonamentals del DDD
- Disseny Estratègic: Bounded Contexts i Llenguatge Ubic
- Disseny Tàctic: Entitats, Agregats i Repositoris
- Mapatge de Contextos (Context Mapping)
Mòdul 7: Dades i Persistència
- Estratègies de Persistència: SQL vs NoSQL
- Patrons d'Accés a Dades: Repository, Unit of Work i DAO
- Base de Dades per Servei i Gestió de Dades Distribuïdes
- Cau i Estratègies d'Invalidació
Mòdul 8: Arquitectura al Núvol i Desplegament
- Fonaments del Cloud Computing (IaaS, PaaS, SaaS)
- Contenidors i Orquestració amb Docker i Kubernetes
- Arquitectura Serverless
- Patrons de Disseny Cloud-Native
- Infraestructura com a Codi (IaC)
Mòdul 9: Qualitat, Seguretat i Observabilitat
- Escalabilitat: Horitzontal vs Vertical i Balanceig de Càrrega
- Alta Disponibilitat i Tolerància a Fallades
- Seguretat per Disseny i Autenticació/Autorització
- Observabilitat: Logging, Mètriques i Traçabilitat
- Rendiment i Proves de Càrrega
