← 全部概念地圖
標準

概念地圖・操作轉換

分類:系統

這一頁不只是把一個概念解釋一遍——一張自己畫的結構圖,加上拿台灣情境從頭走一次的實例演練、這個框架什麼時候會騙你,以及它接回 P.A.I.N. 之後長什麼樣。一頁必須交付的三層 →

操作轉換:兩個人同時動一份清單,最後收斂成同一份

同一份清單,兩個人在同一分鐘各動了一次手。一個在中間插進一項新品,一個把上面某一項刪掉。等兩台手機把訊息換過來,麻煩才開始——每一個動作講的位置,都是照它自己那台當下的清單數出來的,而那份清單已經被對方改過了。操作轉換(Operational Transformation)處理的正是這一秒:兩端各自先跑完自己的動作,再把對方那個動作重新量一次位置才補上。Google Docs 那種你打字我也打字、畫面卻始終一致的體驗,底下就是這套機制在替後到的那一邊換算座標。

操作轉換的並發編輯菱形:兩條路徑收在同一份清單 一個菱形。上頂點是五項的原始清單。左邊那條邊是 A 在位置 3 插入香氛蠟燭,走到左頂點的六項;右邊那條邊是 B 刪除位置 2,走到右頂點的四項。左頂點往下補上位置不變的 B,右頂點往下補上轉換後的 A′,它的插入點由 3 改成 2。兩條邊交會在下方的金色方框,各自得到同一份五項清單:手工皂、香氛蠟燭、木湯匙、布包、陶杯。 原始清單(五項) 1 手工皂 2 明信片 3 木湯匙 4 布包 5 陶杯 A:在位置 3 插入香氛蠟燭 B:刪除位置 2 補上 B(位置不變) 補上轉換後的 A′ 插入點 3 → 2 A 端:六項 已插入香氛蠟燭 B 端:四項 已刪掉明信片 被重新量過的是位置索引 兩端相同 手工皂・香氛蠟燭・木湯匙・布包・陶杯
同一秒的兩個動作,先後順序不同也走到同一份清單——差別只在後到的那一個被重新量過位置。

菱形的四個角,分別是哪一份清單

菱形的四個角,其實是四張時間點各不相同的快照。攤成一張表,比盯著箭頭來回看快得多。

菱形的角那一刻的清單長什麼樣這一步在做什麼
上頂點手工皂、明信片、木湯匙、布包、陶杯(五項)兩端此刻完全一致,所有位置編號都從這一份數起
左頂點(A 端)手工皂、明信片、香氛蠟燭、木湯匙、布包、陶杯(六項)A 的動作先落地,明信片還在位置 2,後面每一項往後退一格
右頂點(B 端)手工皂、木湯匙、布包、陶杯(四項)B 的動作先落地,明信片走了,後面每一項往前補一格
左邊往下那條補上 B,指令一個字都不用改A 端的明信片還在位置 2,「刪位置 2」刪掉的正是它
右邊往下那條補上轉換後的 A′插入點由 3 改成 2 —— 少掉的那一項排在插入點前面
下頂點手工皂、香氛蠟燭、木湯匙、布包、陶杯(五項)兩條路徑逐項對得上,項數與順序都相同

表格裡真正被動到的只有一個東西:A 那個動作落腳的座標。動作本身一個字都沒改——還是「插入香氛蠟燭」——被換掉的只有它該落在第幾格。這也是這套機制最常被誤讀的地方:它管的是座標打架,內容那一層它一個字都沒碰。誰的字留下來、留下來的那個對不對,菱形沒有意見。

要不要上這一套,看你這邊有沒有這三件事

一、同時,還是輪流。市集攤位那份寄賣清單,如果是攤主晚上收攤才統一謄一次,那你要的是一份誰先誰後很清楚的紀錄,這整個菱形都用不上。真正需要它的長相是:三個顧攤的人在同一個下午都開著那份清單,客人問一句就當場改一筆。改的頻率愈密,兩隻手落在同一行的機率就愈高。自問:我們是同時改同一份檔,還是各改各的再合併?

二、撞在同一格時,現在誰活下來。先別談機制,先去看歷史。上一次兩個人同時把「陶杯」的售價改成不同數字,最後檔案裡留的是哪一個——是後存的那個蓋掉前一個,還是有人在群組裡吵完再手動改回來。很多攤位的答案其實是第三種:沒人發現,錯的那個價格就那樣賣了一整週。自問:同一個位置被兩個人動到時,現在是誰的版本留下來?

