有個小型購物清單應用程式,需要加入兩項功能:篩選項目,以及將清單匯出成 CSV。這兩件事幾乎互不相關,於是很自然會想到:分給兩個人做,半小時就能拿到兩部分,不必等一小時。一位執行者負責篩選,另一位負責匯出,兩人各自在自己的工作目錄操作,避免修改混在一起。至於兩部分如何理解清單資料,事前並沒有討論。當時看起來理所當然。

半小時後,兩部分都完成了。各自的檢查都通過,整合時也沒有任何衝突。但整體流程卻跑不起來:畫面上的篩選結果有三列,匯出的檔案中該欄卻是空的。原因很單純。其中一位執行者順手把欄位 completed 改名為 done,覺得這樣比較好讀,另一位並不知道這件事。

分開的資料夾隔開了檔案,卻沒有讓兩人對決策達成共識。接下來分三步處理:先判斷這項工作是否值得拆分,再分配修改範圍並訂好共同約定,最後驗證整合結果,別讓這種意外一路拖到最後才發現。

檢查相依關係

通常有兩個理由值得拆分工作。第一,獨立探索不同範圍:同時查清楚清單如何顯示,以及匯出內容如何產生。第二,同時處理邊界已知、結果可驗證的不同部分。"這裡規劃、那裡執行、另一邊檢查"本身不需要三位參與者,一個工作階段依序做完即可。小型工作從一位執行者開始通常比較合理。

如果確實有理由拆分,接著要問:在還不知道 A 的結果時,B 有哪些部分可以先做?如果 B 完全仰賴 A,這些步驟就得依序進行。有時 B 可以先準備不相依的部分,但整合結果仍得等 A 完成。

用同一個購物清單例子來看,會有三種情況:

要做什麼能否同時開始原因
找出目前在哪裡篩選清單,以及匯出內容由哪裡產生可以查看的是不同區域,結論彼此不相依
針對尚未查明的原因準備最終修正查明原因後先調查;不同且可驗證的假設可以平行研究
撰寫篩選功能和匯出功能約定共同的資料格式後兩部分都依賴同一個欄位;沒有共識,結果就會對不上

第三列是最常見的陷阱。看起來篩選功能在 src/filter.js,匯出功能在 src/export-csv.js,檔案不同,兩部分似乎就互不相干。但它們讀的是同一筆資料、同一個欄位 completed。文章開頭的流程正是這樣壞掉的,分開檔案也救不了。是否獨立,要看行為和共同約定,不是看程式碼分散在幾個檔案裡。

可以請代理協助拆分工作,但先不要啟動執行者:

請將工作拆成幾個部分。每一部分都列出輸入資料、結果、
相依關係和驗證方式。標明哪些部分現在就能開始。
先不要啟動執行者。

這份回覆可以在啟動前先檢查。沒有未解決相依關係的部分,就是可以同時開始的候選。若相依關係欄是空的,最好對照專案確認一下:代理可能漏看了共用的資料模型或設定。

估算到整體結果所需的時間

大家通常用一個數字衡量加速效果:實際執行工作花了多久。但該計算的是拿到可接受的整體結果要多久。除了實際工作,還要算上分派給每位執行者的說明、每個人重新閱讀專案的時間、等待、檢查兩份結果,以及把它們整合起來。

用這個例子做個假設性估算。數字只是方便計算,不是效能測量:

計算項目一位執行者依序處理兩位執行者同時處理
額外的拆分準備:分派兩項工作並讓執行者達成共識0 分鐘5 分鐘
執行20 + 20 分鐘兩部分共 20 分鐘
檢查結果並整合10 分鐘15 分鐘
取得可接受結果的總時間50 分鐘40 分鐘
若因對資料的理解不同而花 15 分鐘重做其中一部分,總時間50 分鐘55 分鐘

兩種做法都需要共同的工作準備,因此表格沒有把它算進去。一次重做就會吃掉省下的十分鐘;整合成本越高,同時工作的方式就得省下越多時間才划算。

除了時間,還有兩種容易被忽略的成本。每多一位執行者,就得重新閱讀一次專案,這會消耗資源;他們回傳的詳細結果也會佔用共同對話的空間。第二種成本更重要:您自己的注意力。您得閱讀兩份結果、彼此核對,再做出決定。如果收到的內容讓您來不及看完,速度就不再由您掌握了。

當兩個規模相近、互不相依的部分,額外成本又不高時,速度有機會接近兩倍。但執行者的人數本身並不保證這件事。

