iTranslated by AI
Learning Architecture with an Owl #4: Event-Driven Architecture (EDA / CQRS / Event Sourcing)
Note: This article is a record of personal knowledge and learning and does not represent the views of any organization I belong to.
🦉 Learning Architecture with an Owl #4
Event-Driven Architecture (EDA) — Shifting the Focus from "State" to "Change"
Our journey through software architecture has reached page 4.
So far, we have progressed through Layered → Domain-Centric → Microservices, and we've finally become able to handle "distribution" and "boundaries."
The protagonist this time is a world where the level of abstraction goes up one step further—
Event-Driven Architecture (Event-Driven Architecture: EDA).

If I were to describe EDA in one sentence:
An architecture that handles the "moment the state changes" rather than the "state" itself.
This event-driven concept is adopted by large-scale services like Slack, Uber, Netflix, and Amazon, and is said to be highly compatible with the era of AI agents.
Now, let's take a look together.
1. What is Event-Driven Architecture? — Centering on "Change" rather than State itself
Layered or Clean Architecture was mainly about how to organize structurally.
Microservices was about how to cut responsibilities and boundaries.
Event-driven takes a slightly different direction.
It is an idea that changes how the application "moves" itself.
■ The Simplest Form of EDA
- Something happens (= event)
- Services subscribing to it react
- Generate the next event
- ...the system moves through this chain of events

Examples of Common Events
- "Order placed"
- "Stock decreased"
- "Payment completed"
- "User logged in"
- "AI agent completed a task"
In services like Netflix recommendations, Uber location tracking, or Slack real-time notifications, countless events are flowing inside the system.
2. Stop "Syncing" and the World Changes: Why Event-Driven was Born
Traditional services used to have conversations like this:
Order Service: "Is it in stock?"
Inventory Service: "Yes, it is."
Order Service: "Okay, then confirm the order."
In other words, it's synchronous (waiting for a response).
However, as the number of services increases, this grows into the following problems:
- If service A is down, B also stops
- Dependencies call more dependencies, leading to complex connections
- When traffic concentrates, it slows down all at once
- It's unclear where scaling is needed
That's where this appeared...
"Instead of making inquiries, we can just broadcast what happened."
This is the world of asynchronous collaboration.

As mentioned in Netflix's internal documents,
"how loosely you can couple services" is the lifeline for operations and scalability.
3. The Three Keywords of EDA
This article will focus on these three keywords.
-
EDA (Event-Driven Architecture)
└ A method of linking services based on changes (events) -
CQRS (Command Query Responsibility Segregation)
└ Separating reading and writing models to scale effectively -
Event Sourcing
└ Saving the "history of events" itself, rather than the "current state"
These three are separate things, but they deliver their maximum effect when combined.
(By the way, Slack's Audit Logs, Box's event logs, and GitHub's webhooks are also close to the philosophy of Event Sourcing.)
4. CQRS — Reading and Writing Are Inherently Different
CQRS is a "power-up device" for event-driven systems.
A standard CRUD model looks like this:
A single model handles both
・Writing (Command)
・Reading (Query)
However, as systems grow in scale, they face the following problems:
- Read load increases disproportionately and fails to scale
- Write processing becomes complex and slow
- Aggregated views become increasingly heavy
So, we take the plunge and separate them.
0 Let's maintain separate models for writing and reading
(=Command Model / Query Model)
Simplified Python example (Excerpt):
# Writing (Command)
service.create_order(order_id, items)
# Reading (Query)
order = query_model.get_order(order_id)
If you are providing a sample on GitHub, a structure like samples/event-driven/cqrs-basic is suitable.
5. Event Sourcing — Saving the "History" Instead of the "State Itself"
Event Sourcing is even more daring.
Standard Storage Method
Saves only the "current state" (a single row in an RDB always represents the latest state).
Event Sourcing Method
Persists the "history of how the state has changed."
Example: Suppose an order status changes as follows:
- Order created
- Payment completed
- Inventory secured
- Shipped
In Event Sourcing, each of these steps is saved.
What are the benefits?
- 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)
Slack is famous for its design that "treats everything as an event."
It also has excellent compatibility with AI agents because event logs become "training data."

