返回博客

Git 用于现场数据

几十年前,软件开发领域就已经解决了并发编辑的问题——包括暂存、提交、冲突检测和代码审查。现场数据也面临同样的问题。我们采用了相同的解决方案。

version-controlofflineconflict-detectionfield-operations

并发问题

自 1970 年代以来,软件开发人员就一直在同时编辑相同的文件。当两个人修改同一个函数时,先提交的一方会成功,而另一方则会遇到合并冲突。这个问题已被彻底解决,以至于如今在世的每一位开发人员都在不经意间使用着这一解决方案:版本控制。将修改暂存,准备就绪后再提交。如果其他人修改了相同的内容,系统会发出提示,你可以在代码发布前解决冲突。

现场数据也存在同样的问题。 两支工作组在同一区域编辑地理要素。一支在地下作业,无法联网;另一支则在城另一端,手机信号时断时续。当两支队伍重新连上网络并提交更改时,如果系统未能检测到数据重叠,其中一支队伍的工作将悄无声息地覆盖另一支的工作。如果系统锁定记录以防止冲突,那么任何人都无法进行离线作业。这些正是软件开发团队在采用版本控制之前所面临的权衡——而大多数现场作业软件至今仍陷于此境。

大多数现场软件是如何处理这一问题的

有三种常见的方法,每种方法都有其代价。

最后写入者胜出。 这是最简单却也最危险的方式。两名用户都在编辑,都提交了数据。第二次提交会无预警地覆盖第一次提交的内容。第一位用户的修改就此消失。这种做法在那些原本设计为单用户操作、后来才勉强添加多用户支持功能的现场软件中,竟出人意料地普遍。它看似正常运行,直到某天突然失效,而一旦出错,往往毫无征兆。

**记录锁定。**当有人打开某个要素进行编辑时,系统会锁定该要素。在锁定解除之前,其他人无法进行编辑。这种机制通过阻止并发操作来防止冲突——但也完全阻止了离线工作。如果一名现场工作人员锁定了一个要素,随后进入地铁隧道并停留四小时,那么该要素对整个团队而言将处于冻结状态。记录锁定是以数据完整性为代价换取操作瘫痪。

通过划分区域来避免冲突。 为每个团队分配一个地理区域,并相信他们会遵守该区域。如果各区域互不重叠、边界始终得到尊重,且没有任何要素跨越边界,这种方法是可行的。但在实际操作中,各区域在每个交叉点、边界以及共享的基础设施走廊处都会发生重叠。这种方法在理论上可行,但在边界处却行不通——而恰恰是这些边界处,往往发生着最有趣的工作。

版本控制模型

我们的方法直接借鉴了软件开发团队的工作方式。这些概念与之完全对应。

**编辑操作是本地化的。**当现场工作人员编辑要素(移动点、调整线段形状、更新属性)时,更改会存储在其浏览器中。其他人无法看到这些更改。这相当于在本地分支上编辑文件。工作人员可以撤销、重做并继续编辑,而不会影响共享数据集。 “未提交更改”标记会记录待处理的编辑数量,这与开发人员跟踪未暂存更改的方式相同。

提交即为提交。 当开发人员准备就绪时,点击“提交”。所有待处理的更改将作为单一版本推送到服务器——这是一个带有时间戳和提交者身份的一致更改集合。这就是提交。它具有原子性:要么所有更改都通过,要么一个都不通过。

**管理员审核即代码审查。**对于非管理员的一线工作人员而言,点击“提交”不会直接发布内容。系统会生成一个标记为待审核的版本。管理员打开审核队列,查看差异——即哪些内容发生了变化、具体位置以及与当前状态的对比情况——然后予以批准或拒绝。这就是拉取请求。在获得授权的人员批准之前,共享数据集不会发生任何变化。

