Event-Driven Architecture Solves Real Problems
Event-driven architecture is one of those ideas that sounds right almost immediately.
And in many cases, it is right.
If something important happens in a system, it makes sense to let other parts of the platform react to it. A customer registered. An order was placed. A payment was authorized. A file was uploaded. These are meaningful business facts. Other systems may care about them. A notification service may send an email. An analytics service may update a report. A search service may update an index. A data pipeline may send the change toward a data lake.
In this kind of situation, events feel natural. The service that publishes the event does not need to know every consumer. New consumers can be added later. Teams can react to the same business fact without tightly wiring every service to every other service. That is the beautiful part of event-driven architecture.
In the Python data engineering world, tools like Apache Kafka and Faust make this pattern accessible and production-ready. They are genuinely good tools for genuinely good use cases.
But there is a trap.
The Risk of "Events Everywhere"
Because once an idea is useful, we sometimes try to use it everywhere.
I have seen this in architecture discussions. A team starts with a good goal: reduce coupling, avoid long synchronous chains, make services more independent, and build a more flexible platform. I agree with all of that. The problem starts when the idea becomes a universal rule.
"All new services should be event-driven."
That sentence makes me careful. Not negative. Not dramatic. Just careful.
The problem is not event-driven architecture. The problem is the word "all."
Not every flow has the same shape. Some flows are simple questions: "Show me this customer profile." "What is the current order status?" "Can this user access this page?" Some flows are direct actions: "Create this customer." "Update this address." "Cancel this booking." Some flows are business processes: "Approve this claim." "Fulfill this order." "Onboard this customer." And some flows are natural event reactions: "The customer registered." "The payment was completed." "The file was uploaded."
These are not the same thing. So it is strange to force all of them through the same architectural pattern.
This is where I think old wisdom fits surprisingly well. The Taoist idea of wu wei is often explained as non-action or effortless action, but I find "non-forcing" more useful in this context. It does not mean doing nothing. It means not forcing action against the nature of the situation.
That is a good architecture principle.
Do not force an event-driven design where a simple request-response flow is enough. Do not force choreography where a business process clearly needs ownership. Do not force orchestration where independent reactions are enough. And do not force a message broker into a flow just because the platform already has one and the diagram looks more modern.
A simple example is a user opening a screen to see a customer profile. That is a query. The user is not asking us to publish a fact into the universe and wait for knowledge to return from the mist. The user just wants the customer profile. In many cases, a simple API call is the natural answer.
Could we make that event-driven? Probably. Should we? Not always.
Sometimes using events for a simple flow is like building an irrigation system to water one houseplant. It may work, and it may even look impressive, but someone still has to maintain the pipes.
This does not mean synchronous APIs are always better. They are not. Too many synchronous calls can create tight runtime coupling. One service is slow, and everything is slow. One service is down, and everything is broken. One API changes, and three teams suddenly discover new hobbies, like incident calls and emergency debugging.
But that is the point. Every pattern has a cost.
Events reduce some kinds of coupling, but they introduce other kinds of complexity: schemas, retries, duplicate messages, ordering, eventual consistency, observability, ownership, and failure handling. APIs give clarity and immediate feedback, but they can create direct dependency. Orchestration gives visibility and control, but it adds a coordinator. Choreography gives independence, but it can hide the full business process.
There is no free architecture. There are only trade-offs we understand and trade-offs we pretend not to see.
Events, Commands, and Queries Are Not the Same
This is why I find the distinction between events, commands, and queries so useful.
Events Describe the Past
An event belongs to the past. It says, "This happened." A customer registered. A payment was authorized. A file was uploaded.
Commands Shape the Future
A command points to the future. It says, "Please make this happen." Reserve inventory. Create shipment. Approve claim.
Queries Ask About the Present
A query belongs to the present. It says, "What is true now?" Show me the customer profile. Give me the current order status. Calculate the price.
This may sound like a small naming detail, but it is not. A lot of confusion starts when we mix these concepts. We publish something that looks like an event, but we secretly expect another service to treat it as a command. We ask for current state through a long asynchronous chain and then wonder why the user experience feels strange.
Good architecture does not confuse the past, present, and future. An event should describe a fact. A command should express intent. A query should ask for information.
A Better Rule: Use the Pattern That Fits the Flow
My practical view is simple: event-driven architecture should be a first-class option, not a universal obligation.
Use events when something meaningful happened and independent systems may need to react. Use APIs when the caller needs a clear answer now. Use orchestration when a business process needs ownership, status, ordering, or compensation. Use choreography when independent services can react safely on their own.
The goal is not to make everything event-driven. The goal is to build systems that are understandable, reliable, scalable, and fit for purpose.
Events can help us get there.
But only when we use them in the right place.
Read the Full Article
I wrote a longer version of this idea, with more examples and a deeper discussion of events, commands, queries, wu wei, and the danger of "events everywhere."
Read the full article: Event-Driven Architecture Is Not for Everything