重複工作,還是刻意複查

重複工作不會出現在報告裡。兩位執行者默默打開相同檔案,研究清單資料的結構,然後各自如實回報自己看過程式碼。但有時第二次檢查是刻意安排的:某個假設很關鍵,您希望由沒看過第一位推理過程的人來驗證。刻意複查和意外重複的差別在於,複查事先會說明檢查對象、原因,以及答案不一致時要怎麼處理。少了最後一項,複查就只是收集意見。

再看相反的情況。您問兩位執行者,清單資料中的 completed 代表什麼。兩人都回答一樣:這個項目已經買了。看起來像是兩邊都確認過。

其實兩人讀到的是 README.md 裡一年前寫下的一行說明,但程式中的欄位早就代表別的意思。他們一致的不是結論,而是資訊來源。

這裡有兩個實用習慣:

  • 請對方指出答案的依據:檔案、行號或程式碼片段。不要只聽轉述,要能自己打開查看;
  • 單獨且確實地驗證共同假設:程式實際做了什麼、整體流程又發生什麼。即使大家都同意,也要查證。

分開的工作階段不代表錯誤也彼此獨立:共用同一個來源,也可能一起看錯。答案不一致時,請檢查依據,不要計算票數:一個人可能看的是最新程式碼,另外兩人看的卻是過期筆記。

經過程式碼確認的欄位意義,才是共同資料模型的基礎,這個模型應在開始前先談妥。經過這三項檢查後,如果拆分工作看起來仍然划算,就可以開始分工。

為每個修改範圍指定負責人

平行工作時有個簡單原則:每個修改範圍只指定一位負責人。不是"這個檔案絕不能兩個人一起碰",而是"這兩項工作進行期間,這個檔案由他修改"。這是期間限定的約定,不是專案本身的屬性。

原則的另一半更重要,也更容易被忘記:整體結果也要有負責人,由他整合各部分,並判斷整體是否完成。如果沒指定整合負責人,工作就會落到最後一個完成的人手上,而他偏偏最不了解別人負責的部分。

啟動前先查看專案,確認需要處理的部分已經有某種分界。如果沒有,也不必為了平行工作就大規模重構:重構本身可能變成當天最大的一項工作,到時候也沒什麼可拆分了。

以我們的購物清單為例,分工可以這樣安排:

範圍修改者約定
src/filter.js, tests/filter.test.js執行者 A依照已談妥的欄位 completed 篩選項目
src/export-csv.js, tests/export-csv.test.js執行者 B依照已談妥的格式匯出傳入的項目集合
src/item-model.js整合負責人共用資料模型在開始前就已談妥;修改前先和所有相依者討論
src/app.js, tests/filter-export.test.js整合負責人串接兩部分,並驗證篩選後的清單能正確匯出
package.json, package-lock.json整合負責人執行者不順手新增相依套件

這張表分配的是修改責任,不是存取權限:需要讀取共用檔案的人都可以讀。

package.json 那一列不是故意刁難:npm install 會同時修改這兩個檔案,兩邊平行安裝很容易直接造成衝突;若安裝的是同一個函式庫的不同版本,整合時也會出問題。如果兩位執行者都需要某個套件,就請他們說明需要什麼、原因為何。由一個人決定並修改一次就好。

開始前先談妥共用資料模型

只有檔案分界、沒有共同約定,效果不會好。篩選和匯出都依賴同一種資料模型。下面是兩者介面的草圖,不是可執行的範例:這裡沒有列出函式實作。開始前也要約定保留項目順序、不修改原始陣列,以及在 CSV 中用 true/false 表示布林值。CSV 的跳脫規則維持不變。

// 清單中的一筆資料:這三個欄位事前談妥,不可改名
const item = { id: 41, title: "oat milk", completed: false };

// filter.js 回傳篩選後的資料,不負責格式化或匯出
filterItems(items, mode);   // mode: "all", "active", "completed"

// export-csv.js 接收已篩選的資料,不會自行篩選
exportCsv(items);           // 回傳欄位為 id,title,completed 的 CSV 字串

請注意,這裡約定的不是檔名,而是輸入和輸出。"匯出功能收到的已經是篩選後的清單"聽起來只是小細節,但正是這句話決定了兩位執行者由誰負責篩選。如果沒講清楚,兩人都可能合理地以為篩選由自己處理,最後匯出的檔案不是包含全部項目,就是重複篩選。

