🔧 Под капотом Event Sourcing

💡 В одном из прошлых постов я упомянул, что этот подход хорошо решает проблемы с версионированием. Event Sourcing меняет базовую модель работы с данными. Вместо чтения текущего состояния вы работаете с историей изменений и это требует другого мышления.

📚 Меняется источник истины. Агрегат хранится в виде последовательности событий. Обычно каждому событию присваивается порядковый номер, а версия агрегата соответствует номеру последнего примененного события.

💾 Агрегат периодически сохраняет свое состояние в так называемые снапшоты, откуда можно взять значения актуальные для определенной версии. Но сразу после этого придется проверить появились ли новые события с момента сохранения. События, которые не вошли в снапшот придется применить отдельно.

🔍 Также важно, что чтение снапшота и replay событий не происходят сами по себе. Эти операции выполняются при попытке применить команду к агрегату. При параллельной обработке команд каждая из них независимо восстанавливает агрегат из событий и работает со своей версией состояния.

⚠️ Согласование происходит только на этапе сохранения события через проверку версии. К моменту сохранения версия агрегата в хранилище уже может отличаться от той версии, на основе которой выполнялась команда. Например потому что другая параллельная команда обработалась и сохранилась быстрее.

🔄 Такую ситуацию можно обрабатывать по-разному. Например обработчик команды может загрузить из хранилища последние события, обновить свою версию агрегата и попытаться применить команду еще раз. Существуют и другие способы, но конфликт придется обработать. Иначе действия пользователя просто потеряются.

💣 Готовые фреймворки прячут за простым API важные детали, такие как обработка конфликтов версий. Но когда абстракции протекут и команды пользователей потеряются среди слоев middleware - отвечать за это все равно придется вам.

🔧 Под капотом Event Sourcing | Сетка — социальная сеть от hh.ru