
Most debates about event-driven architecture fail before they start, because the two sides are discussing different things. The term covers at least four distinct patterns, each with different costs and failure modes. Consequently, this framework first separates them, then states what the brokers actually guarantee, and only then offers a decision.
Four patterns wearing one name
Martin Fowler and colleagues at Thoughtworks concluded from a 2016 summit that “event-driven” conflates four separate patterns: event notification, event-carried state transfer, event sourcing, and CQRS.
That conflation causes real damage. Fowler documents a project in which a manager called event sourcing “a disaster” while actually describing a symptom of an entirely different pattern. Consequently, the blame landed on the wrong technique, and the lesson learned was the wrong lesson.
Therefore, make anyone proposing an “event-driven” name specify which of the four they mean. The answer changes everything downstream.
The people who popularised it walked it back.
This is the part rarely quoted in conference talks. Udi Dahan, one of the two practitioners Fowler credits as CQRS advocates, publicly apologized in 2011 for his role in its overuse, saying most teams that adopted CQRS and event sourcing shouldn’t have.
Fowler’s own write-up carries a similar warning: CQRS adds risky complexity, most uses he encountered went badly, and it should be applied narrowly. Meanwhile, Sam Newman, who wrote the standard microservices texts, argued at QCon London in 2020 that microservices should not be the default choice and that they fit most startups poorly.
Fair enough, but this isn’t unanimous. Greg Young, who originated CQRS, has argued the opposite — that the architecture is genuinely simpler once understood. Notably, that disagreement is itself the signal: when the originators differ, the pattern is context-dependent rather than generally superior.
What the brokers actually guarantee
Marketing language and documentation diverge here, so read the documentation.
Kafka guarantees ordering only within a single topic-partition — not across a topic — and delivers at least once by default. Exactly-once semantics exist but require specific configuration and carry their own constraints.
AWS SQS standard queues support at-least-once delivery, with possible duplicates and out-of-order delivery. Ordering is explicitly best-effort.
Accordingly, plan for duplicate delivery as the normal case. Idempotent consumers are not a refinement you add later; they are the entry fee.
The debugging tax is the real cost.
Here is the cost that rarely appears in the design document. Fowler names it precisely: with event notification, a logical flow spanning several events does not exist anywhere in the program text. No file describes it. Consequently, reconstructing what happened means assembling it from runtime evidence.
The tooling concedes this. OpenTelemetry’s messaging conventions specify span links rather than parent-child relationships for correlating producers with consumers, because the neat causal tree that request-response gives you does not survive asynchronous fan-out.
Therefore, budget observability as part of the migration, not after it. A team that could previously read a stack trace now needs correlation infrastructure to answer the same question.
Schema changes become deployment choreography.
In a request-response system, you deploy a service. In an event-driven one, your schema compatibility mode dictates the order in which you deploy everything.
Confluent’s Schema Registry documents this directly: BACKWARD compatibility requires upgrading all consumers before producers. Choose a different mode and the required order changes.
Consequently, an early schema decision quietly becomes a release-process constraint for every downstream team. Additionally, someone must own that choreography once more than two teams publish events.
You lose rollback and have to hand-write the replacement.
Replacing distributed transactions with sagas has two documented costs, as Chris Richardson notes. First, there is no automatic rollback — developers write compensating transactions by hand for every step that can fail.
Second, the system eventually becomes consistent, so the application must handle states that a transactional system simply never exposes. Notably, both costs land on application developers rather than on infrastructure.
Cost behaves differently at scale.
One practical difference rarely modeled up front: the two shape bills differently. A synchronous call costs compute for its duration. An event, by contrast, costs a publish, storage for the retention window, and a delivery per consumer.
Consequently, fan-out multiplies cost in a way request-response does not. Adding a fifth consumer to a topic is architecturally free but not financially. Additionally, retention is a standing charge you keep paying for events nobody reads.
Therefore, model the consumer count and the retention window before committing, rather than treating the broker as a fixed platform cost.
When each one actually wins
Request-response wins when the caller needs an answer to proceed, when the operation is genuinely transactional, and when a stack trace is your primary debugging tool. Most business software sits here.
Event-driven wins under specific conditions: producers and consumers scale independently; the producer genuinely doesn’t need the outcome; you need a durable log of what happened; or you must fan one occurrence out to many unknown consumers. Furthermore, it wins when teams need to deploy independently more than they need synchronous simplicity.
Six questions before you commit
- Which of the four patterns do you mean? Notification, state transfer, event sourcing, or CQRS — they are not interchangeable.
- Does the caller need the result? If yes, asynchrony adds cost without buying anything.
- Are your consumers idempotent? At-least-once is the documented default, so duplicates will arrive.
- Do you need ordering, and at what granularity? Kafka gives it per partition; SQS standard gives best-effort only.
- Who owns schema evolution? Your compatibility mode becomes everyone’s deployment order.
- Can you afford the observability? If you don’t fund correlation tooling, you are trading debuggability for decoupling.
The honest default
Start request-response. Introduce events at the specific seams where the coupling actually hurts — a slow third-party call, a fan-out to several consumers, an audit log you must retain.
That is not conservatism for its own sake. Rather, it matches what the practitioners who popularised these patterns now say publicly, and it keeps the debugging tax proportional to the benefit.
How Pegotec helps
We size the observability and schema-ownership cost before recommending an event-driven seam, because those are the line items that get discovered late. We’ll also tell you when a synchronous call is simply the right answer.
If you are weighing this decision on a system that already carries traffic, talk to us.
FAQ
It is not one pattern. Martin Fowler and colleagues at Thoughtworks concluded from a 2016 summit that the term conflates four distinct patterns: event notification, event-carried state transfer, event sourcing, and CQRS. They carry different costs and different failure modes. Fowler documents a project where a manager blamed event sourcing for a disaster while describing a symptom of a different pattern entirely, so the wrong technique took the blame. Before you evaluate it, make anyone proposing event-driven architecture name which of the four they mean.
Not by default; design as though duplicates will arrive. Kafka guarantees ordering only within a single topic-partition, not across a topic, and delivers at-least-once by default; exactly-once semantics are available but require specific configuration and impose constraints. AWS SQS standard queues document at-least-once delivery, with possible duplicates and out-of-order delivery, and describe ordering as best-effort. Idempotent consumers are therefore an entry requirement for event-driven architecture, not a later refinement.
Because the logical flow exists nowhere in the code; Martin Fowler calls this out explicitly. With event notification, a flow spanning several events is described in no program text, so reconstructing what happened means assembling it from runtime evidence. The tooling agrees — OpenTelemetry’s messaging semantic conventions specify span links rather than parent-child relationships to correlate producers with consumers, because the causal tree that request-response provides does not survive asynchronous fan-out. Budget correlation tooling as part of the migration, not after it.
No. Start with request-response and introduce events at the seams where coupling actually hurts—a slow third-party call, a fan-out to many consumers, or a durable audit log you must retain. Several practitioners who popularised these patterns now say the same: Udi Dahan publicly apologized in 2011 for his role in CQRS overuse, and Fowler’s own write-up warns that most uses he encountered went badly. Sam Newman argued at QCon London 2020 that microservices should not be a default. Greg Young disagrees, which itself shows the choice is context-dependent.
Let's Talk About Your Project
Enjoyed reading about Event-Driven vs Request-Response: A 2026 Decision Framework for High-Traffic Systems? Book a free 30-minute call with our consultants to discuss your project. No obligation.