Why EventFlow?
The Problem with Traditional Approaches
Documentation Drift
In traditional development, documentation and code inevitably diverge:
Week 1: Docs ←→ Code (in sync)
Week 4: Docs ... Code (starting to drift)
Week 12: Docs ??? Code (what does this even do?)Developers update code but forget to update docs. Product managers write requirements that never make it to implementation. QA writes tests based on outdated specs.
The Translation Problem
Every translation step introduces errors:
Business Requirement → Technical Spec → Code → Tests
↓ ↓ ↓ ↓
"User can checkout" PRD doc if/else mocksEach arrow is a potential source of misunderstanding.
State Machine Complexity
Traditional state machine implementations require:
- Complex configuration files (JSON/YAML)
- Verbose class definitions
- Separate test suites
- Manual diagram maintenance
{
"id": "order",
"initial": "idle",
"states": {
"idle": {
"on": {
"CHECKOUT": {
"target": "awaiting_payment",
"guards": ["isCartNotEmpty"],
"actions": ["emitPaymentRequest"]
}
}
}
}
}Compare this to EventFlow:
on> :checkout from @customer
? cart is not empty
order moves to #awaiting_payment
emit :payment_request to @paymentHow EventFlow Solves This
Single Source of Truth
One file defines everything:
// order.flow - This IS the documentation, tests, and runtime
machine: @order
scenario: checkout flow
given:
@customer is logged in
cart has items
on> :checkout from @customer
? cart is not empty
order moves to #awaiting_payment
emit :payment_request to @payment
expect:
= order is in #awaiting_paymentReadable by Everyone
Non-developers can read and validate the logic:
? payment is verified
order moves to #confirmed
emit :confirmation_email to @customer
otherwise
order moves to #payment_failed
emit :retry_payment to @customerProduct managers can verify: "Yes, that's exactly what should happen."
Self-Documenting Tests
Every scenario with assertions is an executable test:
scenario: expired cart items
given:
cart has expired items
on> :checkout from @customer
? cart has expired items
emit :cart_invalid to @customer
expect:
= @customer received :cart_invalid
= order is not in #awaiting_paymentRun with:
eventflow test order.flowAuto-Generated Diagrams
Visualizations are generated from the same source:
eventflow diagram order.flow --type=lane
eventflow diagram order.flow --type=stateNo manual diagram maintenance. Diagrams always match the code.
The Actor Model Advantage
EventFlow is built on actor model principles:
Isolated State
Each machine manages its own state:
machine: @order
// Only @order can change order state
machine: @payment
// Only @payment can change payment stateMessage Passing
Machines communicate through events, not shared state:
// @order sends to @payment
emit :payment_request to @payment
// @payment responds
emit :payment_success to @orderAutomatic Correlation
The runtime handles event routing automatically:
on> :checkout from @customer
emit :payment_request to @payment // Starts conversation
on :payment_success from @payment // Automatically routed back
order moves to #paidNo correlation IDs to manage. No message queues to configure.
Event Sourcing Built-In
Every machine instance is an aggregate:
┌─────────────────────────────────────────────────────────────┐
│ Event Store │
├─────────────────────────────────────────────────────────────┤
│ aggregate_id │ event_type │ data │ seq │
│ ──────────────┼───────────────────┼────────────────┼───── │
│ order-123 │ :checkout │ {customer} │ 1 │
│ order-123 │ :payment_success │ {txn_id} │ 2 │
│ order-123 │ :shipped │ {tracking} │ 3 │
└─────────────────────────────────────────────────────────────┘State is rebuilt by replaying events. Full audit trail. Time-travel debugging.
When to Use EventFlow
EventFlow is ideal for:
- Business workflows with clear state transitions
- Multi-step processes involving multiple actors
- Event-driven architectures with async communication
- Collaborative teams where non-developers need to understand the logic
- Regulated industries requiring audit trails
EventFlow may not be the best fit for:
- Simple CRUD operations without complex state
- Real-time computation (use purpose-built tools)
- Low-level system programming