三、動作本身有沒有被留下來。菱形能運轉,靠的是「A 在位置 3 插入香氛蠟燭」這句話被完整記著,而不只是記著改完長什麼樣。攤位那份清單如果每次都是整份覆蓋上傳,後到的那一邊就沒有東西可以重新量——它拿到的只有結果,那句「插在位置 3」在路上就蒸發了。有動作紀錄的系統才有本錢做轉換;沒有的,就只能比時間戳然後認賠。自問:有沒有一個地方把每一次的動作本身記下來,供後到的那一邊重新換算位置?

一份文創市集的共用寄賣清單,兩邊各改一次

底下這個台灣中部的文創市集攤位,是為了把這個結構講清楚而編出來的示意情境,沒有指涉任何真實團隊。跟著逐項數一遍,兩條路徑會自己收在同一個地方。

實例演練
  • 週六早上十點,兩台手機一致:寄賣清單上五項——1 手工皂、2 明信片、3 木湯匙、4 布包、5 陶杯。阿凱在攤位顧場,小婕在家補貨。這一刻誰講位置幾,對方都聽得懂
  • 阿凱做了 A:在位置 3 插入「香氛蠟燭」:他那台變六項——1 手工皂、2 明信片、3 香氛蠟燭、4 木湯匙、5 布包、6 陶杯。明信片還坐在原本的位置 2,蠟燭之後的每一項都往後退了一格。他要的是週末主打擺前面
  • 同一分鐘,小婕做了 B:刪除位置 2:明信片缺貨,她把它拿掉。她那台變四項——手工皂、木湯匙、布包、陶杯。兩台各自都覺得自己是對的,畫面已經分岔
  • 阿凱這邊補上 B,位置不用改:他手上六項,明信片仍然坐在位置 2,「刪位置 2」刪掉的正好是它。剩下:手工皂、香氛蠟燭、木湯匙、布包、陶杯——五項。A 先做的那一邊,B 原封不動就對了
  • 小婕這邊照原話補 A,會插錯格:她手上只剩四項——1 手工皂、2 木湯匙、3 布包、4 陶杯。照著「在位置 3 插入香氛蠟燭」做下去,蠟燭會掉到木湯匙後面:手工皂、木湯匙、香氛蠟燭、布包、陶杯。項數一樣是五,順序對不上阿凱那台。同樣的一句話,在不同的清單上指向不同的格子
  • 轉換過的 A′:插入點由 3 改成 2:被刪掉的明信片原本排在插入點前面,所以插入點往前挪一格。小婕補上 A′ 之後:手工皂、香氛蠟燭、木湯匙、布包、陶杯——五項,逐項跟阿凱那台對得上。兩條路走完,落在同一份

整件事沒有任何一方被要求讓步。阿凱的插入照做了,小婕的刪除也照做了,兩個人的意圖都活著——被改掉的只有一個數字:那個「3」。這就是操作轉換的立場:它不裁決誰對,它替後到的那一個重新量一次尺。實務上要付的代價也在這裡:系統得記住「插入」與「刪除」各自的完整語意,還得知道刪除點落在插入點的前面還是後面,才算得出要不要挪那一格。攤位上人不多的時候,這套機制像沒有存在感;等到三個人同時在改、還有一個人在鄉下訊號斷斷續續,它就是那個讓大家收攤時不必重對一次清單的東西。以上為說明結構用的示意情境,僅供理解框架之用。

這個菱形什麼時候會騙你

  1. 它保證兩端相同,管不到那份清單好不好。操作轉換的數學目標只有一個:不管訊息以什麼順序抵達,最後兩端要一樣。至於那個「一樣」有沒有保住兩個人原本想做的事,它沒有承諾過。上面那個場景裡兩個意圖剛好互不打架,算是運氣好。換成兩個人同時把陶杯的售價改成不同數字,菱形照樣會收,收出來的價格卻只可能是其中一個人的——另一個人的判斷連個痕跡都不會留下。收斂是技術指標,正確是生意指標。
  2. 人一多、動作型別一多,要寫的轉換規則會平方地長。只有插入和刪除時,你要定義四組轉換;再加一個「移動」就變九組,再加上粗體、標價這類格式標記,數量還會往上翻。更難的在三個人以上同時動手:兩兩之間都轉換正確,整體仍然可能收不到同一份,這件事在學界吵了很多年。你看到的 demo 通常只有兩隻游標,那支 demo 跑得漂亮,說明不了五個人同時開會改同一頁會怎樣。
  3. 「位置索引」這個前提,只在一條線上成立。菱形算得動,是因為清單是一排可以編號的格子——第 3 格往前挪一格就是第 2 格。一旦你的東西是表格、是樹狀目錄、是畫布上的自由座標,「位置」就不再是一個數字,要換算的維度也跟著長出來。很多團隊把文件協作的順手感直接搬去做設計稿或看板,會在這裡撞牆:兩個人同時把同一張卡片拖到不同的欄位,沒有一個「往前挪一格」的算法救得了它。

