Icon
Icon
2
Last Updates
Icon
New Project
Rebranding Swift Sports with bold visuals and hyper speed interactions.
Mar 12
New Project
Showcasing our latest work for Noire, a brand that breathes fresh life.
Mar 12
New Post
Exploring pixel art aesthetics and code for modern digital experiences.
Mar 12
New Project
A look behind the scenes of the photo shoot that defined a luxury scent.
Mar 12
New Post
Read how our team stays productive and inspired anywhere on the globe.
Mar 12
New Post
Pushing furniture design outside its natural habitat for a unique view.
Mar 12
View all
View all
Icon
Explore our pages
Icon
Home
[01]
About
[02]
Cases
[03]
News
[04]
Contact
[05]
Contact
[05]
Office
149 Zelena St

Lviv, Lviv Oblast 79035
Ukraine

Social
Instagram
LinkedIn
Clutch
Medium

The Power of Events: Event-Driven Patterns in Action (Part 3)

Category:
Articles
Date:
April 14, 2025

Welcome to the third and final part of our series dedicated to Event-Driven Architecture. In the first part (click here to read part 1) we’ve learned about the concept of an event, the advantages and disadvantages of using events in your system, and, most importantly, how to start thinking in terms of events. In the second part (click here to read part 2) we made a deep dive into the topic of storing, propagating, and distributing events. Learned about the common tools (event brokers, event buses, event streams) and their application techniques.

‍

In this article, we are going to step away from the practical aspects of event handling and discuss abstractions. In particular patterns that allow us to build scalable, robust systems, capable of high speed and high availability. We are talking about the fundamental patterns of EDA — Event Notification, Event-Carried State Transfer, Event Sourcing, and CQRS. This time we will not just analyze but also design a full-fledged architecture to show them in action.

‍

Event notification

‍

Let’s start with the most simple one. It’s called Event Notification and is probably familiar to most software developers.

‍

In a nutshell, it’s a basic pub/sub operation.

Publisher raises an event when something significant happens ->

-> subscriber receives the event and decides what to do with it.

‍

An important detail about event notification is that it typically contains only a minimal payload (like an event type and maybe an identifier).

‍

Imagine we have a delivery service. A carrier scans a parcel in a hub to confirm pick-up. At this moment an event is raised in the system that informs that parcel status has changed. Most data about a parcel is already in the system, therefore an event contains only the basic information like new status and probably a timestamp.

‍

This approach has one fundamental flaw. If the subscriber needs some extra data (which is usually the case) it costs an extra queries to the event publisher to fetch more details.

‍

Event-Carried State Transfer

‍

This flaw is covered by Event-Carried State Transfer pattern. Basically, it’s an event-driven approach where events carry all the necessary data for consumers to act without needing additional queries.Let’s say we create an auction app.

There’s an Auction Service with auction_db containing information about competitors, lots, and bids. We would like to inform bidders in case of win-or-lose situations by SMS, messenger app, etc. This is the responsibility of the Notification Service. For that purpose, we raise corresponding win-or-lose events. Competitors want messages to be informative, which means we have to send back a request to the Action Service to give us more data.

‍

To avoid this we can pack everything we need for the notification and send it together with the event payload. In other words, we transfer a state with an event itself.

‍

Event-carried State Transfer is a handy pattern but it brings a few issues you have to keep in mind.

‍

  1. Event payloads can quickly blow up in size. Therefore you have to be careful while designing events to avoid maintainability problems that may come with that.
  2. Data duplication. Imagine you have multiple subscribers, and each of them is going to have their own copy of state. As the system grows it may result in quite an overhead.
  3. Eventual consistency. Having multiple copies of the state means that it’s our responsibility to ensure the data is up-to-date.

‍

Event Sourcing

‍

Unlike the previous two, Event Sourcing is more case-related and in many ways more complex to implement pattern. Most applications persist data in a form state. This state is then updated per request. It is the highest priority for the system to keep the data that presents this state secure and consistent.

‍

But what if instead we will keep a record of every event that occurred in the system and make this sequence of events the backbone of the application and the main source of truce. In this case, a particular state becomes a rather transient thing that can be destroyed and reconstructed on demand. This is the main idea behind Event Sourcing.

‍

In essence, the Event Sourcing pattern stores the entire sequence of events that led to the current state of an entity, instead of just storing the latest state. The system rebuilds the state by replaying these events.

‍

Real-world examples

‍

There are many examples of event-sourced systems. Probably the first one that comes to mind is a banking account. We can check our account balance using the banking app at any time. In essence, this balance is a total of all the debit and credit operations that happened over time.

‍

Blockchain technology is another example of an event-sourced system. Every transaction in a blockchain is an immutable object, and all those transactions are stored in a ledger.

‍

Another popular example of an event-sourced system is VCS. Nowadays every software engineer is familiar with Git. Git is a perfect case of an event-sourced system. The current state of your repository is a result of all the commit history that happened over time.

‍

Snapshotting

‍

One may ask a question: what if our system has to deal with a big volume of data that comes in real-time — hundreds or even thousands of events per minute. If we want to store the entire application event log, won’t this overflow our system in a matter of days/weeks.

‍

In this case, most event-sourced systems use the technique called snapshotting. After a certain period has passed, the old sequence of events is reduced to a single state and from now on it is stored as a sequence of snapshots.

‍

In-memory data models

‍

Disk I/O is usually among the top things that can slow down your web servers. Here Event Sourcing brings another benefit. Considering that the event log is stored on disk (therefore data is persistent and durable) we can move our entire application state to RAM. This allows us to create really high-speed low-latency systems and have easy access to the data.

CQRS

‍

CQRS or Command Query Responsibility Segregation is a pattern that works well with an event-sourced system. However, it is better to hold on to this technique unless it’s really the right case and you know exactly what you are doing.

