Skip to content

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   mocks

Each 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
json
{
  "id": "order",
  "initial": "idle",
  "states": {
    "idle": {
      "on": {
        "CHECKOUT": {
          "target": "awaiting_payment",
          "guards": ["isCartNotEmpty"],
          "actions": ["emitPaymentRequest"]
        }
      }
    }
  }
}

Compare this to EventFlow:

flow
on> :checkout from @customer
  ? cart is not empty
    order moves to #awaiting_payment
    emit :payment_request to @payment

How EventFlow Solves This

Single Source of Truth

One file defines everything:

flow
// 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_payment

Readable by Everyone

Non-developers can read and validate the logic:

flow
? payment is verified
  order moves to #confirmed
  emit :confirmation_email to @customer
otherwise
  order moves to #payment_failed
  emit :retry_payment to @customer

Product managers can verify: "Yes, that's exactly what should happen."

Self-Documenting Tests

Every scenario with assertions is an executable test:

flow
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_payment

Run with:

bash
eventflow test order.flow

Auto-Generated Diagrams

Visualizations are generated from the same source:

bash
eventflow diagram order.flow --type=lane
eventflow diagram order.flow --type=state

No 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:

flow
machine: @order
  // Only @order can change order state

machine: @payment
  // Only @payment can change payment state

Message Passing

Machines communicate through events, not shared state:

flow
// @order sends to @payment
emit :payment_request to @payment

// @payment responds
emit :payment_success to @order

Automatic Correlation

The runtime handles event routing automatically:

flow
on> :checkout from @customer
  emit :payment_request to @payment   // Starts conversation

on :payment_success from @payment     // Automatically routed back
  order moves to #paid

No 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

Released under the MIT License.