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"));
Top comments (0)