10 pontos por GN⁺ 2025-09-23 | 1 comentários | Compartilhar no WhatsApp
  • Apps local-first prometem respostas rápidas e privacidade garantida por padrão, mas têm a limitação de que implementar suporte offline de verdade é extremamente difícil
  • O principal motivo é a complexidade da sincronização; quando vários dispositivos alteram os dados ao mesmo tempo, surge o problema de que eles precisam convergir exatamente para o mesmo estado no fim
  • Existem dois grandes desafios técnicos: incerteza na ordem temporal e conflitos
  • Para resolver isso, é necessário aplicar abordagens de sistemas distribuídos como Hybrid Logical Clocks(HLCs) e CRDTs
  • Ao aproveitar extensões baseadas em SQLite, é possível oferecer uma arquitetura de sincronização simples e confiável, utilizável em todas as plataformas

A promessa e a realidade dos apps offline-first

  • Apps offline-first se apresentam como capazes de oferecer resposta imediata, privacidade garantida por padrão e uso sem espera de carregamento mesmo em redes instáveis
  • Na prática, porém, a maioria dos apps não implementa suporte offline adequadamente; a maior parte apenas salva mudanças temporariamente no dispositivo local e as envia depois quando a conexão volta
  • Esse tipo de implementação é pouco confiável e acaba levando a mensagens de aviso como "suas alterações podem não ter sido salvas"

A dificuldade fundamental da sincronização

  • Ao criar um app local-first, você inevitavelmente está construindo um sistema distribuído
  • Vários dispositivos podem alterar os dados de forma independente enquanto estão offline e, quando se reconectarem depois, precisam convergir exatamente para o mesmo estado
  • Para isso, existem dois grandes desafios
    • Incerteza na ordem dos eventos
    • Conflitos sobre os mesmos dados

1. Incerteza na ordem dos eventos

  • Eventos acontecem em momentos diferentes em vários dispositivos, e o estado pode mudar conforme a ordem aplicada
    • Exemplo: o dispositivo A define x=3, o dispositivo B define x=5 → após mudanças offline em cada um, a sincronização pode produzir resultados diferentes
  • Bancos de dados centralizados tradicionais resolvem isso com consistência forte, mas isso exige sincronização global e não se encaixa em sistemas local-first
  • No fim, é preciso determinar a ordem apropriada para cada evento mesmo em um ambiente dinâmico e distribuído; é necessário um modo de ordenar sem depender de um relógio central

Introdução dos Hybrid Logical Clocks(HLCs)

  • Hybrid Logical Clocks(HLCs) são um algoritmo simples e eficaz que permite chegar a um acordo prático sobre a ordem dos eventos entre dispositivos individuais
  • O HLC combina informação de tempo físico com um contador lógico
  • Por exemplo:
    • O dispositivo A registra um evento às 10:00:00.100, e o HLC fica em (10:00:00.100, 0)
    • O dispositivo B, ao receber a mensagem, eleva o HLC para (10:00:00.100, 1), mesmo que seu relógio esteja atrasado
    • Com isso, é possível determinar corretamente a ordem dos eventos independentemente da diferença entre os relógios físicos dos dois dispositivos

2. O problema dos conflitos

  • Aplicar a ordem correta não é suficiente; quando dispositivos diferentes modificam os mesmos dados de forma independente, conflitos inevitavelmente surgem
  • A maioria dos sistemas exige que o desenvolvedor escreva manualmente o código de resolução de conflitos, o que traz risco de erros e custo de manutenção

Uso de CRDTs

  • A melhor abordagem é aplicar Conflict-Free Replicated Data Types(CRDTs)
  • CRDTs garantem que independentemente da ordem de sincronização, ou mesmo com aplicações duplicadas, o estado final em cada dispositivo sempre será igual
  • A estratégia de CRDT mais simples é Last-Write-Wins(LWW)
    • Cada atualização recebe um timestamp
    • Na sincronização, o valor com o timestamp mais recente é escolhido

