Anti-patterns in event-driven architecture
Scope of experiences
- Many commenters have long-running event-driven systems; others report outright disasters.
- Domains with notable success: insurance and regulated industries (audit trails), banking and trading, manufacturing, public transport ticketing, some embedded systems, and especially games.
- Several note heavy internal use of event concepts inside databases, VCS, and JS/GUI apps, even when the “architecture” isn’t branded as EDA.
Where event-driven shines
- Integration across product suites and heterogeneous systems.
- Moving slow or unreliable operations off the user’s critical path (emails, settlements, notifications, config distribution).
- Domains that naturally produce “facts” over time and need full history, replay, or audit (ledgers, ticketing, some analytics).
- Game dev and complex async systems where evented state machines are a natural fit.
- Command-driven systems using messages as async instructions, not as primary state, are seen as a pragmatic middle ground.
Common anti-patterns and failures
- Overuse: applying EDA everywhere, including simple request/response flows that would be clearer as direct function calls or CRUD APIs.
- “Vanity” or resume-driven architectures: complex Kafka/event-sourcing stacks where a monolith would suffice.
- Modeling queries and tightly coupled workflows as events; using commands with multiple consumers; building distributed monoliths.
- Poor contracts: inconsistent wire formats, weak schema/versioning discipline, and non-deterministic consumers make replay and evolution fragile.
- Operational pain: Kafka and cloud queues introduce infra overhead, difficult local setups, laggy consumers, ordering headaches, and costly observability.
- Debuggability: hard to trace who consumes what, why something didn’t happen, or where a bug arose; no easy “find usages” for events.
Design guidance and patterns
- Start from business/SLA: “can they wait?” If not, prefer synchronous calls.
- Treat events as immutable facts; commands as single-consumer imperatives; avoid events-for-queries.
- Favor entity-centric modeling (“nouns over verbs”), with commands and events changing entity state.
- Embrace additive-only changes, idempotent consumers, deterministic projectors, DLQs, and replay strategies; accept at-least-once semantics where appropriate.
- Invest heavily in telemetry (trace IDs, distributed tracing, shared logging infrastructure).
Meta-consensus
- EDA is powerful but unforgiving: it magnifies both good and bad design.
- Many argue microservices plus EDA are over-applied; a well-structured monolith with selective async pieces often wins on cost, simplicity, and time-to-market.