Arquitetura real · Sênior
Figma: como funciona o multiplayer
Arquitetura real em produção. Pontos centrais: edição colaborativa.
Resposta curta
Arquitetura real em produção. Pontos centrais: edição colaborativa. O primeiro modelo de salvamento do Figma baixava o documento, editava localmente no navegador e enviava o documento inteiro de volta de tempos em tempos. Era uma abordagem prática, fácil de construir e de entender.
01 · CONTEXTO
Antes do multiplayer: salvar o documento inteiro
O primeiro modelo de salvamento do Figma baixava o documento, editava localmente no navegador e enviava o documento inteiro de volta de tempos em tempos. Era uma abordagem prática, fácil de construir e de entender. Mas, com o tempo e mais recursos de equipe, ficou claro que havia um problema: as pessoas às vezes salvavam por cima do trabalho umas das outras sem perceber, e quem recebia um link às vezes via a versão antiga porque o salvamento ainda não tinha terminado.
O time chegou a explorar alternativas mais baratas, como um modo de bastão em que só há um editor ativo por vez, mas sabia que a solução ótima era a edição simultânea. A ideia do motor é simples na teoria: as mudanças de cada pessoa sobem ao servidor e são distribuídas às demais em tempo real; duas mudanças simultâneas são independentes, a menos que atinjam a mesma propriedade do mesmo objeto, e nesse caso vale a mais recente.
02 · ARQUITETURA
Clientes, WebSockets e um processo por documento
Os clientes do Figma são páginas web que falam com um cluster de servidores por WebSockets. Na época do artigo, os servidores abriam um processo separado para cada documento multiplayer, e todas as pessoas que editam aquele documento se conectam a esse processo.
Ao abrir o documento, o cliente começa baixando uma cópia do arquivo.
Dali em diante, as atualizações nos dois sentidos são sincronizadas pela conexão WebSocket com o processo do documento.
Todas as pessoas que editam o mesmo documento se conectam ao mesmo processo.
Se a pessoa ficou offline, ao voltar o cliente baixa uma cópia nova, reaplica as edições feitas offline por cima do estado mais recente e retoma a sincronização por uma nova conexão.
Comentários, usuários, times e projetos ficam no Postgres e chegam aos clientes por um sistema totalmente separado, fora do multiplayer.
O multiplayer só sincroniza mudanças nos documentos. Segundo a fonte, os dois sistemas têm implementações separadas por compromissos diferentes de desempenho, disponibilidade offline e segurança. Conectar e reconectar são simples; toda a complexidade do multiplayer está em lidar com atualizações de documentos já conectados.
03 · OT E CRDT
Por que não OT, e por que só “inspirado em” CRDT
O Figma não quis usar transformação operacional (OT), o algoritmo padrão de multiplayer popularizado por apps como o Google Docs. Como startup, valorizava entregar funcionalidades rápido, e as OTs eram complexas demais para o problema; por isso construiu um sistema próprio, mais simples e fácil de implementar.
As OTs são ótimas para editar textos longos com pouca sobrecarga de memória e desempenho, mas são muito complicadas e difíceis de implementar corretamente. Como o Figma não é um editor de texto, não precisava desse poder.
A inspiração veio dos CRDTs, que satisfazem propriedades matemáticas que garantem consistência eventual: se não houver mais atualizações, todo mundo que acessa a estrutura passa a ver a mesma coisa. Essa restrição é de correção, porque dois clientes editando o mesmo documento não podem divergir para sempre.
O Figma, porém, não usa CRDTs verdadeiros. Eles foram pensados para sistemas descentralizados, sem autoridade central, e isso traz sobrecarga inevitável de desempenho e memória. Como o servidor do Figma é a autoridade central, dá para remover essa sobrecarga e ter uma implementação mais rápida e enxuta. A estrutura final também não é um único CRDT: combina vários.
| Abordagem | O que é | Custo ou ganho para o Figma |
|---|---|---|
| OT | Algoritmo padrão de multiplayer, popularizado por apps como o Google Docs | Ótima para textos longos com pouca sobrecarga, mas complicada e difícil de implementar corretamente |
| CRDT | Estruturas de dados com propriedades matemáticas que garantem consistência eventual | Pensadas para sistemas descentralizados, com sobrecarga inevitável de desempenho e memória |
| Figma | Sistema próprio, inspirado em vários CRDTs separados usados em combinação | Servidor como autoridade central remove a sobrecarga: implementação mais rápida e enxuta |
04 · CONFLITOS
O documento como mapa de propriedades
Todo documento do Figma é uma árvore de objetos, parecida com o DOM do HTML: uma raiz, páginas abaixo dela e uma hierarquia de objetos em cada página. Cada objeto tem um ID e uma coleção de propriedades com valores, o que dá para ver como um mapa de dois níveis. Por isso adicionar recursos ao Figma costuma significar só adicionar propriedades aos objetos.
O servidor guarda o último valor que qualquer cliente enviou para cada propriedade de cada objeto. Mudar propriedades não relacionadas do mesmo objeto, ou a mesma propriedade em objetos não relacionados, não gera conflito. O conflito ocorre quando dois clientes mudam a mesma propriedade do mesmo objeto, e o documento fica com o último valor enviado ao servidor. É parecido com o registrador last-writer-wins da literatura de CRDT, sem timestamp, porque o servidor define a ordem dos eventos.
Dois clientes mudam propriedades não relacionadas do mesmo objeto: não há conflito.
Se os dois mudam a mesma propriedade do mesmo objeto, o documento fica com o último valor enviado ao servidor, que define a ordem dos eventos.
No cliente, a mudança é aplicada imediatamente, sem esperar a confirmação do servidor, para o Figma parecer o mais responsivo possível.
Para evitar o flicker de valores antigos confirmados sobrescrevendo os novos ainda não confirmados, o cliente descarta mudanças do servidor que conflitam com as suas não confirmadas.
As mudanças de cada pessoa sobem ao servidor e são distribuídas às demais.
Uma consequência é que as mudanças são atômicas na fronteira do valor da propriedade: o valor final é sempre um valor enviado por algum cliente. Por isso a edição simultânea do mesmo texto não funciona no Figma: se o texto é B e alguém muda para AB enquanto outra pessoa muda para BC, o resultado será AB ou BC, nunca ABC. O Figma aceita isso porque é uma ferramenta de design, não um editor de texto.
05 · OBJETOS E ÁRVORE
Criar, remover e reparentar sem perder identidade
Criar e remover objetos são ações explícitas do protocolo: escrever uma propriedade num ID inexistente não cria o objeto. Remover apaga do servidor todos os dados do objeto, inclusive as propriedades. Esses dados ficam no buffer de desfazer do cliente que apagou, que é responsável por restaurá-los se a pessoa desfizer; isso evita que documentos longevos cresçam sem parar.
O sistema depende de os clientes gerarem IDs únicos: cada cliente recebe um ID próprio, incluído nos IDs dos objetos que cria, e assim dois clientes nunca geram o mesmo ID. O servidor não pode atribuir esses IDs porque a criação de objetos precisa funcionar offline.
A parte mais complicada é a árvore, por causa do reparentamento, que é mover um objeto de um pai para outro. Havia dois objetivos: mudar o pai não deve conflitar com mudanças em propriedades não relacionadas do mesmo objeto, e dois reparentamentos concorrentes do mesmo objeto nunca devem deixar duas cópias dele em lugares diferentes da árvore.
Apagar e recriar o objeto com outro ID não servia, porque as edições concorrentes seriam descartadas quando a identidade muda. A solução foi guardar o vínculo com o pai como uma propriedade do filho: a identidade é preservada, e o objeto não acaba com vários pais, o que poderia acontecer se cada pai guardasse links para os filhos.
O vínculo com o pai é uma propriedade do filho, então mover um objeto preserva a identidade dele.
Sem restrições, edições concorrentes podem formar um ciclo: um cliente faz A filho de B enquanto outro faz B filho de A.
O servidor rejeita atualizações de pai que causariam ciclo, então o ciclo não pode existir nele.
No cliente ainda pode ocorrer: ele enviou uma mudança não confirmada colocando A sob B e recebeu do servidor uma que coloca B sob A, e não pode rejeitar o que vem do servidor.
O cliente parenteia os objetos um ao outro e os tira da árvore até o servidor rejeitar a mudança dele e o objeto voltar ao lugar certo.
Para ordenar os filhos de um pai, o Figma usa indexação fracionária: a posição do objeto entre os filhos é uma fração entre zero e um (exclusivo), e a ordem sai de ordenar os filhos por essa posição. Inserir um objeto entre dois outros é dar a ele a média das posições dos vizinhos. O vínculo com o pai e a posição são guardados como uma única propriedade, para atualizarem atomicamente.
06 · UNDO E LIÇÕES
Desfazer, desempenho e o que o time aprendeu
O desfazer tem definição natural no modo de uma pessoa só, mas em multiplayer é confuso por natureza. O princípio que orientou o time: se a pessoa desfaz bastante, copia algo e refaz até o presente, o documento não deve mudar. Por isso, no Figma, desfazer modifica o histórico de refazer no momento do desfazer, e refazer modifica o histórico de desfazer no momento do refazer.
O post de lançamento relata outros desafios. Propriedades do mesmo objeto que precisavam mudar juntas exigiram um merge cuidadoso entre mudanças. Ações aparentemente simples em um objeto afetavam outros, gerando conflitos não intencionais entre quem editava objetos aparentemente não relacionados, o que levou a mudar parte do funcionamento do layout. E o desempenho exigiu medição e ajuste, incluindo reformular o formato de arquivo, que não era eficiente para mensagens pequenas.
Antes de mexer no código real, o time montou um protótipo: uma página que simulava três clientes ligados a um servidor e mostrava o estado inteiro do sistema, com cenários de clientes offline e conexões de banda limitada. Entre as lições do post está que dedicar tempo a pesquisar e prototipar no início compensou.
Perguntas frequentes
O que é Figma: como funciona o multiplayer?
Arquitetura real em produção. Pontos centrais: edição colaborativa.
O que o design de Figma: como funciona o multiplayer cobre?
Ele está organizado nestas seções: Antes do multiplayer: salvar o documento inteiro, Clientes, WebSockets e um processo por documento, Por que não OT, e por que só “inspirado em” CRDT, O documento como mapa de propriedades, Criar, remover e reparentar sem perder identidade e Desfazer, desempenho e o que o time aprendeu.
Quanto tempo leva Figma: como funciona o multiplayer e qual é o nível?
Leva cerca de 17 minutos para ler e tem nível Sênior.
Agora projete você mesmo
Rode este caso como uma entrevista na escola de System Design: você toma as decisões, o tutor as questiona e você vê a nota do seu desenho.