Entendendo CQRS e Event Sourcing.

RMAG news

Introdução

Na arquitetura de software moderna, garantir escalabilidade, manutenibilidade e desempenho é crucial. Dois padrões que ajudam a alcançar esses objetivos são CQRS (Command Query Responsibility Segregation) e Event Sourcing. Este artigo explora esses conceitos, seus benefícios e como podem ser implementados.

O que é CQRS?

CQRS significa Segregação de Responsabilidade de Comando e Consulta. É um padrão que separa operações de leitura e escrita para um banco de dados. Tradicionalmente, operações CRUD (Criar, Ler, Atualizar, Deletar) são realizadas em um único modelo, o que pode levar à complexidade e ineficiência, especialmente em sistemas de grande escala.

Benefícios do CQRS

Escalabilidade: Ao separar leituras e escritas, cada uma pode ser escalada independentemente.

Desempenho: Os modelos de leitura podem ser otimizados para consultas, e os modelos de escrita podem ser otimizados para atualizações.

Modelos Simplificados: A separação de preocupações torna a base de código mais limpa e fácil de manter.

Implementando CQRS

Em um sistema CQRS, comandos (escritas) e consultas (leituras) são manipulados por diferentes modelos:

Modelo de Comando: Manipula operações que mudam o estado (ex.: criar, atualizar, deletar).

Modelo de Consulta: Manipula operações somente de leitura (ex.: buscar dados).

Aqui está um exemplo básico usando TypeScript:

// Modelo de Comando
class CreateUserCommand {
constructor(public name: string, public email: string) {}
}

class UserCommandHandler {
handle(command: CreateUserCommand): void {
// Lógica para manipular a criação do usuário
// ex.: salvar no banco de dados
}
}

// Modelo de Consulta
class UserQuery {
constructor(public id: string) {}
}

class UserQueryHandler {
handle(query: UserQuery): User | null {
// Lógica para buscar dados do usuário
// ex.: recuperar do banco de dados
return { id: query.id, name: John Doe, email: john.doe@example.com };
}
}

O que é Event Sourcing?

Event Sourcing é um padrão onde mudanças de estado são capturadas como uma sequência de eventos. Em vez de armazenar o estado atual, o sistema armazena uma série de eventos que descrevem transições de estado.

Benefícios do Event Sourcing

Auditabilidade: Cada mudança é registrada, fornecendo um histórico completo.

Reprodução de Eventos: O estado do sistema pode ser reconstruído reproduzindo eventos.

Desacoplamento: Eventos podem ser usados para integrar com outros sistemas de forma assíncrona.

Implementando Event Sourcing

Em um sistema baseado em eventos, mudanças de estado são representadas como eventos:

// Evento
class UserCreatedEvent {
constructor(public id: string, public name: string, public email: string) {}
}

// Armazenamento de Eventos
class EventStore {
private events: Array<any> = [];

save(event: any): void {
this.events.push(event);
}

getEvents(): Array<any> {
return this.events;
}
}

// Agregado
class User {
private id: string;
private name: string;
private email: string;

constructor(private eventStore: EventStore) {}

create(id: string, name: string, email: string): void {
const event = new UserCreatedEvent(id, name, email);
this.apply(event);
this.eventStore.save(event);
}

private apply(event: UserCreatedEvent): void {
this.id = event.id;
this.name = event.name;
this.email = event.email;
}
}

// Uso
const eventStore = new EventStore();
const user = new User(eventStore);
user.create(1, John Doe, john.doe@example.com);

console.log(eventStore.getEvents());

Combinando CQRS e Event Sourcing

CQRS e Event Sourcing se complementam bem. Event Sourcing se encaixa naturalmente no lado de escrita do CQRS, onde comandos resultam em eventos que são armazenados e processados. O lado de leitura pode usar esses eventos para construir modelos de consulta.

Exemplo

// Modelo de Comando (Baseado em Eventos)
class UserCommandHandler {
constructor(private eventStore: EventStore) {}

handle(command: CreateUserCommand): void {
const event = new UserCreatedEvent(command.name, command.email);
this.eventStore.save(event);
}
}

// Modelo de Consulta
class UserReadModel {
private users: { [key: string]: User } = {};

handleEvent(event: UserCreatedEvent): void {
this.users[event.id] = new User(event.id, event.name, event.email);
}

getUser(id: string): User | null {
return this.users[id] || null;
}
}

// Uso
const eventStore = new EventStore();
const userCommandHandler = new UserCommandHandler(eventStore);
const userReadModel = new UserReadModel();

userCommandHandler.handle(new CreateUserCommand(John Doe, john.doe@example.com));
eventStore.getEvents().forEach(event => userReadModel.handleEvent(event));

console.log(userReadModel.getUser(1));

Please follow and like us:
Pin Share