Event Sourcing
Event Sourcing — паттерн хранения состояния как последовательности событий. Не "текущий баланс = 100", а "начислили +50, потратили -20, начислили +70". Актуальное состояние = fold(events).
Классический пример: счёт
# обычная БД
accounts { id, balance }
UPDATE accounts SET balance = balance - 50 WHERE id = 1
# → потеря истории. Кто? Когда? Почему?
# event sourced
events: [
{ AccountOpened id=1, at=T1 }
{ MoneyDeposited id=1, amount=100, at=T2 }
{ MoneyWithdrawn id=1, amount=30, at=T3 }
{ MoneyDeposited id=1, amount=20, at=T4 }
]
balance(id=1) = 0 + 100 - 30 + 20 = 90
Плюсы
- Полная история — что и когда, никогда не теряется
- Аудит — из коробки, регуляторы счастливы
- Time travel — состояние на любой момент
- Debug — воспроизводимо
- Множественные проекции — из тех же событий разные views
- Естественно масштабируется через Kafka
Минусы
- Сложность вырастает
- Схема событий = навсегда (versioning painful)
- GDPR right-to-be-forgotten конфликтует с immutable log
- Read через fold медленно — нужен snapshot
- Eventual consistency между write model и read models
Snapshot
# для быстрого чтения — кеш состояния каждые N событий
snapshot(id=1, version=1000, state={balance: 5000})
# читаем: snapshot + события с 1001
CQRS
Часто идёт в паре: CQRS (Command Query Responsibility Segregation). Разные модели для записи и чтения.
Command → Aggregate → validate → EventStore.append(events)
│
├→ ReadModel-1 (SQL для UI)
├→ ReadModel-2 (Elasticsearch)
└→ ReadModel-3 (аналитика)
Query → ReadModel-N
Event storming
Методика от Alberto Brandolini: команда с бизнесом на стене стикерами моделирует все события домена. Красный = событие (past tense), синий = команда, жёлтый = агрегат.
Схема эволюция
События иммутабельны. Изменение схемы:
- Upcasting — при загрузке события v1 → v2 на лету
- Weak schema — JSON с optional полями
- Copy-transform — создаёшь новый event store с новой схемой
Реализации
- EventStoreDB — специализированная БД от Greg Young
- Axon (Java), EventFlow (.NET) — фреймворки
- Kafka + Kafka Streams — de facto для больших
- Marten (Postgres + JSONB)
- Свою — просто таблица
events(id, agg_id, type, data, at)
Не для всего
Event Sourcing — молоток, не всё гвоздь. Хорош: финансы, бухгалтерия, аудит, workflow. Плох: простой CRUD, каталоги, где история не важна.