Event-Driven Architecture
Services communicate by publishing and consuming events on a message broker (Kafka, RabbitMQ, SNS/SQS) rather than calling each other directly.
EDA = a town crier shouting news in the square. Anyone who cares listens; the crier doesn't know or care who's in the crowd.
EDA decouples producers from consumers: the order service publishes OrderPlaced and has no knowledge of which downstream services (inventory, billing, notifications) react to it. This enables independent deployability, natural audit trails, and backpressure handling. The cost is operational complexity: you must manage broker availability, consumer group lag, event schema evolution, and out-of-order delivery. Kafka's log retention also serves as an event store, enabling replay — critical for rebuilding derived state.
EDA introduces two consistency challenges: (1) dual-write — you cannot atomically write to your DB and publish to a broker in the same operation without the outbox pattern; (2) ordering — Kafka guarantees order within a partition, so you must carefully choose partition keys (e.g., order ID) to ensure events for the same entity are processed sequentially. Consumer idempotency is mandatory because at-least-once delivery guarantees duplicates. Dead-letter queues (DLQs) are the safety valve — a consumer that cannot process a message after N retries should park it in a DLQ for manual inspection, not drop it.
EDA is my default for cross-bounded-context communication when I can accept eventual consistency. I pair it with: the outbox pattern to eliminate dual-write races, idempotent consumers with deduplication keys, and partition keys aligned to the aggregate root. For schema evolution I use a schema registry (Confluent or AWS Glue) with backward-compatible Avro/Protobuf schemas and a compatibility policy enforced at publish time.
Treating EDA as a solution to all coupling problems. Event-driven choreography at scale becomes 'event spaghetti' — it is hard to trace the causal chain of a business process across 10 event types. For complex multi-step workflows, orchestration (Temporal, Step Functions) provides explicit process visibility at the cost of a central coordinator.