Local-first 不是口号,是数据模型的选择

· 工程

很多人把 local-first 理解成“数据存在本地”。这只是表象。真正的差别在于:本地是数据的唯一真相来源,还是服务器数据的一个缓存副本。

两种架构的实际差异

传统 Web 应用里,服务器是权威。你打开应用,它去问服务器要数据,拿到什么就显示什么。离线时应用基本瘫痪,因为它的状态全在远端。

Local-first 反过来:本地数据库是权威,服务器只是一个同步的中转站。断网时你可以继续读写,恢复连接后差异会被合并。这个转变听起来只是“加个离线缓存”,但一旦落到实处,整个数据模型都要重写。

冲突合并不是补丁,是设计前提

如果本地可以写,那么两个设备同时改同一条数据就是必然会发生的,而不是异常情况。这意味着你不能用“最后写入者覆盖”这种简单策略应付了事 —— 它会在用户真正需要保留内容的时候丢掉数据。

可行的做法是把数据建模为可合并的结构:CRDT、操作日志、或者至少是字段级的版本向量。这比设计一张普通的关系表要费力得多,但它是 local-first 的入场券。

如果你的数据模型不允许并发写入产生可解释的结果,那你做的就是“带离线缓存的 Web 应用”,不是 local-first。

我们也付了代价

Tabula 第一版用了一张普通的 SQLite 表,同步逻辑是“谁后到谁赢”。内测第一周就有用户反馈笔记内容莫名其妙回退。第二版把每条记录改成 append-only 的操作序列,合并逻辑放在客户端,问题才消失。

代价是数据库体积变大、需要定期压缩、以及一套不太好调试的合并代码。收益是用户再也不用担心网络。

← 返回首页