Hey everyone 👋
Today, we’re diving into one of my favourite software architecture topics, Event-Driven Architecture (EDA). It’s one of those patterns that sounds a bit fancy at first, but once you understand it, you start seeing it everywhere: in cloud applications, microservices, and even your daily notifications!
Let’s break it down step by step. ☕
🧩 What Is Event-Driven Architecture?
At its core, Event-Driven Architecture is all about reacting to events.
An event is simply something that happened, for example:
- An order was placed 🛒
 - A payment was completed 💳
 - A user logged in 👤
 
Instead of having tightly coupled services that directly call each other (as in layered or traditional microservice architectures), EDA uses events as the main f…
Hey everyone 👋
Today, we’re diving into one of my favourite software architecture topics, Event-Driven Architecture (EDA). It’s one of those patterns that sounds a bit fancy at first, but once you understand it, you start seeing it everywhere: in cloud applications, microservices, and even your daily notifications!
Let’s break it down step by step. ☕
🧩 What Is Event-Driven Architecture?
At its core, Event-Driven Architecture is all about reacting to events.
An event is simply something that happened, for example:
- An order was placed 🛒
 - A payment was completed 💳
 - A user logged in 👤
 
Instead of having tightly coupled services that directly call each other (as in layered or traditional microservice architectures), EDA uses events as the main form of communication.
Here’s where the magic happens ✨: In EDA, each service acts independently. When something happens, a service simply publishes an event, it’s like saying:
“Hey, an order was placed!”
But here’s the cool bit: the service that emits the event doesn’t know (or care) who is listening, when they’ll react, or how they’ll process it.
That’s a big contrast to traditional architectures, where services often directly call one another through APIs.
EDA, on the other hand, is asynchronous and decoupled. Services communicate via an event broker (or message queue), meaning they’re completely independent; they just publish events into a queue without caring who processes them later.
💡 Why EDA Matters
This independence makes EDA: ✅ Highly scalable ✅ Fault-tolerant ✅ Easier to evolve over time
But it’s not always simple. While EDA offers powerful flexibility, it also introduces complexity. So before jumping in, we need to answer a few important questions 👇
🧠 Key Questions to Understand EDA
- What’s the difference between an event and a message?
 - How do we ensure no data loss?
 - How many brokers or queues do we need?
 - How do we track state across multiple services?
 
Let’s explore each one.
🔁 Events vs. Messages
In EDA, the main concept is an event.
When an event is raised, we don’t care who processes it or when. The system just publishes the event, fire and forget. 🔥
- Events: Fire and forget. The publisher emits and moves on.
 - Messages: Commands or queries, requests that expect a result.
 
So, in message-driven architecture, a message waits for a response, while in event-driven architecture, we publish and continue working asynchronously.
Most EDA systems use a Pub/Sub pattern, one service publishes events and others subscribe to them. In contrast, message-driven systems usually use point-to-point communication since the sender knows exactly which service should handle the message.
🧱 Ensuring No Data Loss
One of the biggest challenges in EDA is data integrity.
Imagine this:
- A service publishes an event to a queue, but right after that, the queue crashes, and the event is gone! 😱
 - Or maybe the consumer reads the event but fails before saving it to the database, and the data is lost again!
 
To prevent this, we can use the Event Forwarding Pattern 🛡️
Here’s how it helps:
- Persist Events, Before a service sends an event to the queue, it first persists it in durable storage.
 - Recover Gracefully, If a service crashes after reading an event, it can re-fetch it later because the queue retained a persisted copy.
 - Track Consumers, Store client IDs so each service knows which messages it has processed.
 - Confirm Completion, After saving to the database, the service confirms success so the event can safely be removed from the queue.
 
This ensures strong data integrity ✅, but it comes with trade-offs:
- Lower performance (because of synchronous writes)
 - Possible duplicate data
 
So, use this approach when data reliability is more important than throughput.
🏗️ How Many Brokers Do We Need?
Good question! Should each microservice have its own broker, or should they all share one?
Let’s look at the concept of Architectural Quantum, introduced in Building Evolutionary Architectures 🧠
An Architectural Quantum is an independently deployable component with high functional cohesion that includes everything needed for the system to work properly.
If all services depend on a single broker, then if that broker goes down, everything goes down. This means the entire system is one single architectural quantum.
But if each service has its own broker, then you have multiple independent systems, more resilient, but also more expensive 💸.
A balanced approach is the Domain Broker Pattern:
- Each domain gets one broker.
 - Services within a domain share the same broker.
 - Domains remain independent of one another.
 
This gives you a nice balance between cost and independence.
🔍 Managing State in EDA
Tracking the state of an entity (like an order) across distributed services can be tricky. Let’s say you have:
- An Order Service 🛒
 - An Inventory Service 📦
 - A Delivery Service 🚚
 
When a user asks, “What’s the status of my order?”, where should we look?
There are two main patterns for managing state:
1️⃣ Push-Based Pattern
Each service writes status updates to a shared queue. The Order Service listens to this queue and keeps the latest status in its database.
✅ Pros:
- Centralized status tracking
 - Easy to query
 
⚠️ Cons:
- All services depend on one queue → Architectural quantum = 1
 - A single failure can bring down the whole system
 
2️⃣ Pull-Based Pattern
In this model, a separate Status Service listens to events from all brokers. It collects and stores the latest status for each order.
✅ Pros:
- No shared dependency, more resilient
 - Central point for querying order status
 
⚠️ Cons:
- Requires building and maintaining an extra service
 
🏁 Final Thoughts
Event-Driven Architecture is incredibly powerful; it enables scalable, resilient, and decoupled systems. But like any architecture, it’s not a one-size-fits-all solution.
EDA shines when:
- You have many independent services that react to real-time changes
 - You need asynchronous communication
 - You care more about flexibility and responsiveness than strict performance
 
However, it adds complexity in state management, data integrity, and broker design, so plan carefully before adopting it.
Thanks for reading! 🙌 If you found this useful, don’t forget to share it with your fellow developers and let’s keep learning together 💬