As vantagens do SQLite

  • Para construir um app local-first, é essencial ter um banco de dados local leve e confiável, e o SQLite é a escolha ideal
  • Ao implementar sincronização com extensões baseadas em SQLite, há os seguintes benefícios
    • Aplicar mensagens é simples: consultar o valor atual → sobrescrever se o novo timestamp for mais recente → caso contrário, ignorar
    • Essa abordagem garante convergência de estado em todos os dispositivos, independentemente da ordem da sincronização

O significado dessa arquitetura

  • Essa estrutura viabiliza uma sincronização simples e confiável
    • Confiabilidade sem perda de dados, mesmo após semanas offline
    • Característica determinística de sempre convergir para o estado final
    • Solução apenas com uma extensão leve de SQLite, sem dependências pesadas
    • Suporte a todas as principais plataformas, como iOS, Android, macOS, Windows, Linux e WASM

Recomendações para desenvolvedores

  • É preciso evitar abordagens que apenas "simulam" suporte offline com uma fila simples de requisições
  • É necessário adotar o conceito de eventual consistency e usar tecnologias comprovadas de sistemas distribuídos como HLC e CRDT
  • Em vez de frameworks grandes e complexos, é preferível buscar uma estrutura pequena e sem dependências
  • Como resultado, o app pode aproveitar vantagens como execução imediata, uso offline e privacidade garantida por padrão

Referência ao open source SQLite-Sync

  • Se houver interesse em um engine offline-first multiplataforma pronto para uso em produção, é possível consultar a extensão open source SQLite-Sync

