Ответ
Event Sourcing (источники событий) — это архитектурный паттерн, при котором состояние системы реконструируется путем последовательного применения всех произошедших событий. Вместо хранения текущего состояния (state), система хранит полную историю изменений в виде неизменяемых событий.
Ключевые принципы:
- Все изменения — это события. Любая операция, изменяющая состояние (например,
UserRegistered,OrderPlaced), сохраняется как отдельное событие в хранилище. - События неизменяемы (immutable). Однажды записанное событие никогда не изменяется и не удаляется. Для отмены используется компенсирующее событие (например,
OrderCancelled). - Состояние — это проекция событий. Текущее состояние объекта (например, баланс счета) получается путем "проигрывания" всех его событий с самого начала.
Упрощенный пример на Python:
# События
class AccountOpened:
def __init__(self, account_id):
self.account_id = account_id
class MoneyDeposited:
def __init__(self, amount):
self.amount = amount
class MoneyWithdrawn:
def __init__(self, amount):
self.amount = amount
# Агрегат (сущность)
class BankAccount:
def __init__(self):
self.id = None
self.balance = 0
def apply(self, event):
"""Применяет событие для изменения состояния"""
if isinstance(event, AccountOpened):
self.id = event.account_id
elif isinstance(event, MoneyDeposited):
self.balance += event.amount
elif isinstance(event, MoneyWithdrawn):
self.balance -= event.amount
@staticmethod
def replay(events):
"""Восстанавливает состояние из списка событий"""
account = BankAccount()
for event in events:
account.apply(event)
return account
# Использование
event_stream = [
AccountOpened(account_id='acc-123'),
MoneyDeposited(amount=100),
MoneyWithdrawn(amount=30)
]
# Восстанавливаем текущее состояние
current_account_state = BankAccount.replay(event_stream)
print(f"Account ID: {current_account_state.id}, Balance: {current_account_state.balance}")
# -> Account ID: acc-123, Balance: 70
Преимущества:
- Полный аудит: Легко отследить, как система пришла в текущее состояние.
- Отладка и "путешествия во времени": Возможность восстановить состояние на любой момент времени.
- Гибкость: Можно создавать новые проекции данных (read models) из существующего потока событий, не меняя основную логику.
Недостатки:
- Сложность реализации: Требует иного подхода к проектированию по сравнению с традиционным CRUD.
- Согласованность в конечном счете (Eventual Consistency): Часто используется с CQRS, что приводит к задержкам в обновлении моделей для чтения.
Ответ 18+ 🔞
Да ты послушай, что эти умники придумали! Event Sourcing, блядь, источники событий. Это ж надо было так мозги закрутить, ёпта! Вместо того чтобы просто хранить, сколько у тебя на счету денег, они предлагают записывать КАЖДУЮ, сука, операцию, как в бухгалтерской книге. Каждое "пополнил", "снял", "открыл счет" — всё это отдельные, блядь, неизменяемые события. Как каменные скрижали, нахуй!
Представь, ты не помнишь, сколько у тебя денег, но у тебя есть полная история твоих трат и пополнений. Чтобы узнать баланс, тебе надо, блядь, взять калькулятор и просуммировать всю эту хуйню с самого начала. Вот это и есть Event Sourcing, ёбана!
Соль, блядь, в чём:
- Всякая хрень — это событие. Зарегистрировался юзер? Событие
UserRegistered. Купил что-то? СобытиеOrderPlaced. Всё летит в хранилище, как есть. - События — это святое. Записал — и нихуя не трогаешь. Хочешь отменить? Ну так запиши новое событие, компенсирующее, типа
OrderCancelled. Нельзя просто взять и стереть, это ж не школьный дневник, блядь! - Состояние — это иллюзия, проекция! Твой текущий баланс — это просто результат проигрывания ВСЕХ событий по твоему счету, от первого до последнего. Как кинолента, ёпта!
Смотри, как это выглядит в коде, чтоб не быть голословным:
# События
class AccountOpened:
def __init__(self, account_id):
self.account_id = account_id
class MoneyDeposited:
def __init__(self, amount):
self.amount = amount
class MoneyWithdrawn:
def __init__(self, amount):
self.amount = amount
# Агрегат (сущность)
class BankAccount:
def __init__(self):
self.id = None
self.balance = 0
def apply(self, event):
"""Применяет событие для изменения состояния"""
if isinstance(event, AccountOpened):
self.id = event.account_id
elif isinstance(event, MoneyDeposited):
self.balance += event.amount
elif isinstance(event, MoneyWithdrawn):
self.balance -= event.amount
@staticmethod
def replay(events):
"""Восстанавливает состояние из списка событий"""
account = BankAccount()
for event in events:
account.apply(event)
return account
# Использование
event_stream = [
AccountOpened(account_id='acc-123'),
MoneyDeposited(amount=100),
MoneyWithdrawn(amount=30)
]
# Восстанавливаем текущее состояние
current_account_state = BankAccount.replay(event_stream)
print(f"Account ID: {current_account_state.id}, Balance: {current_account_state.balance}")
# -> Account ID: acc-123, Balance: 70
Видишь? Мы не храним цифру 70. Мы храним три события: открыли, положили 100, сняли 30. А 70 — это просто результат их применения. Красота, блядь!
Чем это, сука, хорошо:
- Аудит полный, как в НКВД. Всегда можно докопаться, кто, что и когда сделал. Идеально для параноиков.
- Отладка и "путешествия во времени". Хочешь узнать, какой был баланс в прошлый вторник? Пожалуйста, проиграй события до этого момента. Машина времени, ёпта!
- Гибкость овердохуищная. Из одного потока событий можно наделать кучу разных "представлений" данных, не трогая основную логику. Как из одного куска мяса и котлету, и гуляш.
Чем это, блядь, плохо:
- Сложность пиздец. Голову сломаешь, пока перестроишь мышление с обычного CRUD на эту философию.
- Согласованность в конечном счёте (Eventual Consistency). Часто эту штуку используют с CQRS, и получается, что данные в "читаемых" моделях обновляются с небольшой задержкой. То есть ты положил деньги, а в выписке они появятся не сразу. Может, через секунду, а может, и через пять. Волнение ебать, особенно если ждёшь подтверждения платежа!
В общем, инструмент мощный, но не для каждой задачи. Как молоток Тора — им гвоздь в стену не забьёшь, зато можно, блядь, целый мир перестроить.