這一秒的落差,值錢在哪裡

痛點視角

兩隻手同時落在同一行字上,系統會替後到的那一隻重新量一次位置。

這件事漂亮的地方在於,它把「誰先誰後」這個原本要吵架的問題,變成一道可以算的題目——算完誰也不用讓。可是它算的只有座標。價值那一欄,它連格子都沒有。這張圖畫得出兩份清單怎麼被拉回同一份,畫不出香氛蠟燭到底該不該躺在那份寄賣清單上。攤位上真正會流血的地方在別處:那一項擺出去了,有沒有客人走回來找它。系統把衝突收乾淨之後,會留下一種很安靜的錯覺——大家都同意了。真正發生的只有一件事:大家的畫面一致了。同意這兩個字,沒有任何演算法產得出來。所以今晚挑一項這週被兩個人各動過一次的商品,去問一次上一個把它帶走的客人:你當時為什麼選它。那個答案,菱形收不回來。

關於同時編輯,常被問到的幾件事

操作轉換和 CRDT 差在哪裡?

兩者的終點一樣:不管訊息以什麼順序抵達,最後大家看到同一份。走法不同。操作轉換保留「位置索引」這個直覺,靠一支轉換函數替後到的動作換算座標,實務上通常需要一台伺服器把順序排定。CRDT 走另一條路——它替每一個字元或每一項配一個永久不變的識別碼,動作之間天生就能任意交換順序,代價是資料結構會變胖,刪掉的東西還得留下墓碑。自己從零實作時,CRDT 比較不容易寫錯;要接既有的文件協作生態、又在意傳輸量,操作轉換仍然很常見。

Google Docs 用的就是這一套嗎?

是。Google Docs 公開說明過它的即時協作建立在操作轉換上,Etherpad、ShareDB 這些老牌開源專案走的也是同一條路。近幾年新做的協作工具比較多採用 CRDT,像 Yjs、Automerge 這類函式庫。你在畫面上感受不到差別——兩種都會讓你打字的當下看到別人的游標在動。差別藏在後端:離線兩小時再回來、或是要做點對點同步時,CRDT 比較好過。

一定要有中央伺服器嗎?

理論上不必,實務上幾乎都有。純點對點的操作轉換要處理的組合太多——三個人以上同時動手時,要證明任兩條路徑最後都收在同一份,條件會變得非常難滿足。所以主流做法是讓伺服器當排隊員:所有動作先送到它那裡定出一個順序,再廣播出去讓每一端各自轉換。這也是為什麼多數協作工具斷線太久會請你重新載入——它得先把你離線期間累積的那一疊動作,一條一條放進那個順序裡。

我們只是共用一份試算表,需要懂這個嗎?

你不必實作它,但值得知道它管到哪一格為止。共用試算表底下也有一套收斂機制,它保證的是「你們兩台看到的內容一樣」。它管不到的是:同一格的數字被兩個人各填一次時,留下來的那個是誰填的、根據是什麼。知道這條界線之後,力氣會花在對的地方——替真正會撞的那幾格,事先講好一句誰說了算。工具負責讓畫面一致,那句話負責讓決定有主人。

打開你們共用的那份檔,看它上一次衝突是怎麼收掉的——是有人默默貼回去,還是系統自己接上了。想再往下看「網路一斷、兩邊都收不到對方」的時候要放棄什麼,可以接著看CAP 定理的三角;想先確認自己這條協作到底落在哪一格,時間空間協作矩陣把同時或不同時、同地或不同地攤成四格,同時改同一份檔只是其中一格。

發現引用或事實有誤?請寫信回報,我會依更正政策修正。