Почему паттерн Event Sourcing используется вместе с паттерном CQRS

Ответ

Event Sourcing хранит состояние системы как последовательность событий, а CQRS разделяет операции на команды (изменяющие данные) и запросы (читающие данные). Их часто используют вместе, потому что:

  1. Согласованность
    Event Sourcing гарантирует, что все изменения проходят через события, а CQRS обеспечивает разделение чтения и записи, что упрощает масштабирование.

  2. Гибкость
    CQRS позволяет иметь разные модели для чтения (проекции), которые можно перестраивать из событий Event Sourcing.

  3. Производительность
    Запросы могут использовать оптимизированные представления данных, а команды работают с событиями, что снижает нагрузку.

Пример:

// Command (запись)
class CreateOrderCommand {
  execute(data) {
    const event = new OrderCreatedEvent(data);
    eventStore.save(event); // Сохраняем событие
  }
}

// Query (чтение)
class OrdersQuery {
  getOrders() {
    return readModel.getOrders(); // Читаем из проекции
  }
}

Ответ 18+ 🔞

А, слушай, вот эта ваша модная хуйня — Event Sourcing и CQRS. Ну, типа, чтобы не было как у нас в бухгалтерии: одна тётка пишет в журнал, а другая тут же пытается из него же прочитать, да ещё и исправить, и в итоге все друг другу мозги ебут, а журнал похож на помойку после пьянки.

Так вот, Event Sourcing — это когда ты не хранишь итоговую хуйню, а хранишь историю, как в уголовном деле. Не просто «Вася должен 100 рублей». А «1 января: Вася занял 100. 2 января: Вася вернул 50. 3 января: Вася снова занял 20, но уже под проценты, пидарас». Вся цепочка событий, блядь. И состояние системы в любой момент — это просто результат проигрывания всех этих событий с самого начала, как плёнку прокрутить.

А CQRS — это когда ты чётко разделяешь: вот тут мы меняем данные (пишем, командуем), а вот тут — читаем (запрашиваем). Как в армии: один приказывает, другой — исполняет и докладывает. И эти два процесса живут отдельно, не мешая друг другу. А то ведь как бывает: один запрос на чтение такой тяжёлый запустит, что всю систему на запись положит, и все начинают орать «бля, всё легло!».

Их вместе юзают, потому что:

  1. Согласованность, ёпта.
    Event Sourcing следит, чтобы любое изменение было событием — всё по честному, в лог. А CQRS делает так, что чтение и запись не путаются под ногами. Масштабируется проще — читающую часть можно в отдельную базу вынести, хоть на Луну.

  2. Гибкость, мать её.
    CQRS позволяет на основе событий из Event Sourcing наделать кучу разных «представлений» (проекций) для чтения. Нужно тебе отчёт для начальства — одна проекция. Нужно для мобильного приложения — другая. Пересобрал из событий — и поехали. Не надо одну универсальную модель на все случаи жизни городить, которая всё равно никуда не годится.

  3. Производительность, ядрёна вошь.
    Запросы (чтение) летают, потому что бьют в оптимизированную, простую проекцию, специально заточенную под этот конкретный запрос. А команды (запись) просто пишут события — это обычно быстрая операция. И они друг другу не мешают. Красота, блядь.

Вот смотри, как это выглядит в коде, простейший пример:

// Команда (это когда мы что-то меняем, пишем)
class CreateOrderCommand {
  execute(data) {
    // Рождается событие "ЗаказСоздан"
    const event = new OrderCreatedEvent(data);
    // И просто пихается в хранилище событий
    eventStore.save(event); // Всё, записали историю, совесть чиста
  }
}

// Запрос (это когда мы просто хотим посмотреть, что там у нас)
class OrdersQuery {
  getOrders() {
    // А тут мы уже не лезем в события, а читаем из готовой, быстрой проекции
    return readModel.getOrders(); // Всё быстро, никто никому не мешает
  }
}

Вот и вся магия. Не серем в общую кастрюлю, разделяем ответственность, и спим спокойно. А то ведь доверия к этим монолитным системам — ноль ебать.