1 comentários

 
GN⁺ 2025-09-23
Opiniões no Hacker News
  • Falam de CRDTs (Conflict-Free Replicated Data Types) como se fossem a solução, mas na prática é muito difícil criar um modelo de CRDT que corresponda às expectativas intuitivas dos usuários e a uma lógica de negócios consistente, e transformar o modelo de dados em um monte de mensagens para depois reconstruir continuamente o estado real é uma dor de cabeça enorme
    • Existe uma iniciativa chamada BRAID como novo padrão da web. Ela busca ser um padrão de sincronização de estado na web, aplicando tecnologias de Operational Transformation (OT) e CRDT ao HTTP para criar uma web sincronizada essencialmente mais amigável para humanos e máquinas. O Braid melhora o desempenho de rede e oferece suporte nativo a P2P, edição colaborativa e desenvolvimento de webapps local-first. Links relacionados: reunião do BRAID, discussão no HN sobre Braid, discussão sobre API RESTful, texto explicando Braid HTTP
    • Falar de CRDT acaba parecendo uma solução universal, mas na prática merge automático não é algo simples. Tecnicamente, até um algoritmo de "último autor vence" pode ser considerado um CRDT, mas em merges complexos de texto é um problema quase impossível respeitar ao mesmo tempo a intenção e as expectativas do usuário. Em algumas situações, tentar fazer merge com CRDT pode até ser a abordagem errada. Por exemplo, ao reservar uma sala de reunião, se duas pessoas reservarem a mesma sala ao mesmo tempo, em vez de o algoritmo decidir, o certo é que os próprios usuários percebam e resolvam o conflito
    • Concordo que é uma área difícil de encarar para quem não gosta de risco. Também existe uma alternativa “sem CRDT” para quem não quer se aventurar; veja aqui
    • Nossa equipe, ao criar apps local-first, usa um método de simplesmente ignorar conflitos. A última alteração vence. A maioria dos conflitos é trivial (ou pode ser resolvida facilmente com algo como um log de auditoria), ou então não dá para resolver automaticamente de qualquer forma. Por exemplo, em um rastreador de tarefas com suporte offline, se duas pessoas começarem a mesma tarefa ao mesmo tempo, isso precisa ser tratado como processo de negócio
  • Antigamente, quase todo software era local-first, e isso era o normal. Mas hoje o mundo funciona inteiramente em torno de controle e otimização de lucro, e o resultado é uma estrutura em que as pessoas acabam sendo mais prejudicadas com mais frequência. Mesmo quando há insatisfação, quase não existem substitutos
    • Na época em que fazíamos produtos on-premise e self-hosted, a maior reclamação dos clientes era a falta de uma opção em nuvem. A maioria das empresas não quer hospedar por conta própria e prefere pagar uma mensalidade para deixar isso com terceiros. Acho que o HN subestima muito o tamanho real da demanda por serviços em nuvem
    • A ideia de que “se as pessoas querem serviços que as prejudiquem menos, então deve dar para ganhar dinheiro com isso” não faz muito sentido economicamente. O problema é que as pessoas na prática toleram certo nível de prejuízo. Talvez isso mudasse com mais educação ou maior percepção de risco, mas acho que esse é um desafio extremamente difícil de resolver
    • Uma alternativa possível é FOSS (software livre e de código aberto)
  • Gostaria que os apps não dependessem exclusivamente de estar online para todo conteúdo. O GPS da Tesla, por exemplo, não faz cache nem dos tiles já baixados, então, se você fica offline, o mapa simplesmente não mostra nada. Apps como Peacock e Kanopy também não deixam no dispositivo nem a lista de mídia nem os próprios objetos renderizados. O dispositivo já tem 95% do conteúdo, e eu queria que isso fosse aproveitado de forma mais ativa. Basta marcar a UI como dirty e esperar o sucesso do salvamento assíncrono. Sem exigir uma grande mudança de design para apps offline, só com hábitos melhores já daria para resolver facilmente a maior parte desses problemas
    • Muito disso se resolve usando Cache-Control corretamente nas respostas da API e respeitando isso na camada de rede. Assim, mesmo se a validade do cache mudar no servidor, isso pode ser aplicado imediatamente sem atualizar o app
    • O Google Maps permite baixar mapas offline manualmente escolhendo uma área, e também dá para manter várias regiões em cache ao mesmo tempo. Já usei isso muito bem em visitas a parques nacionais
    • Quanto à ideia de que “não é preciso mudar o design do app”, acho que as empresas na verdade querem coletar mais dados. Por exemplo, a Apple também ofereceu mapas offline, mas faz os dados expirarem de propósito para prender o usuário ao seu ecossistema. Suspeito que os tiles de mapa da Tesla (ou do Google) também tenham uma intenção oculta
  • Muitas vezes, ao focar em temas “politicamente quentes” como local-first ou descentralização dos apps, acaba-se perdendo o valor principal que as pessoas realmente querem
    • Ao migrar para o Immich, achei que estaria abrindo mão de algo por ser self-hosted, mas me surpreendi com o fato de ele ser muito melhor que Apple ou Google. É um produto raro, quase um unicórnio
  • Acho que a falta de popularidade dos apps local-first é, no fim, um problema econômico. Modelos SaaS ou sustentados por publicidade estão muito consolidados, enquanto apps local-first são bem menos lucrativos. Quem prefere esse modelo valoriza características como soberania dos dados, criptografia ponta a ponta e uso offline, que entram em conflito com os modelos tradicionais de monetização. No fim, sobra depender da paixão da comunidade open source
    • Hoje em dia, parece que só existem as opções “pagar com dinheiro + dados” ou “assistir a anúncios”, enquanto um modelo de pagar só com dinheiro e ainda ter os dados protegidos foi praticamente excluído
    • Eu também estou criando um app local-first chamado Relay, que adiciona colaboração estilo Google Docs ao Obsidian. Acho o modelo de negócios bem diferente. O serviço é dividido em uma “camada global de identidade” e o “Relay Server” (open source/self-hosted), de modo que o usuário mantém controle total sobre o conteúdo dos documentos. Ele oferece SSO simples e gerenciamento de permissões, e tem chamado atenção especialmente de empresas de AI e AI Safety, além de companhias em que compliance é importante. Link: Relay.md
    • O que vejo muito ao meu redor são consumidores que deixam de comprar porque só existe opção de assinatura. A pessoa quer comprar agora para usar depois, mas as restrições (período promocional, aumento de preço ao voltar depois etc.) acabam destruindo totalmente a vontade de compra. Não acho que esse seja o melhor modelo de negócios
    • Não acho que o problema seja a estrutura de dados replicada. Até jogos single-player, que são totalmente local-first, muitas vezes exigem conexão com a internet por causa do launcher
    • Apps local-first também sofrem bastante com a complexidade. Eles precisam funcionar em todos os tipos de dispositivos e ambientes, enquanto apps cloud-first podem rodar apenas em um único ambiente controlado no servidor, o que é relativamente mais fácil e mais barato de manter
  • Embora software para desktop e mobile às vezes seja tratado como uma exceção estranha do passado, ele continua sendo uma forma muito comum de distribuição de software. Já ao tentar implementar recursos local-first no navegador, você acaba herdando principalmente as desvantagens do browser, como os problemas de integração com o sistema hospedeiro
  • Talvez eu esteja deixando passar alguma coisa, mas em geral me parece que apps “local-first” são o padrão normal. A maioria dos usuários também usa muitos apps baseados em funcionamento offline. Se a ideia for “web apps local-first”, aí a expressão faz mais sentido. Na verdade, “web app local-first” em si é um conceito meio contraditório
    • Eu gostaria de questionar se a maioria dos apps realmente ainda é local-first no sentido de você pagar diretamente por eles. Tirando jogos, parece que quase não existem mais empresas assim, e até jogos single-player hoje exigem internet com desculpas como DRM, anti-cheat e atualizações
    • Aqui, “local-first” significa apps que têm os dados locais como base desde o início, em vez de armazenamento em nuvem, mas com suporte a sincronização com a nuvem
  • Mesmo apps offline-first não são tão diferentes quando há uma conexão instável e o spinner de carregamento fica rodando. Por exemplo, o Google Docs trava tentando verificar se o documento está atualizado, e só abre imediatamente quando você força o corte com o modo avião. O Spotify também para tentando buscar informações extras online até para playlists salvas. No fim, conexões instáveis são a maior dor no desenvolvimento de apps offline, porque os apps sempre tentam acessar os dados da nuvem só mais uma vez
  • A solução do artigo também está presa a uma oferta de nuvem fechada. É parecido com o Firebase, que em si não é ruim, mas é frustrante que isso não esteja explicitamente marcado e que, por trás da expressão “apenas uma extensão do sqlite”, exista suporte só a nuvem comercial. Vendors como Powersync e ElectricSQL pelo menos deixam isso claro, e o Powersync inclusive permite self-hosting
    • Fico em dúvida se o conceito de local-first pode ser aplicado a ferramentas de desenvolvedor. Parece que vale investigar se dá para criar software baseado em modelo de armazenamento local com ferramentas do tipo SQLite-sync. O ElectricSQL permite self-hosting, e acho que também preciso continuar atualizando minha lista de ferramentas de “sqlite sync”. Links relacionados: artigo original sobre local-first, SQLSync, SQLiteSync, SQLite-Sync
  • Acho que precisamos de mais apps apenas locais e self-hosted. Ou então uma estrutura federada também seria boa. Sinto que a infraestrutura de rede vinha sendo um obstáculo, mas com soluções como o Tailscale esse tipo de app vai ficar muito mais fácil
    • Estou criando um software de apresentações, e ele precisa funcionar muito bem localmente, mas ao mesmo tempo também precisa ser acessível de qualquer lugar. Satisfazer essas duas coisas ao mesmo tempo é mais difícil do que parece. Mas, com o avanço da tecnologia, está ficando mais fácil implementar P2P com direct connection ou WebRTC. Ainda é um desafio incorporar isso ao produto real e testar, mas acho que no futuro veremos cada vez mais softwares local-first com networking excelente. É open source. Mais detalhes no perfil
    • Também tenho explorado bastante esse tema ultimamente e achado divertido. Mais detalhes aqui. É bem divertido construir apps de um jeito novo