‍

CQRS is an architectural pattern that separates read and write operations into different models: command model (data modifications only) and query model (read operations only).

‍

This pattern is often misinterpreted with the idea of reporting databases — a secondary database that’s derived from a primary one and is optimized to run reporting queries. In CQRS command and query parts of a system should be distinctively different pieces of software. And, importantly, the command part of the system should not be touched by anything else that’s not related directly to writing into the database.

‍

The main benefit this approach brings is that it allows to optimize each part of the system according to their primary responsibilities independently. The system that’s efficient in writing stuff and the system that is optimized for querying. This also includes scaling command and query parts independently based on their respective workload. This may help to cut hardware costs.

‍

Usually, CQRS systems have some sort of middleware allowing them to split a business logic into two parts. Event brokers, event buses, or event streams work really well for that purpose.

‍

EDA patterns in action

‍

To understand EDA patterns and their application better, let’s do some showcasing.

‍

Imagine we are building a live event ticket explorer that notifies users when tickets for the desired events go on sale.

‍

Functional requirements

‍

  1. The user enters keywords describing what events they are looking for.
  2. Keywords are fragments of unstructured data that may include information like name, type, genre, date, location, etc.
  3. Keywords are accumulated in a database.
  4. The system periodically loads the known keyword base and queries an external API to get up-to-date information about upcoming experiences that match given keywords.
  5. If the search is successful, notify the user via any of the available channels (e-mail, messenger app, etc.).

‍

Non-functional requirements

‍

  1. The system should provide a non-blocking IO.
  2. The system should operate in nearly real-time.
  3. Durability. In case of any failure or data loss, the system should be able to recover to a recent stable state.
  4. The system should log every action.
  5. We want to use microservices architecture because it’s cool.

‍

System design

‍

The system should operate in nearly real time, therefore we need a task manager that will search tickets for us in the background. Let’s define User’s and Task Manager’s responsibilities.

‍

‍

Now let’s define main system components.

Based on use cases we expect to handle the following events: KeywordReceived, SearchTriggered, TicketsFound, and NotificationsSent.

‍

Let’s create the next services: KeywordManager, TaskManager, SearchEngine, NotificationService.

‍

We need the following infrastructure to operate: EventBus, KeywordsDB, and HistoryDB.

‍

Now, let’s think about how can we wire things up to create an effective, fast, and reliable Event-Driven Architecture.

We can highlight 3 flows in this diagram:

‍

Green flow

‍

Core business logic.

‍

The user provides keywords through the KeywordManager service. TaskManager executes a scheduled task that emits the SearchTriggered event. SearchEngine listens to this event and when it occurs, loads keyword data from KeywordsDB. Then it executes the external API to get the latest info (To be honest responses should probably be cached, but let’s skip this for the sake of example). This is a typical example of the Event Notification pattern.

‍

If the response is successful, the info about tickets is packed into the TicketsFound event. NotificationService listens to this event, extracts the data from the event payload, and notifies the user via e-mail, sms, etc. TicketsFound event utilizes an Event-Carried State Transfer Pattern.

‍

If the response is successful, the info about tickets is packed into the TicketsFound event. NotificationService listens to this event, extracts the data from the event payload, and notifies the user via e-mail, sms, etc. TicketsFound event utilizes an Event-Carried State Transfer Pattern.

‍

Red flow

‍

Event history & application log.

‍

To keep track of things we create a data structure called Application Event Log. This could be some kind of Event Stream or other type of storage. Then we subscribe this data structure to the entire traffic that navigates our Event Bus.

‍

We can already see that it brings us quite a few benefits but to utilize them we need to implement the blue flow.

‍

Blue flow

‍

Recoverability and data construction.

‍

Let’s add another service — EventLogKeywordExtractor. TaskManager periodically emits KeywordRefreshRequested events. EventLogKeywordExtractor listens to this event and loads an event log as a stream then extracts info about the relevant keywords.

‍

This data is then populated in a KeywordsDB. KeywordsDB is a transient in-memory storage that we can use to search keywords efficiently. It is fast and lightweight, we can recover it at any point in time using ApplicationEventLog. This is the Event-Sourcing pattern in action.

‍

Even so, now only ApplicationEventLog and EventLogKeywordExtractor service are responsible for all the command operations in the system. The green flow only reads the data that’s being provided and updated by background services which is the showcase of the CQRS pattern.

‍

Conclusion

‍

Event-driven Architecture is a powerful tool that allows you to build scalable, resilient, high-performing, maintainable, and configurable applications. Things like event notifications or event-carried state transfers are pretty common in the modern world and are widely used. Other patterns, event-sourcing and CQRS are more niche and case-related. It’s crucial to understand its concepts, techniques, tools, patterns, use cases, pros & cons as it’s very easy to misuse this paradigm, which may cost you time and money or, in the worst case scenario ruin your application completely. Yet still EDA is something that any mature modern software developer should have in the toolkit.

Found this valuable? Share it forward

Related News

Newsoft at London Tech Week 2026
Events
June 10, 2026
Newsoft at FIBO 2026
Events
April 19, 2026

All news

Subscribe
to our newsletter

You've successfully subscribed
Oops! Something went wrong while submitting the form.
Stay tuned for updates and news coming soon...
PAGES
Home
Home
About us
About us
Our Cases
Our Cases
News
News
Contact
Contact
cases
MedPal AI
MedPal AI
LYMA
LYMA
Underdog
Underdog
Virgin Active
Virgin Active
Socials
Instagram
Instagram
LinkedIn
LinkedIn
Clutch
Clutch
Medium
Medium
NEWSOFT, INC 19 - 26©

We collaborate with ambitious brands and people.

Privacy Policy

Logo
All News