6. The "Golden Combo" of EDA + Microservices
Event-driven can be used on its own, but it is extremely powerful when paired with microservices.
EDA Solves Microservice Problems:
- Excessive communication → Absorbed by asynchronization
- Spaghetti dependencies → Decoupled via an event hub
- Unclear scaling points → Scale independently for each event consumer
- Failure propagation → Buffering with event queues
Uber's dispatch system, Netflix's streaming processing, and Amazon's order processing all have event-driven at their core.
The sample code in this article also adopts a loosely coupled configuration of EventBus → each Consumer, making it easy to visualize the structural changes when moving to microservices.
Mini Event-Driven Experience with Python (Sample Excerpt)
The code excerpts in this article are minimal examples for conceptual understanding.
On GitHub, I have placed a complete sample where event chains for Billing, Inventory, and Notification actually work.
samples/
event-driven/
simple-eda/
event_bus.py
producers/
consumers/
domain/
I will introduce only the excerpts.
# event_bus.py
class EventBus:
def __init__(self):
# Simple in-memory management of {event_type: [handlers]}
self.subscribers = {}
self.event_log = [] # ← The GitHub version also has an event log for a minimal experience of Event Sourcing
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):
# Subscription registration (allows multiple handlers)
self.subscribers.setdefault(event_type, []).append(handler)
While the basics of "Publish → Subscribe" work even with the excerpt in this article,
the actual GitHub sample reproduces a flow where Billing, Inventory, and Notification react in a chain: OrderCreated → PaymentSucceeded → InventoryReserved → OrderCompleted.
Referencing this will deepen your understanding of event chains.
When Should You Adopt EDA?
| Perspective | Cases Suitable for EDA | Cases Not Suitable / Should Be Cautious |
|---|---|---|
| Event Volume / Update Frequency | SaaS, EC, and ride-hailing systems with constant logs/updates | Centered on daily batches, low transaction volume |
| Frequency of Feature Changes | Domains or flows change frequently | Operations with almost no changes |
| Consistency Requirements | Eventual consistency is sufficient | Strong consistency is always required (e.g., payment ledgers) |
| Observability / Audit | Audit logs and tracking are critical | Log requirements are not that strict |
| Operational Infrastructure (Messaging) | Able to operate Kafka / SNS+SQS, etc. | Cannot have a message infrastructure / difficult to operate |
✔ Scenarios Suitable for Adoption
- Services with a high volume of events (logs and updates)
- Products with many frequently changing features
- Where observability and audit trails are critical (Finance, SaaS)
- Handling task execution logs for AI agents
- When coexisting with microservices
✖ Scenarios Best Avoided
- Small-scale, synchronous-centric services
- When you want 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 bullet to be applied to every system."
Summary
Changing Your Perspective Changes the World
By actually running the GitHub sample, you can experience the "satisfaction" of EDA, where processes chain together even though code components never call each other directly.
Event-driven architecture is not just a technology. It is a paradigm that "changes the way you look at things."
- Handle changes instead of states
- Base everything on asynchrony instead of synchrony
- Store history instead of models
- Focus on the flow instead of individual services
In the next page, we will explore how this event-driven approach connects to cloud-native architectures and the control plane of the AI agent era.
The journey for you and the owl continues 🦉
Terminology Mini Dictionary
Event
Information representing the fact that something occurred.
EDA (Event-Driven Architecture)
An architecture that links services centered 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 read-only view created from a collection of events in Event Sourcing.
Event Bus / Event Hub
A mechanism for distributing and relaying events. Representative examples include Kafka and SNS+SQS.
In the GitHub sample of this article, the EventBus is a "minimal version." Moving from here to Kafka or Pub/Sub is the evolution path toward actual production services.
Discussion