CQRS e Event Sourcing em JavaScript: arquitetura para sistemas complexos

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

Por que CQRS e Event Sourcing não são "para poucos"?

\n\n

Quando ouvimos as expressões "CQRS" ou "Event Sourcing", muitos desenvolvedores JavaScript imaginam algo do mundo da arquitetura enterprise em Java ou C#. Esquemas complexos, eventos infinitos, armazenamentos estranhos... Mas e se eu disser que esses padrões podem (e devem!) ser usados em aplicações Node.js comuns?

\n\n

Neste artigo, vamos entender como CQRS e Event Sourcing ajudam a resolver problemas reais: conflitos de dados, logging complexo, escalabilidade e depuração. E tudo isso — em JavaScript puro, sem mágica ou frameworks complexos.

\n\n

O que é CQRS (Command Query Responsibility Segregation)?

\n\n

Imagine que sua aplicação é um restaurante. Os garçons (consultas) e os cozinheiros (comandos) trabalham no mesmo ambiente. Mais cedo ou mais tarde, eles começarão a atrapalhar uns aos outros. O CQRS propõe separar essas zonas: os garçons trabalham no salão (leitura), e os cozinheiros, na cozinha (escrita).

\n\n

CQRS é o princípio de separar as operações em dois canais:

\n
    \n
  • Comandos (Commands) — alteram o estado do sistema (Create, Update, Delete)
  • \n
  • Consultas (Queries) — apenas leem dados (Read)
  • \n
\n\n

Em uma API REST clássica, geralmente usamos o mesmo objeto para leitura e escrita. Por exemplo, UserController contém os métodos GET /users/:id e POST /users. O CQRS propõe separá-los em camadas diferentes.

\n\n

Exemplo simples de CQRS em JavaScript

\n\n
// Comando (alteração de estado)\nclass CreateUserCommand {\n    constructor(name, email) {\n        this.name = name;\n        this.email = email;\n    }\n}\n\nclass UserCommandHandler {\n    async handle(command) {\n        // Validação, lógica de negócio, persistência\n        return await db.users.insert({\n            name: command.name,\n            email: command.email,\n            created_at: new Date()\n        });\n    }\n}\n\n// Consulta (apenas leitura)\nclass GetUserQuery {\n    constructor(userId) {\n        this.userId = userId;\n    }\n}\n\nclass UserQueryHandler {\n    async handle(query) {\n        // Apenas leitura, nenhuma alteração!\n        return await db.users.findOne({ _id: query.userId });\n    }\n}
\n\n

Parece que isso complica o código? Sim, à primeira vista. Mas quando sua aplicação crescer para 50+ endpoints, a separação de comandos e consultas vai te salvar de:

\n
    \n
  • Alterações acidentais de dados em requisições GET
  • \n
  • Problemas com cache (consultas são fáceis de cachear, comandos não)
  • \n
  • Conflitos durante o trabalho paralelo de vários desenvolvedores
  • \n
\n\n

Event Sourcing: registrando cada ação

\n\n

Agora imagine que, em vez de armazenar o estado atual do usuário, você armazena todos os eventos que ocorreram com ele. Não "Ivan, 25 anos, Moscou", mas uma sequência:

\n
    \n
  1. "Usuário criado: Ivan"
  2. \n
  3. "Usuário alterou a idade para 25"
  4. \n
  5. "Usuário mudou-se para Moscou"
  6. \n
\n\n

Event Sourcing é um padrão onde cada alteração de estado é salva como um evento imutável. O estado atual é calculado "reproduzindo" todos os eventos.

\n\n

Implementação de um Event Store em JavaScript

\n\n
class EventStore {\n    constructor() {\n        this.events = [];\n    }\n\n    append(aggregateId, event) {\n        this.events.push({\n            aggregateId,\n            event,\n            timestamp: new Date()\n        });\n    }\n\n    getEvents(aggregateId) {\n        return this.events.filter(e => e.aggregateId === aggregateId);\n    }\n}\n\n// Reconstrução do estado a partir dos eventos\nfunction rebuildState(events) {\n    return events.reduce((state, event) => {\n        switch(event.event.type) {\n            case 'USER_CREATED':\n                return { ...state, name: event.event.name, age: 0 };\n            case                

Blogs

Book Recommendations