Event Sourcing
↑ 8.2 Архитектурные стили и DDD · ← Предыдущая · → Следующая
Зачем это на собесе
Спрашивают, когда это оправдано и какие сложности несёт.
Объяснение
Вместо хранения текущего состояния сохраняется последовательность событий, изменивших его. Состояние — результат их проигрывания.
OrderCreated → ItemAdded → ItemAdded → OrderPaid → OrderShipped
↓ replay
состояние Order = Shipped, items = 2public abstract record OrderEvent(Guid OrderId, DateTimeOffset At);
public record ItemAdded(Guid OrderId, DateTimeOffset At, Sku Sku, int Qty) : OrderEvent(OrderId, At);
public record OrderPaid(Guid OrderId, DateTimeOffset At) : OrderEvent(OrderId, At);
public class Order
{
public Status Status { get; private set; }
public static Order Rehydrate(IEnumerable<OrderEvent> history) { var o = new Order(); foreach (var e in history) o.Apply(e); return o; }
private void Apply(OrderEvent e) { switch (e) { case OrderPaid: Status = Status.Paid; break; /* ... */ } }
}| Плюсы | Минусы |
|---|---|
| полный аудит и история | сложность и порог входа |
| можно восстановить состояние на любой момент | эволюция схемы событий (версионирование, upcasting) |
| естественная основа для проекций и интеграции | eventual consistency проекций |
| отладка «что произошло» | запросы по текущему состоянию — через проекции |
| удаление персональных данных (GDPR): шифрование ключами, crypto-shredding |
Техники: snapshots (ускорение загрузки), проекции/read-модели, оптимистичная блокировка по версии потока, хранилища: EventStoreDB, Marten (PostgreSQL), собственная таблица events.
Когда оправдан: строгий аудит (финансы), сложные доменные процессы с историей, потребность в темпоральных запросах. В остальных случаях — избыточен.
Нюансы и подводные камни
- Изменение формата событий нельзя выполнить «миграцией на месте»: события неизменяемы.
- «Плохое» событие не удаляют, а компенсируют новым.
- Проекции нужно уметь перестраивать (replay).
- Не путайте с журналом изменений (audit log) — он проще и часто достаточен.
- Event Sourcing ≠ CQRS ≠ шина событий.
Практика
- Смоделируйте счёт/заказ через события и восстановите состояние.
- Реализуйте проекцию текущих остатков и её перестроение.
- Используйте Marten для потока событий в PostgreSQL.
Вопросы с ответами
Зачем Event Sourcing?
Полная история изменений, восстановление состояния на любой момент и удобная основа для проекций и интеграций.
Как менять схему событий?
Версионированием и upcasting (преобразованием старых событий при чтении).