你的 Repo 從來都不是故事的全部

程式碼展示的是已存在的東西。真正的原因散落在規格、事故、數據與決策之中。

你的 Repo 從來都不是故事的全部

在一個功能上線六個月後再打開它的 repository,你仍然可以重建出很多東西。你可以追溯架構、檢視 schema、閱讀測試,並清楚看到究竟改了哪些程式碼行。

但你通常無法重建的,是那些令這些程式碼行變得必要的對話。

程式碼不會告訴你,某條驗證規則之所以存在,是因為有一位客戶會送出格式錯誤的 exports。它不會解釋,一個看似奇怪的重試策略其實是在防止下游系統出現重複交易。它也不會顯示,較乾淨的介面是在無障礙測試後被否決,或者某個服務邊界反映的是合約限制,而不是工程上的偏好。

Git 很擅長保存程式碼歷史。但只有當團隊刻意把意圖寫下來,並持續把它與實作連結起來時,它才會保存這些意圖。

這個落差一直都是軟件工程的一部分。AI 編碼工具只是讓它變得更明顯。系統可以讀遍 repository 裏的每一個檔案、追蹤每一個 symbol,並產生一個在技術上看來很有說服力的 patch,卻依然在解決錯的問題。

問題不在於程式碼具有誤導性,而在於程式碼回答的是一個更狹窄的問題。

工程真相的五個層次

大多數有意義的軟件變更,都依賴五個不同層次的證據。

  1. 意圖 — 使用者、客戶或業務到底想達成甚麼結果?這些內容可能存在於規格、ticket、支援對話或會議筆記中。
  2. 限制條件 — 甚麼絕對不能被破壞?相容性承諾、安全邊界、法規、合約、預算與期限,往往都不在 repository 裏。
  3. 實作 — 系統今天是如何運作的?程式碼、測試、schema、相依套件與部署設定構成了這一層。
  4. 執行時證據 — 真實系統裏正在發生甚麼?日誌、trace、metrics、生產數據與事故報告,可能會推翻那些在程式碼中看來合理的假設。
  5. 決策歷史 — 為甚麼會選擇目前這種做法?Pull requests、設計討論、被否決的替代方案,以及過往事故,都藏着答案。

repository 在第三層最有優勢。它確實包含其他幾層的一部分,但通常遠不足以完整代表它們。

這之所以重要,是因為軟件失敗往往出現在各層之間的邊界。實作符合的是一份過時的規格。修正滿足了 ticket,卻違反了營運限制。測試之所以通過,是因為它們編碼的是昨天的假設。程式碼在內部自洽,但生產數據卻遵循着一種從未有人記錄下來的模式。

一個在本地看來正確的 patch,仍然可能是錯的變更。

儲存庫本身無法回答甚麼

試想像一位使用者編輯了一份文件,之後搜尋更新後的句子,結果卻只看到舊版本。「讓搜尋立即更新」聽起來像是一個很明確的要求。儲存庫會揭示幾個可能的切入點,但它本身無法自行界定甚麼才是正確的修復方式。

問題 可能的來源
文件的哪個版本才是權威版本? 原始文件及修訂歷史
舊文字還殘留在哪裡? 同步日誌、擷取輸出、搜尋索引或快取
對這個產品而言,「立即」是甚麼意思? 產品承諾或服務目標
文件內容變更時,其權限是否也一併改變? 原始權限及稽核歷史
過時結果是否只限於某位使用者、某個來源或某個地區? 請求追蹤及生產指標

搜尋程式碼或許能解釋結果是如何返回的,但它無法告訴你,真正的缺陷究竟是同步延遲、擷取內容過時、快取失效、權限傳播問題,還是產品從未明確定義過的預期。

在成熟系統中,這種區分會變得更加重要。看似已過時的欄位,可能仍然支援某個舊版客戶端。看起來重複的服務,可能其實是在分隔具有不同權限要求的資料。表面上似乎多餘的檢查,可能是目前團隊從未親歷過的某次生產事故,在程式碼層面留下的唯一痕跡。

刪除複雜性是有價值的。把偽裝成複雜性的歷史一併刪掉,代價卻很高。

即使有更多上下文,仍然可能得出錯誤答案

最直觀的解法,是給 AI 更多材料:整個儲存庫、每一張工單、每一份文件、每一則訊息,以及每一條日誌。

這帶來的是存取,不是理解。

來源可能已過時、彼此矛盾、帶有推測性,或是為不同受眾而寫。腦力激盪內容不應凌駕於已核准的規格之上。六個月前的需求,不應悄悄推翻昨天才作出的產品決策。生產日誌應與產生它的發佈版本、環境及程式碼路徑對應起來。客戶請求若未先確認適用範圍,不應被當作普遍需求。

