Muita gente olha para Event Sourcing e entende apenas uma coisa:
"vou guardar tudo que aconteceu".
Essa leitura é incompleta.
Guardar histórico pode ser útil, mas não é o ponto central.
Event Sourcing muda a fonte de verdade do sistema.
Em vez de persistir apenas o estado atual de uma entidade, você persiste os fatos que levaram aquele estado a existir.
O saldo de uma conta não é salvo como um número solto.
Ele é consequência de depósitos, saques, tarifas, estornos e ajustes.
O status de um pedido não é apenas PAID ou CANCELLED.
Ele é resultado de uma sequência: pedido criado, pagamento aprovado, estoque reservado, entrega iniciada, cancelamento solicitado, estorno confirmado.
Essa diferença parece conceitual.
Na prática, ela muda persistência, integração, auditoria, replay, debugging e o jeito como o time pensa sobre consistência.
Estado é uma fotografia
O modelo mais comum em aplicações CRUD persiste o estado atual.
Uma tabela orders tem colunas como:
id
customer_id
status
total_amount
created_at
updated_at
Quando algo muda, a linha é atualizada.
O pedido que antes estava CREATED passa a estar PAID.
Depois passa a estar SHIPPED.
Talvez um log auxiliar registre parte da história. Talvez uma tabela de auditoria capture algumas alterações. Talvez ninguém capture nada.
O ponto é que a tabela principal representa a fotografia mais recente.
Esse modelo é simples, direto e funciona muito bem em muitos sistemas.
O problema aparece quando a história importa tanto quanto o estado atual.
Por que o pedido foi cancelado?
Quem aprovou o ajuste?
Qual era o saldo antes do estorno?
Qual evento externo provocou a mudança?
O sistema aplicou as regras na ordem correta?
Se a única fonte confiável é a fotografia final, essas perguntas viram arqueologia.
Você tenta reconstruir intenção a partir de colunas, timestamps, logs, traces e sorte.
Event Sourcing começa dizendo: a fotografia não basta.
Fato não é comando
Antes de falar de armazenamento, vale separar duas coisas que muita arquitetura mistura: comando e evento.
Um comando pede que algo aconteça.
Um evento afirma que algo aconteceu.
CancelOrder é um comando.
OrderCancelled é um fato.
O comando pode ser rejeitado.
O evento não deveria representar uma tentativa, uma intenção vaga ou uma possibilidade futura.
Ele representa uma mudança já aceita pelo domínio.
Essa diferença é importante porque Event Sourcing armazena eventos de domínio, não comandos pendentes.
Se o cliente pede cancelamento de um pedido que já foi entregue, o sistema pode rejeitar o comando.
Nesse caso, não existe OrderCancelled.
Talvez exista OrderCancellationRejected, se essa rejeição for relevante para o domínio.
Mas isso é outro fato.
Em Event Sourcing, a sequência gravada precisa contar a história do que o domínio aceitou como verdade.
Não basta despejar mensagens técnicas em um log e chamar isso de arquitetura orientada a eventos.
O estado nasce do replay
Em um modelo event sourced, o estado atual é reconstruído a partir dos eventos.
Imagine um agregado de pedido com esta sequência:
OrderCreated
OrderItemAdded
OrderItemAdded
PaymentApproved
StockReserved
OrderShipped
Para saber o estado atual, a aplicação carrega os eventos daquele pedido e reaplica a sequência em memória.
Depois do OrderCreated, o pedido existe.
Depois dos OrderItemAdded, ele tem itens.
Depois do PaymentApproved, ele está pago.
Depois do StockReserved, pode seguir para envio.
Depois do OrderShipped, não pode mais ser cancelado por uma regra simples.
O estado não desaparece.
Ele continua existindo.
A diferença é que ele passa a ser derivado.
A fonte de verdade é a lista ordenada de fatos.
Isso permite reconstruir o presente, mas também permite entender como o presente foi formado.
E, quando bem usado, permite criar novas projeções a partir da mesma história.
Kafka parece natural, mas não resolve tudo
Kafka combina muito bem com a ideia de fatos ordenados.
Ele é um log distribuído.
Ele permite retenção.
Ele permite múltiplos consumidores.
Ele permite replay.
É tentador olhar para isso e concluir:
"então Kafka é meu event store".
Às vezes pode ser parte importante da solução.
Mas essa decisão precisa ser feita com cuidado.
Um event store precisa preservar a sequência de eventos de um agregado, controlar concorrência, impedir escrita conflitante, manter contratos evolutivos, permitir leitura eficiente da história relevante e sustentar o processo de reconstrução do estado.
Kafka oferece ordenação dentro de uma partição.
Isso significa que a chave do evento passa a ser crítica.
Se eventos do mesmo agregado caem em partições diferentes, a ordem que interessa ao domínio já foi perdida.
Além disso, Kafka é excelente para distribuir fatos para consumidores, mas nem sempre é a melhor interface para carregar rapidamente a história de um único agregado durante uma transação de negócio.
Dependendo do volume, da retenção, da compactação, da necessidade de snapshots e da forma de consulta, pode fazer sentido usar um event store dedicado, um banco modelado para append-only ou uma combinação em que o store persiste a verdade e Kafka distribui os eventos.
Kafka ajuda muito.
Mas Event Sourcing não nasce automaticamente porque existe um tópico.
Append-only muda o tipo de problema
Quando você persiste fatos, a operação principal deixa de ser update e passa a ser append.
Você não sobrescreve que um pedido está cancelado.
Você acrescenta o fato OrderCancelled.
Isso traz vantagens.
Auditoria fica mais natural.
Replay passa a ser possível.
O histórico não depende de logs secundários.
Projeções podem ser reconstruídas.
Correções podem ser expressas como novos eventos, em vez de mutações silenciosas.
Mas também traz custos.
Você precisa lidar com evolução de schema.
Precisa decidir o que fazer com eventos antigos.
Precisa pensar em snapshots quando a história de um agregado cresce demais.
Precisa proteger a ordem por agregado.
Precisa garantir idempotência nos consumidores.
Precisa desenhar projeções para leitura, porque consultar diretamente o log de eventos para toda tela costuma ser uma péssima experiência operacional.
Append-only reduz alguns tipos de inconsistência, mas cria uma disciplina nova.
Sem essa disciplina, o sistema vira apenas um histórico caro e difícil de consultar.
Projeções são parte do desenho
Um erro comum é achar que Event Sourcing elimina modelos de leitura.
Na prática, ele torna os modelos de leitura mais explícitos.
O log de eventos responde muito bem à pergunta:
"o que aconteceu?"
Mas uma tela, um relatório ou uma API muitas vezes pergunta:
"qual é a visão atual que eu preciso exibir agora?"
Essa visão normalmente é uma projeção.
Um consumidor lê os eventos e materializa uma estrutura otimizada para consulta.
Pode ser uma tabela relacional.
Pode ser um índice de busca.
Pode ser um documento.
Pode ser um cache.
O importante é não confundir projeção com fonte de verdade.
Se a projeção atrasar, ela pode ser reconstruída.
Se a projeção corromper, ela pode ser descartada e refeita a partir dos eventos.
Esse é um dos grandes ganhos do modelo.
Mas ele só existe se os eventos realmente carregam informação suficiente e se a retenção da história permite reconstrução.
Se os eventos dependem de consultar estado externo que já mudou, o replay deixa de ser confiável.
Nem todo histórico é Event Sourcing
Salvar uma tabela de auditoria não é, por si só, Event Sourcing.
Publicar eventos no Kafka também não.
Ter CDC em cima do banco também não.
Essas técnicas podem participar de uma arquitetura orientada a eventos, mas Event Sourcing exige uma decisão mais profunda:
o sistema reconstrói seu estado a partir dos eventos?
As regras de negócio aplicam novos comandos considerando a história do agregado?
Os eventos são fatos de domínio, e não apenas diffs técnicos de tabela?
Existe controle de concorrência para impedir duas histórias incompatíveis?
Existe estratégia para evolução desses eventos ao longo do tempo?
Se a resposta for não, talvez você tenha integração por eventos, auditoria, outbox, CDC ou logs de alteração.
Tudo isso pode ser útil.
Mas não é a mesma coisa.
Chamar tudo de Event Sourcing só aumenta a confusão.
Quando faz sentido
Event Sourcing costuma fazer sentido quando a história é parte essencial do domínio.
Sistemas financeiros.
Esteiras de aprovação.
Pedidos com ciclo de vida complexo.
Compliance.
Controle de inventário.
Processos longos com compensações.
Domínios onde explicar "como chegamos aqui" é tão importante quanto saber "onde estamos agora".
Também pode fazer sentido quando o negócio precisa criar novas leituras sobre fatos antigos.
Um time pode descobrir depois que precisa calcular métricas com outra regra, alimentar uma nova projeção ou reprocessar um fluxo corrigido.
Se a história está preservada como fatos bem modelados, isso é possível.
Se só existe o estado atual, o passado foi compactado sem volta.
Mas a decisão precisa ser econômica.
Event Sourcing cobra em complexidade de modelagem, infraestrutura, testes, ferramentas, observabilidade e maturidade do time.
Aplicar o padrão em cadastro simples, CRUD administrativo ou domínio sem necessidade real de histórico tende a produzir sofisticação sem retorno.
A pergunta principal
A pergunta não é:
"devo usar Event Sourcing porque uso Kafka?"
A pergunta é:
"o meu domínio precisa tratar a história como fonte de verdade?"
Se precisa, Event Sourcing pode ser uma ferramenta poderosa.
Kafka pode ajudar na distribuição, no replay e na integração entre consumidores.
Mas a parte difícil continua sendo modelar os fatos certos, preservar ordem, evoluir contratos, construir projeções e operar o fluxo com clareza.
Se não precisa, talvez um modelo de estado atual com eventos bem publicados, Outbox Pattern e consumidores idempotentes resolva melhor.
Arquitetura boa não é a que guarda tudo.
É a que sabe o que precisa ser verdade.
Event Sourcing vale quando os fatos são essa verdade.