開始前也要談妥如何驗收結果。以這個例子來說,資料 41 和 43 的 completed: true,資料 42 則是 false。"completed" 模式應依照原本順序顯示 41 和 43;CSV 也應匯出這兩筆資料,標題列為 id,title,completed,最後一欄的值為 true。這個流程會同時經過兩個部分,正好能抓出本文開頭的那種錯誤。

另外也要談約定變更。如果工作進行到一半,發現共同格式必須調整,這就不只是修改單一檔案的小事。所有依賴該格式的工作都得重新檢查,因為已完成的部分可能是根據舊格式做的。

分開的工作目錄(git worktree)不能取代共同約定。它們能實際隔開修改,這很有幫助:在共用目錄裡執行檢查,可能會把另一項工作的未完成修改也算進去,最後通過的狀態其實沒有任何一位執行者單獨驗證過。不過資料夾無法替您談妥資料格式,而且連接埠、本機資料庫和其他外部資源仍然共用。未被追蹤的 .env 在新的資料夾裡預設根本不存在:需要另外複製過去,例如透過 .worktreeinclude。

給每位執行者一份簡短任務說明

任務說明不必很長。通常列出七項就夠了:目標、從哪個版本開始、負責的檔案、共同約定、可驗證的結果、回覆時要提供什麼,以及需要修改別人負責的範圍時該怎麼做。

目標:清單篩選器可顯示所有項目、只顯示未完成或只顯示已完成項目。
開始版本:已確認資料模型的主分支最新 commit。
您負責的檔案:src/filter.js 和 tests/filter.test.js。
共同約定:completed 欄位維持布林值,不更改欄位名稱;
篩選器回傳資料陣列,不負責匯出。
結果:篩選器測試通過;用三筆資料測試時,每種模式
都會回傳預期清單。
請回報:實際修改的檔案清單、測試執行結果、
執行測試所用的版本,以及尚未解決的問題。
如果需要修改 src/item-model.js 或 src/app.js:請先停下來,
說明需要的修改和原因,等候回覆。

給第二位執行者的說明也照這個方式寫:負責另一組檔案、遵循相同的資料格式、有自己的驗證結果,越界時也採取相同做法。這裡就不必把整份內容重寫一次了。

接著談回報內容。您需要的是實際修改檔案清單,以及實際的檢查結果。"沒有碰別人的檔案"很容易寫進回覆,而且您越反覆要求,這句話越可能出現。請核對修改清單,不要只看文字說明。任務說明中的界線是一項約定,不是權限限制:提示文字無法阻止代理寫入檔案,存取權限要另外設定。

由子代理負責部分工作時

在 Claude Code 中,子代理會使用自己的上下文視窗。一般子代理看不到您的對話,只會依照 Claude 撰寫的任務說明工作;fork 模式則會繼承整段對話。因此,最好在任務說明中明確列出共同約定和驗收條件。完成後會回傳摘要:讀起來方便,但不會顯示檔案實際改了哪些內容,而且摘要本身也會佔用主對話的空間。詳情請參閱子代理說明文件。

重新協調重疊範圍

遲早會有人碰到別人的負責範圍。執行者 B 發現,如果不修改 src/app.js,匯出功能就無處串接:匯出按鈕根本不會被呼叫。

好的回報應包含原因、需要的修改,以及相依關係。src/app.js 已由整合負責人負責,因此 B 可以先完成自己的模組,再提出串接需求。如果沒有共用修改就無法繼續自己的部分,就先暫停相依的工作。

接下來有兩種做法。整合負責人可以自行修改共用檔案,因為那是他的範圍。或者明確把該範圍交給執行者 B,但要先確認原負責人目前沒有修改這個檔案:交接時工作沒有停下來,就會出現分工原本要避免的狀況。

千萬別逼執行者繞過界線。像"別碰 app.js,自己想個辦法"這種要求,通常只會讓他在自己的檔案裡複製別人的邏輯,或多加一層後來沒人說得清楚的包裝。表面上遵守了分工表,實際上專案卻多出第二套匯出邏輯。

整合行為,不只是整合檔案

開始整合前,負責人需要先弄清楚三件事:每個部分從哪個版本開始、各位執行者在哪個版本上做了哪些檢查,以及實際修改了哪些檔案。這些都應該已寫在任務回報中,檔案清單則要和實際差異核對。

接著整合各部分,最重要的是執行開始前談妥的整體流程。兩種差異很大的問題可能會擋住進度。

文字衝突。不同部分修改了同一處、刪除或重新命名檔案,Git 無法自動整合。解決衝突後,還要檢查最後的行為。

