iTranslated by AI
Learning Architecture with the Owl #4: Event-Driven Architecture (EDA / CQRS / Event Sourcing)
This article is a record of personal knowledge and learning, and does not represent the views of my affiliated organization.
🦉 Learning Architecture with the Owl #4
Event-Driven Architecture (EDA) ─ A Paradigm Shift: Looking at "Changes" Instead of "States"
Our software architecture journey has reached page 4.
So far, we have progressed through Layered → Domain-Centric → Microservices, and we have finally become capable of handling "distribution" and "boundaries."
The star of this page is a concept that takes abstraction one step further:
Event-Driven Architecture (EDA).

In a nutshell, EDA is:
An architecture that treats "the moment a state changes" rather than the "state" itself.
Adopted by large-scale services like Slack, Uber, Netflix, and Amazon, this "event-driven" philosophy is also said to be highly compatible with the era of AI agents.
Let's dive in together.
1. What is Event-Driven? ─ Focusing on "Change" Rather Than State Itself
Layered and Clean Architecture were mainly about how to organize structure.
Microservices were about how to define responsibilities and boundaries.
Event-Driven is a bit different in direction.
It is an idea that changes the very "way an application moves."
■ The Simplest Form of EDA
- Something happens (= an event)
- Services subscribing to it react
- Next events are generated
- ...The system operates through this chain reaction

Common Examples of Events
- "Order placed"
- "Inventory decreased"
- "Payment completed"
- "User logged in"
- "AI agent completed a task"
Netflix's recommendations, Uber's location-based updates, and Slack's real-time notifications all have countless events flowing through their systems internally.
2. Changing the World by Abandoning "Synchronicity": Why EDA Was Born
Conventional services used to communicate like this:
Order Service: "Is there inventory?"
Inventory Service: "Yes, there is."
Order Service: "Okay, then I'll confirm the order."
In other words, it is synchronous (waiting for a response).
However, as the number of services grows, this expands into problems such as:
- If Service A goes down, B also stops
- Dependencies call other dependencies, leading to complex connections
- Traffic spikes cause immediate slowdowns
- It becomes unclear where to scale
This is where the following emerged:
"Instead of asking, just broadcast what happened."
This is the world of asynchronous coordination.