**冲突检测即合并检查。**当某个版本被提交时,服务器会检查自提交者上次同步以来,是否有人编辑了相同的要素或相同的地理区域。如果存在重叠,系统会标记冲突。两个版本都会显示出来——提交者的修改显示为蓝色,其他用户的修改显示为橙色——团队需要明确地解决冲突。不会发生无提示的覆盖,也不会丢失数据。

**版本历史即提交日志。**每个已提交的版本都会被完整保留——包括提交者、提交时间、修改内容以及审批人。版本会随着时间推移被压缩,但绝不会被删除。您可以随时还原任何功能在历史上的任意状态。版本日志集审计轨迹、撤销机制和机构记忆于一体。

实际应用中的表现

有两支施工队正在同一光纤网络上作业。A组正在现场编辑北部区域的电缆路线。B组正在地下编辑中部区域的熔接点。两组均处于离线状态。

A组完成工作并重新上线。他们提交了自己的版本。服务器接受了该版本——没有冲突,因为自A组上次同步以来,没有人修改过这些功能。管理员审查了差异报告,确认电缆路线的更改合理,并予以批准。更改随即生效。

一小时后,B组浮出水面并提交了修改。服务器检测到他们有两个接点编辑与A组已修改的特征重叠。系统弹出了冲突警告。B组打开冲突视图,看到了两个版本——他们的编辑显示为蓝色,A组已提交的状态显示为橙色。他们调整了接点位置以适应A组对电缆路线的更改,重新提交后,管理员批准了已解决的版本。

丢失的数据总量:零。手动核对所耗时间:几分钟。被静默覆盖的功能数量:零。

试着对比一下其他方案。如果采用“最后写入者胜出”机制,B组提交的方案就会悄无声息地覆盖掉A组对电缆路线所做的修改。如果采用记录锁定机制,当一方在地下作业时,另一方将无法进行编辑。如果采用基于区域的避让机制,重叠路段的协调工作将变得极其棘手,只能依靠电话沟通和电子表格来处理。

优先离线,而非勉强支持离线

一种常见的误解是,认为离线支持意味着在网络中断时能实现平滑降级。这种观点默认认为在线状态是常态,而离线状态则是需要处理的例外情况。但在实际操作中,情况恰恰相反。网络连接本就是间歇性的——地下室、隧道、农村地区以及施工现场往往没有信号。如果一个系统将离线状态视为例外情况,那么它将大部分时间都处于例外处理模式中。

版本控制则完全相反。离线是默认的工作状态。在您决定提交之前,所有编辑操作都仅在本地进行。网络仅用于两件事:将您的更改推送到服务器,以及从他人那里拉取最新状态。在这两者之间,您可以独立工作,并拥有完整的编辑权限。当网络连接恢复时,您进行同步——剩下的工作由系统自动处理。

这就是该模型之所以有效的原因。它并非为了将离线状态作为特例而设计,而是基于这样一个假设:用户通常处于离线状态,偶尔才会连接网络——这恰恰符合实地工作的运作方式。

摘要

  • 现场数据管理面临着与软件开发数十年前已解决的相同并发问题:多人同时编辑同一内容,且通常处于离线状态,存在无声覆盖的风险。
  • “最后写入者获胜”原则会导致无声数据丢失。记录锁定机制阻碍了离线工作。基于区域的冲突避免机制在每个边界和重叠区域都会失效。
  • 版本控制模型——本地草稿、原子提交、管理员审核、冲突检测、永久历史记录——直接从软件开发领域映射到了现场操作中。
  • 现场编辑内容会本地存储,直到工作人员提交。非管理员的提交需经过审核队列。冲突在服务器端被检测到并提示进行明确解决——没有无声覆盖,没有数据丢失。
  • 每个已提交的版本都会保留提交者、时间戳和审批者信息。版本历史记录经过压缩但永不删除。任何功能的状态都可在任意时间点被还原。
  • 离线是默认的工作状态,而非需要处理的例外情况。系统默认用户通常处于断开连接状态,仅偶尔进行同步——这与实地工作的实际运作方式相吻合。