語意不相容。沒有人同時修改同一行,文字也順利整合,沒有任何衝突訊息。問題就出在本文的欄位改名案例:篩選器讀取 done,匯出功能讀取 completed,最後什麼也匯不出來。兩部分各自的檢查仍然全數通過,因為它們只驗證自己的功能和資料。

順利整合不代表彼此相容

沒有衝突地完成整合,不代表行為相容。您可以透過介面操作整體流程,或用測試驗證函式之間的串接;各部分的個別檢查不能取代整體驗證。

兩部分工作整合為一個成果,再透過共同流程驗證執行者 A執行者 B整合負責人整體流程篩選和匯出一起驗證整合各部分src/filter.jssrc/export-csv.js
由一位負責人整合各部分,只有整體流程能驗證它們是否相容

請看圖中最下面的箭頭。上半部就是大家通常所說的分工:兩個獨立部分,各自在不同檔案中修改。至於整體是否完成,則要看下方會同時經過兩個部分的流程。在這個箭頭走完以前,您只有兩份各自的結果,還沒有整體成果。如果專案規定要執行完整的檢查,整體流程也不能取代那些檢查。

記錄共同決策

整合完成後,整體結果的負責人要決定下一步怎麼做。例如:

  1. 接受整體結果:流程通過、修改內容說得清楚、驗收條件都已符合。
  2. 退回特定部分修改,並指出哪裡和什麼不一致。不要只說"匯出怪怪的",而要說"匯出讀取的欄位已經不在資料模型裡了"。
  3. 重新檢視分工方式:減少執行者人數,或改成依序處理。

第三種做法很正常,不代表失敗。哪些跡象表示該重新考慮分工,很快就看得出來:

  • 共同資料格式一再改變,每次都得重做兩個部分;
  • 執行者彼此等待,表示原本就有相依關係,只是沒有說清楚;
  • 您收到結果的速度比自己讀完的速度還快。

最後一種狀況最令人頭痛,因為表面看起來像是成功。一次順利拆分也不代表每次都會如此:代理每次執行的結果都可能不同,重要的結論最好再用規模相近的工作驗證一次。

部分完成也可以是合理的結果。篩選功能可能已完成並通過檢查,但匯出功能還沒好,就如實記錄目前只完成兩部分中的一部分。整體工作仍未完成,不能因為其中一半能運作就宣告結束,分工安排得再周到也改變不了這一點。

檢查自己的理解

看兩種情況。先自己想想,再核對說明。

還沒找到錯誤原因。
匯出偶爾會產生空檔案,您很想立刻把修正交給兩位執行者。先重現問題並調查原因。如果找到不同且可驗證的假設,可以分別交給兩人研究。但沒有根據就提出兩種修正,還不算解決問題:每個修正都得連結到原因,並用原本的流程驗證。

檔案不同,數量卻是同一個。
篩選器以"件"計算商品數量,匯出功能卻以"包"輸出相同數量。兩邊檢查都通過,但畫面和檔案中的數字對不上。這不是程式碼錯誤:兩部分都沒有越過各自的界線。缺的是計量單位的約定。開始前要把它記錄在共同資料模型中,由整合負責人修改 src/item-model.js,再重新執行整體流程。

Claude Code 可以協助哪些事

就像本文一開始提到的,代理可以先草擬拆分方式,再依照您列出的重點整理成一份連貫的任務說明。還有三種用途也很實際,不過決策仍由您負責:

  • 草擬工作範圍清單。請代理檢視專案,列出每項工作會修改哪些檔案和路徑。這只是草稿,每個範圍的負責人仍由您指定。
  • 整合並執行整體檢查。代理可以整合各部分、列出完整修改清單,並執行整體流程。之後請您親自完整檢查這些修改。
  • 有疑問的地方。兩個聽起來都很有把握的說法,不代表決策已經確定。請對方提供依據、檔案和行號;至於誰能修改共用檔案,應由事先談妥的分工表決定,而不是看誰說得比較有說服力。

最後,重點是一項決策和兩個責任安排。決策是要不要拆分:每增加一位執行者,都應帶來足以抵銷任務準備、檢查和整合成本的效益。兩個責任安排則是每個修改範圍都有負責人,整體結果也有負責人。購物清單的例子正是缺少這些:沒談妥 completed 欄位,也沒指定誰要一起檢查篩選和匯出。工具可以代勞機械性的工作,但整合後的行為是否符合需求,仍得由人來判斷。