因此,一個嚴肅的上下文系統需要的不只是檢索。它還需要一種方式去推理:

  • 權威性: 哪個來源有資格定義需求?
  • 時效性: 哪些資訊是最新的,哪些已被取代?
  • 來源脈絡: 每一項主張、限制或結論是從哪裡來的?
  • 關聯性: 哪些問題、發佈、客戶、資料集與程式碼路徑是彼此相關的?
  • 權限: 哪些來源可用於這項任務,並可展示給這個人?

上下文不是一堆 token,而是一個帶有時間、權威性與邊界的圖譜。

更多上下文應帶來更多證據,而不是在沒有證據的情況下帶來更高信心。

真正的工作單位是變更

編輯器和編碼工具是圍繞檔案來組織的,因為檔案是我們修改的對象。工程團隊則是圍繞變更來組織的。

一項變更始於一個原因。它會演變成需求,觸及程式碼與資料,經過審查,進入生產,並產生新的證據。如果這些階段彼此脫節,未來每一項任務都得再來一輪考古。

一個處理真實軟件的 AI 系統,應該遵循這個生命週期。

在實作之前,它應該識別請求、相關限制,以及任何互相衝突的來源。它應該知道自己是在修復缺陷、改變預期行為,還是引入新的契約。

在實作期間,它應該把每一個有意義的選擇都連結到證據。為甚麼是這個模組?為甚麼採用這種遷移策略?為甚麼要保留這個分支?這些解釋應該在產生程式碼的那段對話之外,仍然能夠留存。

實作完成後,系統應將驗證結果、審查決定,以及新發現的限制條件附加到這次變更上。否則下一個人——或下一次 AI 工作階段——就得重新把這些資訊找出來。

這就是只能編輯儲存庫的工具,與能參與工程工作的系統之間的分別。

AI 應該減少重建成本,而不是取代判斷

更好的上下文有時被視為通往自主軟件開發的路徑。但它眼前的價值沒有那麼戲劇化,卻更實用:在作出變更之前,降低重建現實狀況的成本。

AI 可以把原始需求放到相關程式碼旁邊。它可以找出某個不尋常保護措施背後的事故。它可以把失敗的指標連結到改變了它的那次發佈。它也可以在實作開始前,就指出兩個權威來源之間存在分歧。

這些能力不會消除工程判斷。它們會讓判斷建立在更充分的資訊之上。

最終仍然要由人來決定哪些取捨是可接受的、需求是否完整,以及一次發佈可以承受多少風險。系統應該讓證據清晰可見,讓推理過程可供檢視,而不是用一個看似漂亮的 patch 掩蓋不確定性。

衡量標準不是「它能不能產生程式碼?」

衡量標準是「它能不能解釋,為甚麼現在這樣改才是正確的變更?」

從理解儲存庫,到理解工作本身

編碼助手最初之所以變得有用,是因為它們能理解開發者眼前的檔案。接下來的重要一步,是對儲存庫的理解:找出相關程式碼、追蹤符號,並在整個專案中套用變更。

下一步,是理解儲存庫周圍正在進行的工作。

這意味著要把程式碼連結到提出它的規格、釐清它的對話、質疑它的生產環境證據,以及之後應被記住的決策。這也意味著要排除無關、過時,或超出使用者權限範圍的上下文。

在打造 Dvina 的過程中,這是我們不斷回到的一個想法。工作並不是發生在單一檔案、單一應用程式或單一對話之內。意義存在於它們之間的連結,以及這些連結如何隨時間改變。

儲存庫依然至關重要。它是系統行為可執行的事實來源。只是對於產品意圖、營運現實,或組織記憶而言,它並不是完整的事實來源。

完整脈絡會改變最終建成的東西

如果只有程式碼,自然會問:

甚麼樣的變更適合這個系統?

如果有更廣闊的上下文,問題就會變成:

甚麼樣的變更,才同時適合這個系統、這項需求、這段歷史,以及當下這個時刻?

第二個問題能在限制演變成回歸之前先把它們識別出來。它讓審閱者理解實作背後的理據。它幫助新加入的團隊成員明白,為甚麼系統會是現在這個樣子。它也為 AI 賦予一個有根有據的角色:不是編輯器裏的神諭,而是能夠在整個工作過程中整合證據的參與者。

你的 repo 從來都不是全部的故事。

真正的機會,是建立能讀懂其餘部分的系統——而且能展示它們的推理過程。

加入 Dvina

免費註冊,把你所有工具整合到一個簡單的工作空間。

探索更多


我們只會收集確保服務順暢運作所需的分析資料。