April 04, 2026

Event Sourcing de Forma Simples (com Exemplos em .NET)

Neste artigo, tento explicar Event Sourcing de forma simples e com uma linguagem mais casual, para facilitar o entendimento desse conceito. Quando comecei a trabalhar com Event Sourcing, tive bastante dificuldade por causa da linguagem muito acadêmica e formal. Aqui, a ideia é trazer uma visão mais amigável e de alto nível de como esse padrão funciona. Ao mesmo tempo, também mostro alguns detalhes de implementação para não ficar só na teoria.


O que é Event Sourcing?

Em vez de salvar o estado final, você armazena eventos que, quando processados, resultam no estado final.

É só isso? Sim!

Esse conceito pode ser expandido, mas vamos começar simples. Veja este aggregate:


public class BankAccount
{
    private decimal balance { get; set; } = 0;
    List<Event> changes = new();

    void When(Event @event)
    {
        switch (@event)
        {
            case Withdraw:
                balance -= @event.amount;
                break;

            case Deposit:
                balance += @event.amount;
                break;
        }
    }
}

Você pode ver que o estado é definido pelos eventos em vez de ser obtido através de uma consulta no banco de dados. Isso é Event Sourcing. Nós armazenamos objetos (eventos) que são responsáveis por alterar o estado das entidades.

Em um sistema bancário, podemos criar eventos como:

  • Withdrawn (Saque)
  • Deposit (Depósito)
  • TaxApplied (Aplicação de taxa)
  • LimitChanged (Alteração de limite)
  • Transfer (Transferência)
  • E muitos outros

Esses eventos são armazenados em um log de eventos, que pode ser um simples List<Event> ou uma solução mais robusta como um Event Store.

O conceito mais importante em Event Sourcing é que o log de eventos é imutável. Não existem updates ou deletes. Na prática, seu banco de dados deve impor uma política que impeça comandos UPDATE e DELETE nessa tabela.

Performance

Imagine uma conta bancária após 20 anos com centenas de milhares de operações, multiplicado por milhões de usuários. Reprocessar todos os eventos toda vez geraria um overhead significativo.

É aí que entram padrões de design para melhorar a performance.

Projeções

Uma projeção mantém o estado atual (final) de uma entidade.

Por exemplo, toda vez que um novo evento acontece no BankAccount, você atualiza um BankAccountProjection com o saldo mais recente. Assim, em vez de recalcular tudo, você sempre tem um estado pronto para uso. Toda vez que um evento acontece, você atualiza o BankAccountProjection.

Se você suspeitar de inconsistência, pode reprocessar todos os eventos e reconstruir o estado. Esse processo é chamado de event replay.

Snapshot

Como você reprocessa 500.000 eventos para milhões de usuários de forma eficiente?

Você não faz isso direto. Você usa snapshots.

A cada N eventos (ex: 50 ou 500), você salva um snapshot do estado atual.

Ao reconstruir, você começa a partir do último snapshot em vez do início. Por exemplo, se existe um snapshot no evento 550.000, você só precisa reprocessar os eventos depois disso.

Isso reduz significativamente o custo computacional.

Coisas legais sobre Event Sourcing

  • Suporta aplicações offline-first (eventos podem ser sincronizados depois)
  • Histórico completo (auditável) de todas as mudanças
  • Capacidade de reconstruir estados passados (voltar no tempo)
  • Útil para analytics, data science e big data
  • Permite simular ou projetar estados futuros

Conceitos que você vai ouvir por aí

Eventual Consistency (Consistência Eventual)

É uma decisão consciente de que o estado pode não estar imediatamente consistente, mas ficará consistente com o tempo.

Exemplo: Você terminou de assistir algo na Netflix, mas no celular ainda aparece como não concluído. Depois de alguns segundos, os sistemas sincronizam e o estado fica correto.

Optimistic Concurrency (Concorrência Otimista)

  • Você adiciona um campo version no aggregate
  • Cada evento espera uma versão específica

Exemplo:

Um evento de saque de $500 espera que a conta esteja na versão 203. Ao salvar, o sistema verifica a versão atual no banco.

Se a versão não for 203, uma exceção é lançada e o usuário precisa refazer a operação.

Ferramentas no ecossistema .NET

  • Marten – Banco NoSQL construído para Event Sourcing com várias funcionalidades nativas
  • Azure Cosmos DB – Armazenamento confiável para eventos
  • Azure Service Bus – Ajuda a distribuir eventos entre sistemas
  • MediatR & CQRS – Ajuda a organizar comandos, queries e notificações de eventos

Meu artigo favorito de Event Sourcing

https://martinfowler.com/eaaDev/EventSourcing.html

Quando eu trabalhava como Software Engineer contratado, eu estava basicamente desesperado. Eu precisava construir um microserviço usando Event Sourcing com projeções, e nada fazia sentido na época.

Depois de ler o artigo do Martin Fowler e ver os exemplos de “Ship”, tudo começou a fazer sentido. Fez tanto sentido que eu nem terminei de ler o artigo inteiro.

Em apenas uma semana, eu já tinha:

  • Um log de eventos implementado
  • O estado sendo construído a partir dos eventos
  • Uma projeção salvando o estado final

Esse artigo foi um ponto de virada para mim no entendimento de Event Sourcing na prática.

Preparei esse treinamento para eu mesmo praticar e relembrar todos os conceitos: https://github.com/gagregori/eventsourcingtraining