iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🦉

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 LayeredDomain-CentricMicroservices, 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).

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

EDA-simple

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.

Sync vs Async

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.

  1. EDA (Event-Driven Architecture)
    └ A method of linking services based on changes (events)

  2. CQRS (Command Query Responsibility Segregation)
    └ Separating reading and writing models to scale effectively

  3. 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."

EDA


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