Event sourcing: сначала журнал событий, потом фичи
Почему event sourcing - это не архитектурная мода, а практический ответ на вопрос «что произошло в системе вчера».
Каждые несколько месяцев ко мне приходит команда с одной и той же проблемой в разных вариациях. В системе что-то пошло не так - неправильно посчитался баланс, пропал заказ, статус переключился в неверное значение. Нужно понять, что произошло. А понять невозможно, потому что база данных хранит только текущее состояние.
Это не проблема логирования. Это архитектурная проблема, которая стала незаметной из-за того, как большинство систем строится по умолчанию.
Что такое event sourcing на самом деле
Идея простая. Вместо того чтобы перезаписывать запись при изменении, вы добавляете событие, описывающее то, что случилось. Текущее состояние получается воспроизведением этих событий.
Баланс счёта - это не число в столбце. Это результат всех пополнений, списаний и корректировок с момента открытия счёта. Статус заказа - не поле. Это последнее в цепочке событий: создан, подтверждён, отправлен, доставлен.
Звучит как лишняя работа, и поначалу так и есть. Но это меняет вопрос с «какое состояние сейчас?» на «что произошло и почему?»
Проблема журнала аудита
В регулируемых отраслях это не опционально. Банки, страховые компании, здравоохранение, логистика - у всех есть версия одного и того же требования: покажи полную историю этой сущности. Кто менял, когда, с какими значениями, по какому триггеру.
В традиционной базе с изменяемым состоянием это восстанавливают из логов, снапшотов резервных копий и памяти людей. Медленно, неполно, и всегда спорно.
С event sourcing история и есть данные. Восстанавливать нечего. Читаешь поток событий.
Когда это не тот инструмент
Event sourcing добавляет реальную сложность. Путь чтения требует проекций - нужно строить и поддерживать представления текущего состояния, а это дополнительное хранение и логика синхронизации. Эволюция схемы сложнее: старые события должны понимать новый код. Отладка бага в проекции требует воспроизведения истории.
Для простого CRUD-приложения с низкими регуляторными требованиями - это накладные расходы с малой отдачей. Я бы не рекомендовал это как умолчание.
Сигнал, что event sourcing начинает окупаться: команда регулярно строит костыли, чтобы ответить на вопрос «что произошло?», или требования к аудиту появляются постфактум, когда данных уже нет.
Практический путь
Не обязательно заходить сразу полностью. Разумная промежуточная позиция - добавить журнал событий рядом с традиционным хранилищем состояния: таблицу только для добавления или поток, куда записывается каждая значимая мутация. Это не чистый event sourcing, но он решает проблему аудита без перестройки всей модели данных.
Если этот паттерн проживёт шесть месяцев в продакшне, у вас будет куда лучшее понимание того, стоит ли полная архитектура event sourcing инвестиций для вашей конкретной системы.
Вопрос, который я задаю первым
Перед тем как рекомендовать event sourcing кому-либо, я спрашиваю: на какой вопрос о вашей собственной системе вы сегодня не можете ответить? Если ответ - «я не знаю, что изменилось и почему», event sourcing стоит рассматривать серьёзно. Если ответ - «у нас медленные чтения», это, скорее всего, не то лекарство.
Архитектурные решения должны определяться реальными проблемами, а не тем, что интересно строить.