Il problema: catene di chiamate rigide
Quando un utente si registra, il sistema deve: inviare l'email di benvenuto, creare il profilo default, notificare il team di vendita, aggiornare le statistiche, attivare il periodo di prova. Il controller chiama cinque servizi in sequenza. Se aggiungi un sesto step (integrazione CRM), devi modificare il controller. Se il servizio email e lento, rallenta tutto. Se fallisce, blocca i passaggi successivi. Le dipendenze crescono linearmente con le funzionalita.
L'architettura event-driven inverte il flusso: il controller fa una sola cosa — registra l'utente e pubblica un evento UserRegistered. Ogni componente interessato reagisce all'evento indipendentemente. Il controller non sa quanti listener ci sono, ne cosa fanno. I listener non si conoscono tra loro.
Concetti fondamentali
Evento: un fatto accaduto
Un evento e un fatto immutabile che descrive qualcosa che e già successo: OrderPlaced, PaymentReceived, ArticlePublished. Non e una richiesta ("fai qualcosa") ma una notifica ("e successo qualcosa"). Questa distinzione e fondamentale: l'emittente non si aspetta una risposta e non sa chi sta ascoltando.
Producer e Consumer
Il producer emette l'evento. Il consumer (listener/subscriber) reagisce. Un evento può avere zero, uno o molti consumer. Aggiungere un consumer non richiede modifiche al producer. Rimuoverne uno non rompe nulla.
Esempio teorico: ciclo di vita di un ordine
-
OrderPlaced→SendOrderConfirmationListenerinvia l'email,ReserveInventoryListenerblocca lo stock,NotifyWarehouseListenerprepara la spedizione,UpdateDashboardListeneraggiorna le metriche -
PaymentReceived→ConfirmOrderListeneraggiorna lo stato,GenerateInvoiceListenercrea la fattura -
OrderShipped→SendShippingNotificationListenernotifica il cliente,StartDeliveryTrackingListenerattiva il tracking
Ogni listener e una classe isolata, testabile, che fa una sola cosa. Aggiungere un'integrazione con un nuovo sistema di analytics? Crei un listener, lo registri sull'evento, e tutto funziona senza toccare il codice esistente.
Sincrono vs Asincrono
- Sincrono: i listener vengono eseguiti nella stessa request. Semplice, ma se un listener e lento, rallenta la response. Adatto per operazioni veloci e critiche (validazione, aggiornamento stato).
- Asincrono: i listener vengono accodati (Redis, RabbitMQ, database) e eseguiti da worker separati. Non rallenta la response. Adatto per operazioni lente (email, PDF, integrazioni esterne) o non critiche.
In pratica, la maggior parte dei sistemi usa un mix: alcuni listener sincroni per le operazioni critiche, altri asincroni per il resto.
Event-Driven in Soft PHP MVC
Il framework usa eventi tramite l'Observer Pattern nei Model: i lifecycle hooks (beforeSave, afterSave, beforeDelete) sono eventi sincroni che permettono di reagire ai cambiamenti delle entita. Il CacheObserver invalida la cache quando un articolo viene modificato — senza che il Model sappia che la cache esiste.
Quando usare Event-Driven Architecture
- Usa eventi quando un'azione ha effetti collaterali che non sono responsabilità del componente che la esegue
- Usa eventi quando vuoi che nuove funzionalita possano "agganciarsi" senza modificare il codice esistente
- Usa eventi quando il disaccoppiamento tra componenti e una priorità
- Non usare eventi per flussi lineari semplici dove una chiamata diretta e più chiara
- Non usare eventi se il debugging e già difficile: gli eventi rendono il flusso meno tracciabile
L'architettura event-driven non e un'alternativa a MVC o Hexagonal: e un principio di comunicazione che si applica dentro qualsiasi architettura. Quando i componenti reagiscono a fatti invece di essere chiamati direttamente, il sistema diventa più flessibile, più estensibile e più resiliente.
Top comments (0)