Event-driven: quando è davvero la scelta giusta?
Le architetture event-driven vengono spesso presentate come la naturale evoluzione delle integrazioni tradizionali.
Un sistema pubblica un evento, gli altri lo ricevono e reagiscono in modo indipendente.
Il produttore non deve conoscere tutti i destinatari. I sistemi possono elaborare le informazioni con tempi differenti. Un nuovo consumer può essere aggiunto senza modificare necessariamente chi ha generato l’evento.
Il modello appare elegante:
Sistema sorgente ↓ Evento ↓Message broker ↙ ↓ ↘CRM ERP AnalyticsIn alcuni contesti, questa architettura produce un valore concreto.
Permette di assorbire picchi, isolare temporaneamente sistemi non disponibili, distribuire le elaborazioni e ridurre alcune forme di accoppiamento.
In altri casi, però, trasforma un flusso relativamente semplice in un sistema distribuito più difficile da comprendere, verificare e gestire.
La domanda utile non è quindi:
Dovremmo adottare un’architettura event-driven?
È piuttosto:
Quale problema stiamo cercando di risolvere e perché una comunicazione asincrona dovrebbe essere più adatta?
Un’architettura event-driven non elimina la complessità.
La sposta.
Riduce alcune dipendenze dirette, ma introduce messaggi, code, duplicazioni, ritardi, consistenza eventuale, gestione dello stato e nuove esigenze di osservabilità.
La scelta è corretta quando questo scambio produce un vantaggio reale.
In un’architettura event-driven, un componente comunica che qualcosa è accaduto.
Per esempio:
- un ordine è stato creato;
- un pagamento è stato confermato;
- un prodotto è stato aggiornato;
- una spedizione è partita;
- un documento è stato elaborato;
- un utente ha completato una registrazione.
L’evento viene pubblicato e uno o più componenti possono reagire.
Order Created ↓ ┌────┼───────────┐ ↓ ↓ ↓ERP Email Preparazione spedizioneIl produttore dell’evento non dovrebbe coordinare direttamente tutte le operazioni successive.
Comunica un fatto rilevante. Sono i consumer a decidere se e come utilizzarlo.
Questo modello è differente da una chiamata sincrona tradizionale:
E-commerce → crea ordine nell’ERP → attende la rispostaNel modello sincrono, chi effettua la chiamata conosce il destinatario e attende un risultato.
Nel modello event-driven, il produttore pubblica un’informazione e può continuare senza attendere che ogni consumer completi il proprio lavoro.
La differenza non riguarda soltanto la tecnologia.
Cambia il modo in cui vengono distribuite responsabilità, errori e stato del processo.
Una distinzione importante è quella tra evento e comando.
Un comando esprime una richiesta:
CreateInvoiceSendNotificationUpdateInventoryUn evento descrive qualcosa che è già avvenuto:
OrderConfirmedInvoiceCreatedInventoryUpdatedLa differenza può sembrare terminologica, ma ha conseguenze architetturali.
Un comando chiede a un componente specifico di eseguire un’azione.
Chi lo invia conosce almeno la capacità che vuole utilizzare.
Order Service → CreateInvoice → Billing ServiceIl servizio di fatturazione può accettare o rifiutare la richiesta.
Un evento non dovrebbe ordinare ai consumer cosa fare.
Comunica che lo stato del dominio è cambiato.
Order Service → OrderConfirmedIl servizio di fatturazione può utilizzare l’evento per creare una fattura. Un servizio di analytics può registrarlo. Un sistema di notifiche può inviare un messaggio.
Il produttore non deve necessariamente conoscere queste reazioni.
Un messaggio chiamato OrderCreated potrebbe sembrare un evento, ma essere in realtà utilizzato come richiesta implicita al sistema di logistica.
In questo caso il produttore si aspetta un comportamento specifico, anche se il contratto non lo dichiara chiaramente.
Questa ambiguità rende difficile comprendere:
- chi è responsabile dell’azione;
- se il messaggio può essere ignorato;
- quale risultato è atteso;
- come gestire un fallimento;
- quando il processo può essere considerato completo.
Nominare correttamente i messaggi aiuta a rendere esplicite le responsabilità.
L’asincronia non dovrebbe essere introdotta soltanto perché i sistemi sono numerosi o perché un message broker è già disponibile.
Deve risolvere un’esigenza concreta.
In una chiamata sincrona, entrambi i sistemi devono essere disponibili nello stesso momento.
Sistema A → Sistema BSe il sistema B non risponde, anche il processo del sistema A può bloccarsi.
Con una coda, il messaggio può essere conservato finché il destinatario non torna disponibile.
Sistema A → Coda → Sistema BQuesto è utile quando il produttore può completare la propria attività senza attendere l’elaborazione immediata del consumer.
Un sistema può produrre richieste più velocemente di quanto il destinatario riesca a elaborarle.
La coda funziona come un buffer.
Il produttore continua a pubblicare, mentre i consumer elaborano i messaggi secondo la capacità disponibile.
Questo permette di gestire variazioni temporanee del carico senza dimensionare ogni componente sul picco massimo.
Quando più sistemi devono reagire allo stesso cambiamento, un evento può evitare che il produttore li chiami direttamente uno per uno.
ProductUpdated ↓ ┌────┼───────────┐ ↓ ↓ ↓Search Cache MarketplaceIl produttore rimane meno dipendente dal numero e dall’identità dei destinatari.
Alcune elaborazioni non devono essere completate durante la richiesta dell’utente.
Per esempio:
- generazione di un report;
- elaborazione di immagini;
- invio di notifiche;
- aggiornamento di indici di ricerca;
- sincronizzazione con sistemi esterni;
- arricchimento dei dati.
Spostare queste attività in processi asincroni può ridurre il tempo di risposta percepito e isolare i fallimenti secondari.
Se il contratto degli eventi rimane stabile, diversi consumer possono essere sviluppati e distribuiti separatamente.
Questo vantaggio diventa rilevante quando più team gestiscono componenti differenti e hanno realmente bisogno di cicli di rilascio autonomi.
L’event-driven non è una soluzione superiore in ogni situazione.
Molti processi sono più comprensibili se rappresentati attraverso una chiamata diretta.
Se un utente deve sapere subito se un pagamento è stato autorizzato, una risposta asincrona può rendere il flusso più complesso.
La richiesta ha bisogno di un risultato chiaro:
Richiesta → Elaborazione → RispostaTrasformarla in:
Richiesta → Messaggio → Attesa → Evento di rispostaintroduce stato, timeout e correlazione senza necessariamente produrre un vantaggio.
Se un servizio deve interrogare un altro servizio specifico e la relazione è chiara, una chiamata API può essere sufficiente.
Aggiungere un broker tra due componenti non li rende automaticamente meno accoppiati.
Il produttore continua spesso a dipendere:
- dal significato del messaggio;
- dal comportamento del consumer;
- dai tempi di elaborazione;
- dall’esito finale.
L’accoppiamento può diventare meno visibile, ma non necessariamente scomparire.
Un flusso composto da pochi passaggi, con errori facilmente gestibili, può essere più semplice da seguire in modo sincrono.
La sequenza rimane esplicita nel codice e l’errore può essere restituito direttamente al chiamante.
Quando il carico è prevedibile e contenuto, il buffering offerto da una coda può non essere necessario.
Il costo operativo del broker, del monitoraggio e della gestione dei consumer potrebbe superare il beneficio.
Un sistema distribuito richiede strumenti e competenze per osservare code, messaggi, retry, consumer e ritardi.
Adottare il modello prima di avere queste capacità può diminuire l’affidabilità anziché migliorarla.
Uno dei principali argomenti a favore delle architetture event-driven è il disaccoppiamento.
È un beneficio reale, ma deve essere interpretato con precisione.
Il produttore può non conoscere l’indirizzo o l’implementazione dei consumer.
Rimane però legato a un contratto informativo.
Un evento come:
{ "eventType": "OrderConfirmed", "orderId": "ORD-1824", "customerId": "CUS-77", "total": 129.90, "currency": "EUR"}crea comunque dipendenze.
I consumer dipendono:
- dal nome dell’evento;
- dal significato dei campi;
- dalla presenza degli identificativi;
- dalle unità di misura;
- dalle regole di versione;
- dalla semantica del momento in cui l’evento viene emesso.
Il produttore non è libero di modificare arbitrariamente il contratto.
Il disaccoppiamento riguarda quindi alcune dimensioni:
- distribuzione;
- disponibilità temporale;
- conoscenza diretta dei destinatari;
- ciclo di rilascio.
Non elimina l’accoppiamento semantico.
Se il significato dell’evento non è stabile e condiviso, i consumer possono interpretarlo in modi differenti.
Un sistema event-driven aggiunge componenti e comportamenti che devono essere gestiti.
Il messaggio non passa semplicemente da A a B.
Può essere memorizzato, duplicato, ritardato, elaborato fuori ordine o spostato in una coda degli errori.
Molte infrastrutture garantiscono che un messaggio venga consegnato almeno una volta.
Questo significa che può essere consegnato più volte.
Il consumer deve quindi essere preparato a ricevere duplicati.
Evento 1 → ConsumerEvento 1 → ConsumerSenza idempotenza, la seconda elaborazione può:
- creare una seconda fattura;
- inviare un’altra email;
- ridurre nuovamente la disponibilità;
- duplicare una registrazione;
- applicare due volte una modifica.
La duplicazione non è un caso eccezionale. Deve essere considerata parte del modello.
Non sempre gli eventi vengono elaborati nello stesso ordine in cui sono stati prodotti.
Un consumer potrebbe ricevere:
CustomerAddressUpdatedprima di:
CustomerCreatedOppure due aggiornamenti dello stesso elemento potrebbero essere elaborati da consumer differenti in ordine diverso.
Quando l’ordine è importante, è necessario definire:
- chiave di partizionamento;
- versione dell’entità;
- sequenza;
- gestione degli eventi obsoleti;
- comportamento in presenza di lacune.
Dopo la pubblicazione di un evento, i sistemi non si aggiornano necessariamente nello stesso momento.
Per un certo intervallo possono mostrare stati differenti.
ERP: ordine confermatoCRM: aggiornamento in attesaAnalytics: dato non ancora disponibileQuesta consistenza eventuale può essere accettabile, ma deve essere compresa dal business e dalle interfacce utente.
Se l’organizzazione si aspetta che tutti i sistemi riflettano immediatamente lo stesso stato, l’asincronia può generare confusione.
In un flusso sincrono, il chiamante riceve spesso un errore immediato.
In un sistema event-driven, il produttore può aver completato correttamente il proprio lavoro mentre uno dei consumer fallisce alcuni minuti dopo.
La gestione dell’errore diventa una responsabilità separata:
- chi rileva il fallimento;
- chi viene notificato;
- quanti retry eseguire;
- quando isolare il messaggio;
- come correggere il dato;
- come rilanciare l’elaborazione;
- come verificare lo stato complessivo.
Un processo può attraversare più code e consumer.
OrderConfirmed ↓Billing ↓InvoiceCreated ↓DocumentStorage ↓InvoiceArchivedQuando il risultato finale manca, non è sufficiente controllare un solo servizio.
Serve ricostruire l’intera catena.
Senza identificativi di correlazione e osservabilità distribuita, l’analisi può diventare molto costosa.
Non tutti gli eventi devono contenere la stessa quantità di informazioni.
Esistono due approcci comuni.
Il messaggio comunica che qualcosa è accaduto e contiene pochi riferimenti.
{ "eventType": "CustomerUpdated", "customerId": "CUS-77"}Il consumer deve interrogare il sistema sorgente per ottenere i dati aggiornati.
Questo approccio mantiene il messaggio piccolo e riduce la duplicazione dei dati.
Introduce però una dipendenza operativa: il consumer deve poter contattare il sistema sorgente.
Se molti consumer reagiscono contemporaneamente, il produttore può ricevere numerose richieste.
Il messaggio contiene i dati necessari al consumer.
{ "eventType": "CustomerUpdated", "customerId": "CUS-77", "email": "customer@example.com", "status": "active", "updatedAt": "2026-07-30T12:40:00Z"}Il consumer può elaborare il messaggio senza interrogare il produttore.
Questo aumenta l’autonomia e la resilienza.
Produce però altre responsabilità:
- dimensione dei messaggi;
- dati duplicati;
- informazioni sensibili;
- evoluzione dello schema;
- gestione degli eventi obsoleti;
- scelta dei campi da pubblicare.
Non esiste una soluzione sempre corretta.
La scelta dipende da quanta autonomia serve ai consumer e da quali dati sia opportuno distribuire.
Un evento non dovrebbe essere semplicemente la serializzazione di una tabella o dell’oggetto interno di un’applicazione.
Dovrebbe rappresentare un fatto significativo per il dominio.
Un evento descrive qualcosa che è avvenuto.
Nomi come:
OrderConfirmed;PaymentReceived;ShipmentDispatched;CustomerSuspended;
sono generalmente più chiari di nomi generici come:
OrderEvent;DataChanged;Update;Notification.
Il nome dovrebbe comunicare il significato senza richiedere l’analisi completa del payload.
Deve essere chiaro quando l’evento viene pubblicato.
OrderCreated può significare:
- carrello convertito in ordine;
- pagamento ricevuto;
- ordine salvato nel database;
- ordine validato;
- ordine accettato dall’ERP.
Interpretazioni diverse producono comportamenti differenti nei consumer.
Il messaggio deve contenere un identificativo stabile e comprensibile.
Quando più sistemi utilizzano identificativi differenti, deve essere chiaro quale venga pubblicato e come possa essere correlato agli altri.
Sono spesso utili:
- data e ora dell’evento;
- versione dello schema;
- versione dell’entità;
- identificativo univoco del messaggio;
- identificativo di correlazione;
- origine dell’evento.
Questi metadata aiutano a gestire duplicazioni, ordinamento e ricostruzione del flusso.
Il payload dovrebbe fornire le informazioni necessarie senza trasformarsi in una copia completa dello stato interno.
Pubblicare ogni campo “nel caso possa servire” aumenta il rischio di creare contratti difficili da modificare.
In un sistema event-driven è prudente assumere che ogni messaggio possa arrivare più volte.
L’idempotenza permette di elaborare lo stesso evento senza produrre effetti duplicati.
Un consumer può registrare gli identificativi già elaborati:
Event ID: EVT-9348Stato: completatoSe lo stesso evento viene ricevuto nuovamente, il consumer può ignorarlo oppure restituire l’esito precedente.
Altre strategie includono:
- vincoli univoci nel database;
- chiavi di idempotenza;
- confronto con la versione corrente;
- operazioni di upsert;
- controllo dello stato del dominio;
- transazioni locali.
La strategia dipende dal tipo di effetto.
Aggiornare lo stato di un cliente può essere relativamente semplice da rendere idempotente.
Inviare una comunicazione o avviare un pagamento richiede controlli più espliciti.
L’idempotenza dovrebbe essere progettata insieme al consumer, non aggiunta soltanto dopo il primo problema di duplicazione.
Quando un consumer fallisce, un nuovo tentativo può essere appropriato.
Non tutti gli errori, però, sono temporanei.
Possono includere:
- timeout;
- servizio non disponibile;
- limite temporaneo dell’API;
- problema di rete;
- lock momentaneo.
Questi errori possono essere ritentati con intervalli crescenti.
Tentativo 1 → 10 secondiTentativo 2 → 1 minutoTentativo 3 → 5 minutiPossono includere:
- dato non valido;
- identificativo inesistente;
- contratto incompatibile;
- autorizzazione mancante;
- regola di business violata.
Ripetere automaticamente lo stesso messaggio non modifica la condizione.
Dopo un numero definito di tentativi, il messaggio può essere spostato in una dead-letter queue o in uno stato di errore.
Questo non risolve il problema.
Lo isola per evitare che blocchi l’intero flusso.
Devono quindi esistere procedure per:
- visualizzare i messaggi falliti;
- comprendere il motivo;
- correggere i dati;
- rilanciare l’elaborazione;
- verificare l’esito;
- chiudere l’anomalia.
Una dead-letter queue senza un processo operativo diventa semplicemente un archivio di problemi dimenticati.
In un processo distribuito, un’operazione può riuscire in un sistema e fallire in un altro.
Supponiamo che la conferma di un ordine attivi:
- prenotazione del magazzino;
- acquisizione del pagamento;
- creazione della spedizione.
Il magazzino può completare la prenotazione, mentre il pagamento fallisce.
Non esiste necessariamente una transazione unica capace di annullare automaticamente tutte le operazioni.
Serve quindi definire cosa debba accadere.
Possibili strategie includono:
- compensare le operazioni già eseguite;
- mantenere lo stato parziale e richiedere un intervento;
- ritentare soltanto il passaggio fallito;
- utilizzare una macchina a stati;
- introdurre un coordinatore del processo.
Un componente centrale decide quali passaggi eseguire e come reagire agli esiti.
Order Process ├─ Prenota magazzino ├─ Acquisisce pagamento └─ Crea spedizioneIl processo è più semplice da ricostruire, ma il coordinatore assume una responsabilità importante.
Ogni servizio reagisce agli eventi e pubblica nuovi eventi.
OrderConfirmed ↓StockReserved ↓PaymentCaptured ↓ShipmentCreatedLa dipendenza diretta tra servizi diminuisce, ma il processo complessivo può diventare difficile da vedere.
La coreografia funziona meglio quando le reazioni sono relativamente indipendenti.
Quando esiste una sequenza di business rigida, con compensazioni e stato complessivo, l’orchestrazione può essere più comprensibile.
In un’architettura asincrona, sapere che il produttore ha pubblicato correttamente un evento non dimostra che il processo sia completato.
Serve osservare l’intero percorso.
Per ogni messaggio dovrebbe essere possibile conoscere:
- chi lo ha prodotto;
- quando;
- su quale topic o coda;
- quali consumer lo hanno ricevuto;
- quali elaborazioni sono riuscite;
- quali sono fallite;
- quanti retry sono stati eseguiti;
- se il messaggio è in attesa;
- se è stato isolato;
- quale stato di business ha prodotto.
Un identificativo comune permette di collegare eventi differenti appartenenti allo stesso processo.
Correlation ID: COR-2817
OrderConfirmed ↓StockReserved ↓PaymentCaptured ↓ShipmentRequestedSenza questa correlazione, ogni servizio mostra soltanto una parte del flusso.
Le metriche utili possono includere:
- numero di messaggi pubblicati;
- tempo in coda;
- ritardo del consumer;
- tasso di errore;
- numero di retry;
- messaggi nella dead-letter queue;
- tempo necessario per completare un processo;
- differenza tra eventi prodotti ed elaborati.
Non basta monitorare che il broker sia disponibile.
Il broker può funzionare correttamente mentre i processi di business rimangono bloccati.
Le metriche aggregate mostrano la salute generale.
Durante un incidente serve però trovare il singolo ordine, cliente o documento.
Una buona osservabilità deve supportare entrambi i livelli:
- panoramica del sistema;
- ricostruzione del singolo caso.
Gli eventi diventano contratti condivisi da più consumer.
Modificarli richiede quindi attenzione.
Aggiungere un campo facoltativo può essere compatibile se i consumer ignorano ciò che non conoscono.
Anche in questo caso è necessario verificare:
- valori predefiniti;
- gestione dei campi assenti;
- serializzazione;
- validazione.
Rinominare un campo, modificarne il tipo o cambiarne il significato può interrompere i consumer esistenti.
Possibili strategie includono:
- pubblicare una nuova versione dell’evento;
- mantenere temporaneamente entrambe;
- adattare i consumer progressivamente;
- usare un livello di compatibilità;
- definire regole di deprecazione.
In sistemi con molti eventi, un registro degli schemi può aiutare a:
- documentare i contratti;
- validare i messaggi;
- verificare la compatibilità;
- identificare proprietari e versioni;
- limitare modifiche involontarie.
La tecnologia non sostituisce però la governance.
Serve comunque sapere chi può modificare un contratto e chi deve essere coinvolto.
Un evento condiviso crea una dipendenza organizzativa oltre che tecnica.
Per ogni evento dovrebbe essere chiaro:
- quale team lo possiede;
- quale servizio lo produce;
- quale fatto rappresenta;
- quali garanzie offre;
- quanto a lungo viene conservato;
- quali dati sensibili contiene;
- quali modifiche sono compatibili;
- come vengono comunicati i cambiamenti.
Anche la responsabilità dei consumer deve essere esplicita.
Chi interviene quando un consumer accumula ritardo? Chi gestisce la dead-letter queue? Chi decide se un evento possa essere rielaborato?
Senza queste risposte, l’infrastruttura può essere tecnicamente distribuita mentre la responsabilità rimane indefinita.
Un’architettura event-driven può esistere anche all’interno di un’applicazione modulare o tra pochi sistemi.
Allo stesso modo, un’architettura a microservizi può utilizzare prevalentemente comunicazioni sincrone.
I due concetti non sono equivalenti.
È possibile utilizzare eventi per:
- separare moduli interni;
- gestire elaborazioni in background;
- integrare un monolite con servizi esterni;
- alimentare analytics e audit;
- coordinare pipeline di dati;
- propagare cambiamenti a sistemi legacy.
La scelta dovrebbe essere guidata dal flusso e dalle esigenze operative, non dall’etichetta architetturale.
Un broker non trasforma automaticamente un sistema in una piattaforma moderna.
Può anche diventare un ulteriore componente inserito in un’architettura che non ne trae un beneficio concreto.
Considero più ragionevole introdurre eventi quando sono presenti diverse di queste condizioni.
L’attività principale può essere completata anche se alcune elaborazioni secondarie avvengono successivamente.
Il produttore non dovrebbe coordinare direttamente un numero crescente di destinatari.
La velocità di produzione e quella di elaborazione possono differire significativamente.
I sistemi destinatari possono essere isolati attraverso code e retry.
Il fallimento di un consumer non deve necessariamente bloccare gli altri.
I componenti devono poter evolvere senza distribuzioni coordinate continue.
Il team dispone di:
- monitoraggio;
- alert;
- tracciamento;
- procedure di recupero;
- gestione degli schemi;
- responsabilità definite.
La presenza del problema tecnico senza la capacità operativa non è sufficiente.
L’adozione può essere sproporzionata quando:
- esistono soltanto due sistemi;
- il flusso richiede una risposta immediata;
- i volumi sono limitati;
- il processo è breve e lineare;
- l’ordine delle operazioni è rigido;
- non esiste una strategia per duplicazioni e retry;
- nessuno monitora code e consumer;
- il team non ha esperienza con sistemi distribuiti;
- la scelta nasce principalmente dal desiderio di modernizzare lo stack.
In questi casi, una chiamata API ben progettata può essere più affidabile e più facile da mantenere.
La semplicità non è una mancanza di ambizione architetturale.
È una proprietà da preservare finché il problema non richiede qualcosa di diverso.
Adottare un modello event-driven non richiede necessariamente una trasformazione completa.
È possibile iniziare da un confine specifico.
Un primo candidato può essere un’operazione che non deve bloccare la richiesta principale:
- invio di email;
- aggiornamento di analytics;
- generazione di documenti;
- indicizzazione;
- sincronizzazione non immediata.
Questo permette di sperimentare il modello con un impatto limitato.
L’evento dovrebbe rappresentare un fatto chiaro, con un proprietario e un contratto documentato.
È preferibile evitare inizialmente eventi troppo generici come EntityChanged.
Prima di aumentare il numero dei consumer, è utile verificare:
- gestione dei duplicati;
- retry;
- errori permanenti;
- osservabilità;
- rielaborazione.
Fin dalle prime implementazioni devono essere disponibili:
- stato delle code;
- errori;
- ritardi;
- identificativi di correlazione;
- procedure per rilanciare i messaggi.
Dopo le prime adozioni è utile verificare se il modello ha realmente:
- ridotto l’accoppiamento;
- aumentato la resilienza;
- semplificato l’aggiunta di consumer;
- migliorato la gestione dei picchi;
- ridotto le modifiche coordinate.
Se il vantaggio non è evidente, estendere l’architettura potrebbe soltanto amplificare il costo.
Prima di introdurre un evento, considero utile rispondere a queste domande:
- Il produttore deve conoscere il destinatario?
- Ha bisogno di una risposta immediata?
- Il processo può accettare un ritardo?
- Il messaggio può essere elaborato più di una volta?
- L’ordine degli eventi è importante?
- Quale sistema possiede lo stato?
- Come verranno gestiti i fallimenti?
- Come verrà verificato il completamento?
- Chi monitora il consumer?
- Il beneficio supera il costo operativo?
Se le risposte rimangono ambigue, probabilmente non è ancora il momento di scegliere la tecnologia.
Il disegno del processo dovrebbe precedere la configurazione del broker.
Un’architettura event-driven può rendere un sistema più resiliente, estensibile e capace di gestire carichi variabili.
Può anche renderlo più difficile da comprendere.
Il valore non nasce dalla semplice presenza di eventi, topic o code.
Nasce quando l’asincronia risolve un vincolo reale:
- un produttore non deve attendere;
- più consumer devono reagire in autonomia;
- i picchi devono essere assorbiti;
- le indisponibilità devono essere isolate;
- i cicli di evoluzione devono essere indipendenti.
In cambio, il sistema deve accettare e governare:
- duplicazioni;
- consistenza eventuale;
- ritardi;
- fallimenti distribuiti;
- evoluzione dei contratti;
- maggiore complessità operativa.
Per questo considero l’event-driven una scelta architetturale, non una preferenza tecnologica.
Disaccoppiare i sistemi non significa eliminare le relazioni tra loro.
Significa renderle meno dirette e, idealmente, più governabili.
Quando il problema giustifica questo scambio, gli eventi possono produrre un vantaggio significativo.
Quando non lo giustifica, una comunicazione diretta, osservabile e ben progettata rimane spesso la soluzione migliore.