Five Common Misconceptions About Event-Driven Architecture
An opportunity for everyone to do a little self-test. Do you believe any of these five statements? If so, don’t worry, you’re not the only one, I’ve come across them many times. I’m very convinced they’re untrue, though. This is my humble attempt to improve our shared understanding of some properties of event-driven architecture.
EDA means Event Sourcing
Well, it doesn’t. Event sourcing is an approach to persisting data within a service. Instead of writing the current state to the database, and updating that stored data when the state changes, you store an event for every state change. The state can then be restored by replaying the events.
Event-driven architecture is about communication between services. A service publishes any changes in its subdomain it deems potentially interesting for others, and other services subscribe to these updates. These events are carriers of state and triggers of actions on the subscriber side.
While these two patterns complement each other well, you can have either without the other.
You can have an event-driven architecture consisting of multiple microservices, where none of them uses event sourcing. Maybe they all use CRUD operations on their relational database to persist state. They might still use e.g. a transactional outbox and publish all changes as events, for other services to subscribe to. An architecture that makes a lot of sense, if you want to get the benefits of event-driven architecture, but for some reason don’t think you’d profit from event sourcing, or feel you’re not ready for it.
Conversely, wherever you persist application state to a data store, you can do it with event sourcing. In a monolithic application, on in a single service in your microservices system. Or in all of them, but that’s a per-service decision - if you do it in one, it does not affect the others.
EDA and using Kafka are equivalent
Apache Kafka is a log-based message broker that’s very popular in event-driven systems. Log-based message brokers are a good architectural fit for event-driven architecture.
But for Kafka, whatever you send is just a “record”. A byte array. If you use it to publish events, commands, queries, or some other type of message no one has even thought of yet - Kafka doesn’t care. In this regard, the labeling on its home page, “Kafka is an open-source distributed event streaming platform”, is a bit misleading. That’s certainly the intended usage (and it should probably make you think if you use it in another way), but nothing is preventing you from using it differently. Trekking gear is made for hiking, but nothing stops you from wearing it in the office (physically, I mean, not accounting for dress codes).
Just as you can use Kafka without being event-driven, you can build an event-driven architecture without Kafka. And I’m not only talking about “Kafka replacements”, i.e. other log-based message brokers. I don’t know why you’d want to, but you could use a store-and-forward message queue (like ActiveMQ or RabbitMQ) for your eventing. You could even do it without any messaging infrastructure at all, e.g. by implementing HTTP feeds.
Just because you could, doesn’t mean you should! A log-based message broker is most likely the best approach for you, too, if you want an event-driven architecture. But it’s not the tool that makes it event-driven. It’s the semantics of your messages, and the flow of them through your system - see the next point.
EDA is only about the message naming/semantics
What makes a message an event? That it describes a fact, something that happened. E.g. “ShipItem” is a command. “OrderConfirmed” is an event.
This is true, but if you only focus on the semantics of your individual messages, without looking at the overall flow, you might fool yourself.
Look at the image below. Technically, all these messages are events. But each of the events has exactly one subscriber, and that subscriber will in turn emit an event that the original publisher subscribes to.
This is really a request-response flow. For example, the order service commands the inventory service to reserve an item. The fact that it phrases its question differently, as a statement, doesn’t make the system event-driven. For these messages, that look like events but really expect a specific recipient to carry out an action, Martin Fowler coined the term “passive-agressive commands”.
If you want to explore this further, I encourage you to watch my recent talk “The Unreasonable Effectiveness of Events” (Video, Slides), where I speak about this in detail.
EDA only makes sense when everything is event-based
Your application provides a REST API for the frontend? Surely that’s not event-driven. But that doesn’t mean you can’t build an event-driven architecture in the backend. If your backend system consists of multiple services, you can still leverage event-driven architecture to achieve better scalability and resilience (as being event-driven will remove any runtime dependency between your services).
In fact, it’s very common to build systems where only the inter-service communication within the system is completely event-driven, while communication with the “outside” world uses other patterns. This can be for the user interface, or for the integration of third-party systems, where you have to make do with whatever interfaces they offer, and those might not be event-driven. But don’t let this deter you from designing the communication between the services you implement in an event-driven way.
(You can read more about this in last month’s blog post “Event-Driven Core, Request-Response Shell”).
EDA is inherently complex
Ok, it’s more complex than a small, non-distributed application (a small monolith, if you will).
But so are microservices. Once you enter microservices land, to support autonomous development and operations across multiple teams, you have the added challenge of dealing with the distributed nature.
So the question shouldn’t be, do things exist in this world that are less complex than event-driven architecture? (Of course there are.)
Instead, the question is: If I build a microservices architecture, is event-driven architecture more complex than an architecture that is based on REST or RPC calls? There my answer would clearly be no.
Don’t mistake “unfamiliar” with complex. Calling methods or functions is what we do in coding all the time. Making an HTTP request or gRPC call feels much closer to that than emitting (or consuming) an event. But just because something is different doesn’t mean it’s more complex.
Yes, it might be a bit mind-bending at first. But there’s nothing inherently complex in event-driven architecture. In fact, the separation of roles and responsibilities is even clearer than in a command-based system. Commands can fail, so when you issue a command, the caller has to think about what to do when things go wrong. This blurs responsibility - as the client of a service, you’re not necessarily in the best position to deal with its errors.
If you emit an event, you signal that you’re done, and you don’t want to hear back from any of the subscribers. Dealing with the event is their task now. When done right, event-driven architecture can have a beautiful simplicity to it.