Event Sourcing vs. Event-Driven Architecture
Are they both same? What’s the Difference and Why Use Them?
When building modern systems, particularly in a microservices environment, you’ll often hear two terms: Event Sourcing and Event-Driven Architecture. At first glance, they may seem similar, but they serve different purposes. Why do we have both, and how do they differ from traditional architectures? In this blog, we’ll explore these concepts in an interactive and engaging way, using a Product and Order API example to help you understand the key differences and benefits.
Embark on a journey of continuous learning and exploration with DotNet-FullStack-Dev. Uncover more by visiting our https://dotnet-fullstack-dev.blogspot.com reach out for further information.
1. What is Event-Driven Architecture?
Event-Driven Architecture (EDA) is a design pattern where events are used to trigger and communicate between decoupled services. Events are essentially state changes or actions that happen in the system, like a user placing an order or a product being added to a catalog.
Interactive Thought:
Think of an event as a knock on the door — when someone knocks, it’s a signal for you to respond. It’s the same in EDA: an event occurs, and the system reacts.
In an event-driven system, services publish events when something important happens, and other services subscribe to those events to take action. This creates a highly decoupled system where services don’t directly communicate with each other but rather through events.
For detailed event-driven implementation can refer: https://medium.com/@dotnetfullstackdev/building-an-event-driven-order-processing-application-in-c-6edcb70df524
2. What is Event Sourcing?
Event Sourcing, on the other hand, is a data persistence pattern where changes to an application’s state are stored as a sequence of events. Instead of storing the current state of the data (as in traditional architectures), event sourcing stores every event that changes the state.
Interactive Insight:
Imagine you have a notebook, and every time you change something (like updating a product price or order status), you write it down. If you want to know the current state of an order or product, you go through the entire list of changes and “replay” them to get the final result.
3. Are Event Sourcing and Event-Driven the Same?
While both patterns revolve around events, they are not the same:
- Event-Driven Architecture focuses on how services communicate and react to events.
- Event Sourcing focuses on how data changes are stored and tracked over time.
An event-driven system could use event sourcing as its data persistence model, but it’s not required. You could also have a traditional database with event-driven architecture, where events simply trigger actions without storing every state change.
4. Why Do We Have Both?
You might wonder, “If both deal with events, why have two concepts?” Here’s why:
- Event-Driven Architecture is about communication: It helps microservices or distributed systems stay decoupled while allowing them to react to important actions (events).
- Event Sourcing is about data persistence: It captures every state change as an event, providing a full history of changes that can be replayed, audited, or used for debugging.
Both are valuable but serve different roles in your system.
5. How Does This Compare to Traditional Architecture?
Traditional architectures typically store only the current state of the data, without retaining the historical state. This makes it hard to audit or reconstruct how the system reached its current state.
For example, in a Product API and Order API, if you wanted to see how many price changes a product has had over time or when an order changed status, you would either:
- Store an additional audit trail manually (in a relational database), or
- Simply overwrite the data, losing historical changes.
In an event-sourced system, every state change (event) is preserved, and you can replay events to recreate any past state.
6. Example: Product and Order APIs
Let’s take an example of a Product API and an Order API. In a traditional architecture, your database would only store the current state:
- Product Table: Stores the current product information (like product name, price, quantity).
- Order Table: Stores the current state of orders (like order ID, status, total amount).
If you were to update the price of a product, you would simply update the price in the product table, overwriting the old value. If you wanted to track historical price changes, you’d have to implement a custom solution like an audit table.
In Event Sourcing, every price change is stored as an event:
- Event: Product price updated.
- Event: Product description updated.
- Event: Order placed.
- Event: Order shipped.
Each of these events captures what happened rather than just the end state. You can replay these events to see how the state evolved.
Interactive Example:
Let’s say you have a Product API with event sourcing. Here’s what it might look like:
public class ProductUpdatedEvent
{
public Guid ProductId { get; set; }
public string Name { get; set; }
public decimal NewPrice { get; set; }
public DateTime Timestamp { get; set; }
}
// Storing the event
public void UpdateProductPrice(Guid productId, decimal newPrice)
{
var productEvent = new ProductUpdatedEvent
{
ProductId = productId,
NewPrice = newPrice,
Timestamp = DateTime.Now
};
// Store this event (e.g., in an event store)
eventStore.AppendEvent(productEvent);
}
// Replaying the events
public Product ReplayProductEvents(Guid productId)
{
var events = eventStore.GetEventsForProduct(productId);
Product product = new Product();
foreach (var evnt in events)
{
product.ApplyEvent(evnt);
}
return product;
}
Every time you update a product, you store the event rather than overwriting the data. You can replay those events to rebuild the state of the product at any given time.
In an event-driven architecture, when a product price changes, it triggers an event:
public class ProductPriceChangedEvent
{
public Guid ProductId { get; set; }
public decimal OldPrice { get; set; }
public decimal NewPrice { get; set; }
}
// Publishing the event
public void NotifyPriceChange(Guid productId, decimal oldPrice, decimal newPrice)
{
var priceChangedEvent = new ProductPriceChangedEvent
{
ProductId = productId,
OldPrice = oldPrice,
NewPrice = newPrice
};
eventBus.Publish(priceChangedEvent);
}
The Order API subscribes to this event, so if the product price impacts any orders, it can react accordingly.
7. How Event Sourcing and Event-Driven Architecture Work Together
Now, let’s put it all together. In your Product API and Order API:
- Event Sourcing tracks every change to the product (price changes, stock updates).
- Event-Driven Architecture allows the Order API to react to those changes. For example, if a product price changes, the Order API can revalidate or adjust affected orders.
In essence, event sourcing stores the facts, while event-driven ensures that services know about and react to those facts.
8. The Benefits of Event Sourcing and Event-Driven Architecture
- Auditability: With event sourcing, you can always track why and how something happened.
- Decoupling: Event-driven architectures decouple your services, making them more maintainable and scalable.
- Rebuildability: In event sourcing, you can replay events to recreate a state from any point in time.
- Flexibility: Event-driven systems allow you to easily add new functionality (e.g., notifications) by just subscribing to events.
9. Wrapping Up
Event Sourcing and Event-Driven Architecture might sound similar, but they serve different purposes. Event sourcing is about storing every state change, while event-driven architecture is about how services communicate in a decoupled way. Together, they form a powerful combination for building scalable, auditable, and maintainable systems.
In this blog, we explored how you can use these patterns with a Product API and Order API to manage changes and notify services. Whether you’re building an ecommerce platform or any other complex system, these patterns will help you design more robust, fault-tolerant systems.
So, are you ready to adopt event-driven or event-sourced architectures in your projects? What other examples would you like to explore? Let’s discuss!
By leveraging these patterns, you can design systems that are more resilient and adaptable to change. Dive in and start experimenting with Event Sourcing and Event-Driven Architecture to see the benefits for yourself!