As mentioned in Netflix's internal documentation,
"How loosely you can couple services" is the lifeline for operation and scalability.
3. The 3 Keywords Constituting EDA
In this article, we will focus on these three:
-
EDA (Event-Driven Architecture)
└ A method of linking services based on changes (events) -
CQRS (Command Query Responsibility Segregation)
└ Scaling by separating models for reading and writing -
Event Sourcing
└ Saving the "history of events" itself instead of the "current state"
While these three are distinct, they maximize their effectiveness when combined.
(By the way, things like Slack's Audit Logs, Box's event logs, and GitHub's Webhooks are close to the philosophy of Event Sourcing.)
4. CQRS ─ Reading and Writing Have Fundamentally Different Natures
CQRS is an "EDA power-up component."
A typical CRUD model looks like this:
A single model handles:
・Writing (Command)
・Reading (Query)
Both responsibilities.
However, as applications scale, you face problems like these:
- The system doesn't scale because the reading load increases too much
- Write operations are complex and slow
- Aggregation views become increasingly heavy
So, we take the plunge and separate them:
Let's keep the write model and read model separate
(= Command Model / Query Model)
A simple Python example (excerpt):
# Writing (Command)
service.create_order(order_id, items)
# Reading (Query)
order = query_model.get_order(order_id)
If you are creating a GitHub sample, a structure like samples/event-driven/cqrs-basic is suitable.
5. Event Sourcing ─ Saving "History" Instead of "Current State"
Event Sourcing is even bolder.
Conventional Storage Method
Saving only the "current state" (One row in an RDB is always the latest state)
Event Sourcing Method
Persisting the "history of how the state has changed"
Example: Suppose an order's state transitioned like this
- Order created
- Payment completed
- Inventory reserved
- Shipped
With Event Sourcing, we save every single one of these.
Why is this beneficial?
- State can be reconstructed (resilient to failures)
- Aggregation and audit trails are extremely easy to obtain
- Multiple read views (Projections) can be created flexibly
- Time-series analysis (highly compatible with AI analysis)
It is well known that Slack uses a design where "everything is treated as an event." It is also highly compatible with AI agents because the event logs serve as "learning data."

6. The "Golden Combo" of EDA + Microservices
Event-driven can be used on its own, but it is extremely powerful when combined with microservices.
How EDA Solves Microservices Problems
- Excessive communication problem → Absorbed by asynchronous processing
- Spaghetti dependency relationships → Loosely coupled via an event hub
- Unclear scaling points → Independent scaling for each event consumer
- Fault propagation → Buffered via event queues
Uber's dispatch system, Netflix's streaming processing, and Amazon's order processing all have event-driven architecture at their core.
The sample code for this article also uses an EventBus → Consumer loosely coupled configuration, making it easy to visualize structural changes when moving to microservices.
Experiencing Mini Event-Driven in Python (Sample Excerpt)
This code excerpt is a minimal example for conceptual understanding. The GitHub repository contains a complete sample where the EDA event chain—including Billing, Inventory, and Notification—actually runs.
samples/
event-driven/
simple-eda/
event_bus.py
producers/
consumers/
domain/
Here is an excerpt:
# event_bus.py
class EventBus:
def __init__(self):
# Simple in-memory management: {event_type: [handlers]}
self.subscribers = {}
self.event_log = [] # ← The GitHub version also includes event logs for a minimal Event Sourcing experience
def publish(self, event):
# Save the published event to the log and notify subscribers
self.event_log.append(event)
for handler in self.subscribers.get(type(event), []):
handler(event)
def subscribe(self, event_type, handler):
# Register subscription (multiple handlers can be attached)
self.subscribers.setdefault(event_type, []).append(handler)
While the basic "Publish → Subscribe" works with just this excerpt, in the actual GitHub sample, Billing, Inventory, and Notification react in a chain, reproducing the flow of OrderCreated → PaymentSucceeded → InventoryReserved → OrderCompleted.
Referencing this will deepen your understanding of event chaining.
When Should You Adopt EDA?
| Perspective | Cases Suitable for EDA | Cases to Avoid / Proceed with Caution |
|---|---|---|
| Event Volume / Update Frequency | SaaS, EC, and dispatch systems with constant logs/updates | Daily batch-centric, few transactions |
| Feature Change Frequency | Frequent changes in domain or flow | Business logic that rarely changes |
| Consistency Requirements | Eventual consistency is acceptable | Strong consistency required (e.g., payment master ledgers) |
| Observability / Audit | Audit logs and tracing are important | Log requirements are not that strict |
| Operational Foundation | Can operate Kafka / SNS+SQS, etc. | Cannot maintain or struggle to operate message infrastructure |
✔ Scenarios where adoption is suitable
- Services where large volumes of events (logs/updates) fly around
- Products with many frequently changing features
- Where observability and audit trails are critical (Finance, SaaS)
- Handling execution logs for AI agents
- When coexisting with microservices
✖ Scenarios better to avoid
- Small-scale, sync-centric services
- When you need to keep consistency simple (strong consistency is mandatory)
- Monoliths with low event volume
- Environments where you cannot maintain operational infrastructure (like Kafka)
EDA is powerful, but it is not a "magic wand that should be applied to every system."
Summary
Seeing Events Changes the World
When you actually run the GitHub sample, you can experience the "satisfaction" of EDA: processes chain together even though the code segments never call each other directly.
Event-Driven Architecture is more than just a technique. It is a paradigm that "changes the way you look at things themselves."
- Handle changes, not states
- Use asynchronous as the standard, not synchronous
- Persist history, not models
- Focus on flow, not individual services
In the next page, we will explore how this event-driven approach connects to Cloud-Native and the control planes of the AI agent era.
The journey of you and the owl continues. 🦉
Mini Glossary
Event
Information representing the fact that something happened.
EDA (Event-Driven Architecture)
An architecture where services are linked around events.
CQRS
A design that separates reading (Query) and writing (Command).
Event Sourcing
A method of persisting event history itself and reconstructing the state from that history.
Projection
A view for reading created from Event Sourcing event groups.
Event Bus / Event Hub
A mechanism for distributing and relaying events. Kafka / SNS+SQS are representative examples.
The EventBus in this article's GitHub sample is a "minimal configuration version"; replacing it with Kafka or Pub/Sub is the development path for real-world services.
Discussion