Local-First
CRDT
Sincronização de Dados
Arquitetura
Tempo Real

CRDTs: como sincronizar dados sem servidor para arbitrar conflitos

CRDTs resolvem o problema mais difícil do local-first: mesclar edições offline sem perder dados e sem um servidor central para decidir quem ganha.

Imagine dois usuários editando o mesmo documento em aviões diferentes, sem internet. Cada um altera o mesmo campo. Quando pousam e os aparelhos sincronizam, alguém precisa decidir qual versão vence. A resposta tradicional foi simples e brutal: o último a salvar sobrescreve o anterior. O outro perde o trabalho e nem percebe.

Esse é o problema central de qualquer aplicação local-first. O dado vive primeiro no dispositivo, a edição acontece offline e a reconciliação vem depois. A pergunta não é se haverá conflito, é como mesclar duas verdades divergentes sem perder informação e, idealmente, sem depender de um servidor central agindo como juiz. CRDTs são a resposta matemática mais elegante que temos para isso.

O que é um CRDT, sem misticismo

CRDT é a sigla de Conflict-free Replicated Data Type, ou tipo de dado replicado livre de conflito. O nome assusta mais que o conceito. Na prática, é uma estrutura de dados projetada para que múltiplas cópias possam ser editadas de forma independente e, quando se encontrarem, convirjam automaticamente para o mesmo estado final, sem coordenação prévia.

A palavra-chave é convergência. Não importa a ordem em que as alterações chegam, nem quantas vezes a mesma alteração é aplicada, nem por quantos saltos ela passou na rede. Se dois dispositivos viram o mesmo conjunto de operações, eles terminam idênticos. Essa garantia é matemática, não uma promessa de boa vontade do código.

Para conseguir isso, as operações de um CRDT precisam ter três propriedades. Elas são comutativas, então a ordem não altera o resultado. São associativas, então o agrupamento não importa. E são idempotentes, então aplicar a mesma coisa duas vezes não causa estrago. Estruturas que respeitam essas regras formam o que a matemática chama de semilattice, e é dela que vem a garantia de convergência.

Por que isso resolve o problema do local-first

Sem CRDTs, sincronizar offline exige um árbitro. Normalmente um servidor que recebe todas as versões, aplica uma regra qualquer, frequentemente o famigerado last-write-wins, e devolve a verdade oficial. Isso tem dois custos. O dado perdido na sobrescrita, e a dependência de um ponto central sempre online para resolver qualquer divergência.

CRDTs dissolvem essa dependência. Como a mesclagem é determinística e embutida na própria estrutura, qualquer dispositivo pode reconciliar com qualquer outro, em qualquer topologia. Dois celulares podem sincronizar direto via Bluetooth, três réplicas podem se ajustar em malha, e o resultado é o mesmo que teriam com um servidor coordenando tudo. O servidor, quando existe, vira apenas um relay conveniente, não uma autoridade.

Isso muda a natureza da aplicação. O usuário não espera resposta de rede para ver sua edição aplicada, porque a verdade local já é válida. A sincronização acontece em segundo plano e nunca volta dizendo "seu trabalho foi descartado". É o que torna a experiência de apps como editores colaborativos modernos tão fluida, e é a fundação técnica de qualquer arquitetura local-first séria.

Os sabores de CRDT que você vai encontrar

Dois grandes estilos dominam. Os CRDTs baseados em estado, ou state-based, trocam a estrutura inteira entre réplicas e usam uma função de merge para combinar. São simples de raciocinar, mas pesados na rede quando o dado cresce. Os baseados em operação, ou op-based, propagam apenas as mudanças individuais, o que é mais econômico, porém exige uma camada de entrega confiável das operações.

Acima desses estilos existe um catálogo de tipos prontos. Contadores que somam incrementos de várias réplicas sem perder nenhum. Conjuntos que sabem mesclar adições e remoções de forma coerente, como o OR-Set. E o caso mais cobiçado, o texto sequencial, onde cada caractere recebe um identificador único e ordenável para que inserções concorrentes não se atropelem. Algoritmos como Yjs e Automerge empacotam tudo isso em bibliotecas que você usa sem reimplementar a teoria.

A boa notícia para quem decide arquitetura é que raramente se escreve um CRDT do zero. Você escolhe a biblioteca, modela seus dados sobre os tipos que ela oferece e ganha a convergência de brinde. O trabalho intelectual está em mapear o domínio para essas estruturas, não em provar teoremas.

Onde os CRDTs realmente brilham

Eles são imbatíveis quando a regra de mesclagem é genuinamente neutra, ou seja, quando manter as duas edições é sempre o comportamento correto. Texto colaborativo é o exemplo perfeito: se duas pessoas digitam em parágrafos diferentes, você quer os dois parágrafos, ponto. Listas, quadros kanban, anotações, desenhos vetoriais e a maioria das ferramentas de produtividade colaborativa caem nessa categoria.

Também brilham em cenários de conectividade ruim ou intermitente por natureza. Aplicações de campo, coleta de dados em áreas remotas, dispositivos que passam horas offline. Em aplicações offline-first, o CRDT é o que permite trabalhar com confiança total de que nada será descartado na próxima sincronização. A convergência automática é exatamente a garantia que esses contextos exigem.

E brilham quando você quer eliminar o servidor do caminho crítico. Arquiteturas peer-to-peer, malhas locais, sincronização entre dispositivos do mesmo usuário sem passar pela nuvem. Tudo isso fica viável porque a inteligência da mesclagem mora no dado, não na infraestrutura.

Onde eles não são a resposta certa

Aqui está a parte que costuma ser varrida para baixo do tapete. CRTDs convergem para um estado válido, mas não necessariamente para o estado que o seu negócio considera correto. Convergência não é sinônimo de regra de negócio satisfeita. Se duas pessoas reservam o último assento de um voo offline, o CRDT vai mesclar ambas as reservas alegremente, e você terá uma garantia matemática de overbooking.

Conflitos que exigem decisão semântica não pertencem ao CRDT. Saldo que não pode ficar negativo, unicidade de um campo, aprovação que invalida outra, qualquer invariante que precise de um "não, isso não pode acontecer" quer um árbitro de verdade. Nesses casos, a regra de negócio precisa decidir o conflito, e tentar empurrar isso para a camada de dados produz bugs sutis e caros.

Há também o custo de memória e armazenamento. Para garantir a convergência, muitos CRDTs guardam metadados que crescem com o histórico de edições. Tombstones de itens removidos, identificadores por caractere, vetores de versão. Sem estratégias de compactação, uma estrutura aparentemente pequena pode inchar de forma surpreendente. Nem todo problema vira CRDT de forma barata, e nem todo problema deveria virar.

Minha recomendação como CTO é pragmática. Use CRDT onde a mesclagem é naturalmente aditiva e o ganho de experiência é real. Onde a correção depende de uma invariante de negócio, aceite um árbitro, seja um servidor, uma fila de comandos ou um fluxo de resolução explícito apresentado ao usuário. O erro mais comum é tratar CRDT como bala de prata e descobrir o overbooking em produção.

Se você está desenhando a camada de sincronização de um produto local-first agora, vale separar com clareza o que é mesclável automaticamente do que precisa de decisão humana ou de servidor antes de escolher a ferramenta. Essa divisão honesta vai economizar meses de retrabalho.

Leia também