What event-driven architecture is and when it fits, CQRS and its trade-offs, event sourcing and its challenges, implementing database sharding, implementing idempotent APIs, and back-pressure in services.
Published September 25, 2026
These are "powerful but costly" patterns. Senior answers explain when not to use them, and how to operate them: schema evolution, replay, reconciliation, monitoring.
Short answer: In EDA, components communicate by producing and reacting to events: immutable facts about something that happened (OrderPlaced, PaymentFailed), usually through a broker or log (Kafka, RabbitMQ, EventBridge). Producers don't know their consumers. The styles:
It's a good fit for:
It's a poor fit when you need immediate, strongly consistent responses across services, for simple CRUD systems, or when the team lacks observability and operational maturity (debugging event chains is harder). Essentials: schema governance, idempotency, ordering by key, DLQs, tracing and replay.
Learn it in depth → Event-Driven Architecture Patterns
Short answer: Command Query Responsibility Segregation means separate models (and often separate stores) for writes (commands) and reads (queries):
The benefits:
The trade-offs:
Use it where the read and write workloads differ significantly in shape or scale, not for every CRUD screen. You can apply it selectively, per bounded context.
Learn it in depth → CQRS Basics
Short answer: Event sourcing stores an entity's state as an append-only sequence of events (AccountOpened, MoneyDeposited, MoneyWithdrawn), instead of the current state. The current state is derived by replaying the events (with snapshots for performance). The benefits:
The challenges:
Short answer:
DataSource keyed by the shard key);Rule: exhaust vertical scaling, replicas, partitioning and caching first. Sharding is a one-way door, with high complexity.
Learn it in depth → Database Sharding
Short answer:
Idempotency-Key (a UUID) per logical operation, and reuses it on retries;(key, client or tenant, request hash, status, response, created_at), with a unique constraint. This is inserted atomically before or with the business operation (in the same transaction, or with a status of IN_PROGRESS);@Transactional
public OrderResponse create(String idemKey, CreateOrderRequest req) {
var existing = idempotency.find(idemKey);
if (existing.isPresent()) {
var rec = existing.get();
if (!rec.requestHash().equals(hash(req))) throw new IdempotencyKeyMismatchException();
return rec.response(); // replay the original result
}
idempotency.insertInProgress(idemKey, hash(req)); // a unique constraint blocks concurrent twins
OrderResponse resp = orders.place(req);
idempotency.complete(idemKey, resp);
return resp;
}
Learn it in depth → Payment — Idempotency Implementation
Short answer: Back-pressure means a slower downstream signals an upstream to slow down, instead of being overwhelmed (unbounded queues, then OOMs and cascading timeouts). The implementations:
CallerRunsPolicy slows the producers), and bounded in-memory buffers.Retry-After when the concurrency or queue limits are hit (Resilience4j bulkheads or rate limiters, concurrency limiters like Netflix's adaptive concurrency limits).request(n) demand in Reactor or WebFlux, and limitRate, overflow strategies.The goal is graceful degradation: the system serves what it can at its capacity, and says no quickly to the rest.
Q: What's the difference between an event and a command?
A: A command expresses intent, and targets one handler, which may reject it (PlaceOrder). An event states a fact that already happened, and may have many (or no) subscribers (OrderPlaced). Commands are named in the imperative; events in the past tense.
Q: How do you rebuild a CQRS read model? A: Deploy a new projection version that consumes from the beginning of the event log (or a snapshot plus the log), into a new table or index. When it has caught up, switch reads to it (an alias or feature flag), then drop the old one. This is why retention and replay capability matter.
Q: Do you need Kafka for event sourcing? A: No, and Kafka is often a poor event store on its own (no per-aggregate optimistic concurrency, and awkward per-entity reads). Use a proper event store (EventStoreDB, Axon Server, or a Postgres events table with a stream version constraint), and publish to Kafka for integration.
Q: What is the "outbox + CDC" combination good for? A: Reliable event publication. The business change and the event commit atomically in one database transaction, and CDC (Debezium) streams the outbox to Kafka with low latency, and no polling load. It solves the dual-write problem.