CQRS e Event Sourcing em Swift: Arquitetura para Projetos 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 a arquitetura tradicional não dá conta das tarefas modernas?

\n\n

Você já se deparou com uma situação em que adicionar um simples novo recurso em um aplicativo Swift se transforma em um pesadelo? Bugs surgem, dados são perdidos e a lógica cresce a proporções incríveis? Familiar? Bem-vindo ao mundo onde CQRS e Event Sourcing se tornam seus melhores amigos.

\n\n

Esses padrões não são apenas palavras da moda. São uma forma de pensar que muda radicalmente a abordagem para construir aplicativos em Swift. E hoje vamos analisá-los com exemplos reais. Sem enrolação, sem teorias complicadas — apenas prática.

\n\n

O que é CQRS? Dividir para conquistar

\n\n

CQRS (Command Query Responsibility Segregation) é um princípio que diz: "Chega de misturar leitura e escrita na mesma classe". Parece simples, mas as consequências são enormes.

\n\n

Na arquitetura CRUD (Create, Read, Update, Delete) clássica, você usa um único modelo para tudo. Por exemplo, User. Ele é salvo, lido e atualizado. E se para a leitura forem necessários alguns campos e para a escrita, outros? Começam as gambiarras: campos opcionais, flags, mapeamentos...

\n\n

O CQRS propõe separar as responsabilidades:

\n
    \n
  • Comandos (Commands) — alteram o estado. Eles modificam dados, mas não retornam nada.
  • \n
  • Consultas (Queries) — leem dados. Eles não alteram o estado, apenas retornam um resultado.
  • \n
\n\n

Em Swift, isso pode ser assim:

\n\n
// Comando — apenas mutação\nstruct CreateUserCommand {\n    let id: UUID\n    let name: String\n    let email: String\n}\n\n// Consulta — apenas leitura\nstruct GetUserQuery {\n    let userId: UUID\n}\n\n// Manipulador do comando\nclass CreateUserCommandHandler {\n    func handle(_ command: CreateUserCommand) {\n        // Lógica de criação do usuário\n        print("Usuário criado: \\(command.name)")\n    }\n}\n\n// Manipulador da consulta\nclass GetUserQueryHandler {\n    func handle(_ query: GetUserQuery) -> User? {\n        // Lógica de obtenção do usuário\n        return User(id: query.userId, name: "Alexei", email: "alex@example.com")\n    }\n}
\n\n

Viu? Nenhuma mistura. Cada classe faz exatamente uma coisa. Isso simplifica testes, manutenção e escalabilidade.

\n\n

Event Sourcing: Armazenando o histórico, não o estado

\n\n

Agora vamos para o Event Sourcing — um padrão que armazena não o estado atual de um objeto, mas toda a sequência de eventos que levaram a ele.

\n\n

Imagine uma conta bancária. Em vez de armazenar o saldo (1000 reais), você armazena uma lista de eventos: "Abertura de conta", "Depósito de 500", "Saque de 200", "Depósito de 700". Para saber o saldo atual, você simplesmente reproduz todos os eventos. Isso oferece possibilidades incríveis: auditoria, reversão de alterações, análise.

\n\n

Vamos implementar isso em Swift:

\n\n
// Evento\nprotocol Event {}\n\nstruct AccountCreated: Event {\n    let accountId: UUID\n    let initialBalance: Double\n}\n\nstruct MoneyDeposited: Event {\n    let accountId: UUID\n    let amount: Double\n}\n\nstruct MoneyWithdrawn: Event {\n    let accountId: UUID\n    let amount: Double\n}\n\n// Agregado — restaura o estado a partir dos eventos\nclass BankAccount {\n    private(set) var balance: Double = 0\n    private(set) var isActive: Bool = false\n    private(set) var accountId: UUID?\n\n    func apply(_ event: Event) {\n        switch event {\n        case let created as AccountCreated:\n            accountId = created.accountId\n            balance = created.initialBalance\n            isActive = true\n        case let deposited as MoneyDeposited:\n            balance += deposited.amount\n        case let withdrawn as MoneyWithdrawn:\n            balance -= withdrawn.amount\n        default:\n            break\n        }\n    }\n\n    // Restauração a partir do histórico de eventos\n    static func load(from history: [Event]) -> BankAccount {\n        l                

Blogs

Book Recommendations