The order service wrote the order to its database and published OrderPlaced to Kafka. Clean, decoupled, textbook. Then one afternoon the database commit succeeded and the Kafka publish failed, and a customer had an order that existed, had been charged for, and that the warehouse had never heard of. The team spent two days reconciling before anyone said the words "dual write."
Event-driven architecture interview questions concentrate on those seams — the gap between two systems that must agree but cannot share a transaction. This guide covers events versus commands, choreography versus orchestration, the outbox pattern that fixes the story above, ordering, replay and the honest downsides.
What event-driven interviews actually test
- Vocabulary — events vs commands, and why the distinction shapes coupling.
- Coordination — choreography vs orchestration for multi-service workflows.
- Reliability — dual writes, the outbox pattern, idempotent consumers.
- Ordering and replay — partitions, event sourcing, rebuilding state.
- Honest tradeoffs — what you lose, and when not to use events.
Events, commands and why the distinction matters
A precise vocabulary answer scores immediately:
- An event is a statement of fact about something that already happened —
OrderPlaced,PaymentCaptured. Past tense. The publisher does not know or care who consumes it, and cannot be rejected. - A command is a request for something to happen —
PlaceOrder. Imperative, addressed to a specific handler, and can fail or be refused. - A query asks for data without changing anything.
The consequence, which is the actual answer: events invert the dependency. With commands, the caller must know who handles it, so adding a consumer means changing the producer. With events, the producer announces a fact and any number of consumers subscribe, so you add behaviour without touching the source. That is the coupling benefit people mean when they say "decoupled."
The trap worth naming: a badly designed event that is really a command in disguise — SendWelcomeEmail published as an "event" — recreates the coupling while losing the clarity. Events describe what happened; they do not instruct.
Also expect event notification versus event-carried state transfer: a thin event carrying only an ID means consumers must call back for details (chatty, but always current), while a fat event carrying the full state means consumers are self-sufficient (no callback, but the payload can be stale and the contract is larger). Naming that tradeoff is a good signal.
Choreography vs orchestration
The multi-service workflow question — order, payment, inventory, shipping.
- Choreography — each service listens for events and reacts, publishing its own. No central controller. Maximum decoupling and easy to add participants, but the overall workflow exists nowhere explicitly: to understand it you read six codebases, and debugging a stuck order is genuinely hard.
- Orchestration — a coordinator (a workflow engine or saga orchestrator) explicitly drives the steps and handles failures. The process is visible, testable and observable in one place, at the cost of a component that knows about everyone and can become a bottleneck.
The mature answer: choreography for simple reactive flows, orchestration once the workflow has more than a few steps or needs compensation, timeouts and visibility. Most teams that start fully choreographed eventually add an orchestrator for their critical business processes, and saying that reads as experience rather than theory. Name Temporal, AWS Step Functions or Camunda as the tools people actually reach for.
The dual write problem and the outbox pattern
Back to the intro. You need to update your database and publish an event, atomically — and they are two systems with no shared transaction. Publishing first risks announcing something that then fails to persist; persisting first risks the story above.
The transactional outbox is the standard fix, and interviewers expect it by name:
-- One local transaction covers both the state change AND the intent to publish
BEGIN;
INSERT INTO orders (id, customer_id, amount_paise, status)
VALUES ('ord_9d31', 'cus_44a1', 249900, 'placed');
INSERT INTO outbox (id, aggregate_id, event_type, payload, created_at)
VALUES (gen_random_uuid(), 'ord_9d31', 'OrderPlaced',
'{"orderId":"ord_9d31","amountPaise":249900}', now());
COMMIT;
-- A separate relay polls (or tails the WAL via CDC) and publishes,
-- marking rows sent. At-least-once — so consumers must be idempotent.
Explain why it works: the event is now part of the same local transaction as the state change, so they cannot diverge. A separate relay process — polling the table, or tailing the write-ahead log with change data capture via Debezium — publishes and marks rows sent. Delivery becomes at-least-once, which is why consumers must be idempotent; that consequence is the follow-up, so volunteer it.
Know the inverse too — the inbox pattern, where a consumer records processed message IDs in its own database inside the same transaction as its state change, giving exactly-once processing. Our distributed systems guide covers the delivery semantics underneath.
Ordering, partitions and replay
- Ordering is per-partition, not global. Kafka guarantees order within a partition, so if order matters for an entity, partition by that entity's key — all events for one order land in one partition and stay ordered. Global ordering means one partition, which means no parallelism.
- Out-of-order handling — even so, consumers should tolerate it: version numbers on events, or last-write-wins on a timestamp with a tie-break. Assuming perfect ordering is a common failure.
- Replay — a genuine superpower of log-based systems. Reset a consumer's offset and rebuild its state, or launch a new service that catches up on history. This is why Kafka is chosen over a traditional broker for event backbones.
- Event sourcing — storing state as an append-only sequence of events rather than a mutable row, deriving current state by replaying. Gives a perfect audit log and time travel; costs you query complexity (hence CQRS), snapshotting for performance, and a genuinely hard schema-evolution problem because old events are immutable and must remain readable forever.
Be honest that event sourcing is a heavier commitment than event-driven messaging, and that the two are frequently confused. Recommending it only where auditability is a hard requirement is the credible position. Our Kafka guide covers partitions and offsets in depth.
The honest downsides
Senior rounds specifically test whether you can criticise the pattern you are advocating:
- Debugging is much harder. A synchronous stack trace becomes a trail across services and topics. Distributed tracing with correlation IDs is not optional; it is table stakes.
- Eventual consistency leaks to users. The classic symptom is placing an order and not seeing it in your order list yet. That is a product decision, not just a technical one.
- Schema evolution is a contract problem. Consumers you have never met depend on your event shape. Use a schema registry, add fields rather than change them, and version topics.
- Local reasoning disappears. No single place describes the business process end to end, which is precisely what orchestration reintroduces.
- Operational surface grows — a broker to run, consumer lag to monitor, dead letter queues to drain, and replays to perform carefully.
So the strongest closing position: events are worth it when you genuinely need decoupling, asynchrony or replay — and a synchronous call is simpler, easier to debug and perfectly correct for a great many problems. Candidates who say that are trusted more, not less.
The books, real systems, ChatGPT — where each fits
- Designing Data-Intensive Applications — the chapters on logs and stream processing, again the best single source.
- microservices.io (Chris Richardson) — the canonical pattern catalogue, including outbox, saga and CQRS with the tradeoffs written out.
- Martin Fowler's writing on event-driven — particularly the piece distinguishing the four different things people mean by "event-driven", which is exactly the vocabulary confusion interviews probe.
- Building a two-service flow with an outbox — highest yield. Then kill the broker after the database commit and watch the outbox save you.
- Debezium's documentation — the practical CDC implementation of the outbox relay.
- ChatGPT — good for comparing patterns and generating consumers. It will not ask what happened to the order the warehouse never heard about.
- Greenroom — the spoken layer. Ari, the AI interviewer, runs design rounds out loud and pushes on the seams between services. Fair tradeoff: Ari will not run your consumers.
How to prepare for an event-driven architecture interview
- Week 1: vocabulary. Distinguish events, commands, notification versus state transfer, and rehearse why events invert dependencies.
- Week 2: coordination. Design one workflow both choreographed and orchestrated, and argue when each is right.
- Week 3: reliability. Implement the outbox pattern and an idempotent consumer, then deliberately break the broker mid-flow.
- Final week: ordering and replay, plus rehearsing the honest downsides — then two spoken mocks with design follow-ups.
Building the rest of the stack? The Kafka guide covers the log, the RabbitMQ guide covers the broker alternative, the microservices guide covers the architecture, and the distributed systems guide covers the guarantees underneath.
Frequently asked questions
What are the most common event-driven architecture interview questions?
The most common questions cover the difference between an event and a command and why it changes coupling, choreography versus orchestration for multi-service workflows, the dual write problem and how the transactional outbox pattern solves it, why consumers must be idempotent, how ordering works with partitions, what event sourcing gives you and what it costs, and the honest downsides of going event-driven.
What is the difference between an event and a command?
An event is a statement of fact about something that already happened, expressed in the past tense such as OrderPlaced, and the publisher neither knows nor cares who consumes it. A command is a request for something to happen, expressed imperatively such as PlaceOrder, addressed to a specific handler, and it can be rejected. The distinction matters because events invert the dependency, letting you add consumers without changing the producer.
What is the dual write problem?
The dual write problem occurs when a service must update its own database and publish an event to a broker, but the two are separate systems with no shared transaction. If the database commit succeeds and the publish fails, downstream services never learn about a change that definitely happened. If you publish first and the commit fails, you have announced something that did not happen. Either way the systems silently diverge.
What is the transactional outbox pattern?
The outbox pattern writes the event into an outbox table inside the same local database transaction as the state change, so the state and the intent to publish either both commit or both roll back. A separate relay process then reads the outbox — by polling or by tailing the write-ahead log with change data capture — publishes the events, and marks them sent. Delivery becomes at-least-once, so consumers must be idempotent.
When should you use choreography instead of orchestration?
Use choreography, where each service reacts to events independently, for simple reactive flows with few participants and no complex failure handling, since it maximises decoupling and makes adding consumers easy. Move to orchestration once a workflow has several steps or needs compensating actions, timeouts and visibility, because the choreographed version exists nowhere explicitly and debugging a stuck process means reading several codebases.
What are the downsides of event-driven architecture?
Debugging is substantially harder because a synchronous stack trace becomes a trail across services, making distributed tracing mandatory rather than optional. Eventual consistency leaks into the user experience, such as an order not appearing immediately after being placed. Event schemas become contracts with consumers you have never met, so evolution requires a registry and additive changes. You also lose local reasoning about business processes and take on real operational overhead.