1 figma 的协同编辑
::: block-1
2022 年 9 月,
Adobe200 亿美元收购figma,体验过的同学会知道这一切都是值得的。——鲁迅 =。=
:::
多年以前,figma就决定必须支持多人协同,当时只是觉得作为一个浏览器设计工具,不做协同味道不对。最终这个决策赶上了SAAS和在线办公双风口,获得了巨大的收益。
让我们跟随 2019 年figma的旧文 How Figma’s multiplayer technology works,一起看看如何实现实用的协同架构。
2 设计思路
作者首先放弃了 OT 架构:
OT是为文本编辑设计的OT非常复杂,容易出错成本过高
figma更多的是受到CRDT理论的影响,结合本身中心化的产品设计,用中心化的服务器,实现了更适合设计稿协同场景的简化版CRDT架构。
figma服务器为每个文档都单独开启了一个线程,用于同步多人编辑行为。
更有趣的是,作者从一个3 客户端 1 服务端的原型入手,逐步验证了技术和体验的可行性,从而完成了整体设计。
:::: column ::: column-left 30%
服务器
::: ::: column-right 70%
客户端
::: ::::
3 有趣的设计
3.1 属性原子化和扁平的树结构
- 为了减少操作同步的冲突,数据结构的最小粒度是属性。
客户端总是第一时间应用所有本地更改,这样操作会非常流畅。- 更改总是期待
服务器的确认,其他更改被忽略(下图左侧,step 2),于是预测更精确闪屏更少(下图左侧,避免了红>绿>红)。 - 子元素会通过维护
parent字段来实现互相嵌套。降低了复杂度,还进一步减少了操作之间可能的冲突。
ps:树结构协同编辑,有一个新问题是容易形成环。
figma会在服务器检测,从而阻止环的形成。客户端则会临时保留环结构,等待服务器最终指令完成同步。
3.2 创建和删除
服务器不保留已删除数据客户端用额外字段实现假删除
3.3 顺序问题
同一个父节点下,如果有多个字元素,就会有多人协作的排序问题。这里用了经典的分数索引算法Realtime Editing of Ordered Sequences。
此算法的好处是:
- 容易理解和实施
- 仅依赖单个值,即:
position字段
此算法的坏处(附辩解)是:
- 值越来越长:协同设计场景下,此问题并不严重,且算法有压缩优化空间(改为字符串)。
- 最终结果顺序错位:再次体现协同设计文档和文本编辑的区别,错位并没有太大影响。
- 中间值冲突:再次体现中心化的场景,只需服务器做出选择即,可保证最终一致性。
至此,协同节点顺序问题,也获得了性能、实现成本和体验之间较好的平衡。
3.4 undo、redo
协作撤销和单机撤销有较大区别,还记得服务器不存储删除吗?小编认为figma中,服务器也不记录撤销历史。 原则上架构仅需要,准确无误的支持,用户先undo,再copy,再redo的经典操作路径即可。
客户端应用每个动作。客户端为每个动作生成undo,放进历史列表,step 1、3。客户端同步每个动作,step 2、4。- 此时,如果
客户端收到了新的冲突动作,则undo列表可能折旧,但我们无需处理step 4,直到: - 若用户
undo,step 5,此时先取出undo动作。 - 根据当前状态,看是否需要修复
undo记录,step 7。 - 应用
undo。 - 若此时
redo,则生成新的undo,类似step 6、8,重新放进历史列表。
最后数据结构大致理解为:
type Block = {
client: string;
id: string;
parent: string;
position: string;
prop: string;
value: string;
version: number;
status: "load" | "sync" | "set" | "ignore" | "confirmed";
};
这篇文章过于经典,很多地方都有翻译和解读,今天再读了一遍。
以上如有错误遗漏,还望指出,不胜感激。