CQRS e Event Sourcing em Java: Arquitetura que não teme a complexidade

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Quando o CRUD deixa de dar conta

\n\n

Imagine que você está escrevendo um sistema para negociações em bolsa de valores. A cada segundo — milhares de ordens. Cada ordem não é apenas "inserir um registro". É verificação de saldo, recálculo de portfólio, auditoria, notificações. E agora imagine que você precisa não apenas registrar o estado atual, mas também recuperar o que aconteceu às 14:35:22.003 de ontem. O CRUD (Create, Read, Update, Delete) comum quebra aqui. Bem-vindo ao mundo do CQRS e Event Sourcing em Java.

\n\n

Esses dois padrões não são apenas palavras da moda. São ferramentas que permitem construir sistemas com alta performance, auditoria completa e capacidade de "rebobinar o tempo". Neste artigo, vamos analisar como implementar CQRS (Command Query Responsibility Segregation) e Event Sourcing em Java, usando frameworks modernos e código limpo. Sem enrolação, com exemplos.

\n\n

O que é CQRS em palavras simples

\n\n

CQRS é a separação de responsabilidades entre comandos (escrita) e consultas (leitura). No CRUD clássico, você usa o mesmo modelo para leitura e escrita. No CQRS, você cria dois modelos diferentes: um para alterar dados (comandos), outro para extraí-los (consultas).

\n\n

Por que isso é necessário?

\n
    \n
  • Performance: Leitura e escrita escalam independentemente. Você pode ter 10 réplicas para leitura e 2 para escrita.
  • \n
  • Segurança: Comandos podem verificar regras de negócio, enquanto consultas apenas fornecem dados.
  • \n
  • Flexibilidade: Para leitura, você pode usar visões desnormalizadas; para escrita, visões normalizadas.
  • \n
\n\n

Exemplo de código: Separação de comandos e consultas

\n\n

Suponha que temos um sistema de gerenciamento de pedidos. Em vez de fazer OrderService.save(order), separamos:

\n\n
// Comando — é uma intenção de alterar o estado\npublic class CreateOrderCommand {\n    private final String orderId;\n    private final String customerId;\n    private final List<OrderItem> items;\n\n    // construtor, getters...\n}\n\n// Manipulador do comando\n@Component\npublic class CreateOrderCommandHandler {\n    @Autowired\n    private OrderRepository orderRepository;\n\n    public void handle(CreateOrderCommand command) {\n        // Validação de regras de negócio\n        if (command.getItems().isEmpty()) {\n            throw new IllegalArgumentException("Order must have at least one item");\n        }\n        Order order = new Order(command.getOrderId(), command.getCustomerId(), command.getItems());\n        orderRepository.save(order);\n    }\n}\n\n// Consulta — é a obtenção de dados\npublic class GetOrderQuery {\n    private final String orderId;\n    // construtor, getters...\n}\n\n// Manipulador da consulta\n@Component\npublic class GetOrderQueryHandler {\n    @Autowired\n    private OrderReadRepository orderReadRepository;\n\n    public OrderDTO handle(GetOrderQuery query) {\n        // Leitura direta de um banco de dados otimizado\n        return orderReadRepository.findById(query.getOrderId());\n    }\n}
\n\n

Observe: OrderRepository (escrita) e OrderReadRepository (leitura) são interfaces diferentes. Elas podem apontar para bancos de dados diferentes ou esquemas diferentes.

\n\n

Event Sourcing: Armazenamos não o estado, mas a história

\n\n

Event Sourcing é um padrão no qual salvamos não o estado atual de um objeto, mas a sequência de eventos que levaram a esse estado. Em vez de "Pedido nº 123: status = DELIVERED", armazenamos: "Evento 1: Pedido criado", "Evento 2: Item adicionado", "Evento 3: Pedido pago", "Evento 4: Pedido entregue".

\n\n

Como funciona em Java

\n\n

Cada evento é um objeto imutável (immutable). Nós os salvamos em um Event Store (banco de dados especializado). O estado atual do agregado é calculado reproduzindo (replaying) todos os eventos.

\n\n
// Evento base\npublic interface Do                

Blogs

Book Recommendations