顯示具有 程式 標籤的文章。 顯示所有文章
顯示具有 程式 標籤的文章。 顯示所有文章

2026年9月14日 星期一

Uncle Bob 現在幾乎不看程式碼了——但他比誰都在意程式碼長什麼樣

 

Matt Pocock 前陣子直播訪了 Robert C. Martin,也就是《Clean Code》的作者、大家口中的 Uncle Bob。73 歲的人,本來以為會是「老派工程師教訓 AI 世代」的戲碼,結果完全不是。他去年十二月開始玩 coding agent,玩到現在,整套工作方式被他自己翻掉重來了一次。

我看完覺得有一堆東西值得寫下來,所以整理成這篇。

一開始,AI 是來扯後腿的

他說他早期試 ChatGPT、Grok 那些東西,沒什麼感覺。真正的轉折是他手上剛好有個專案,就順手叫 agent 幫忙寫。agent 是寫出來了,但東西很髒,他得一直在後面收拾。

他的結論當時是:這玩意兒很快,但它讓我變慢。

然後他想通了一件事,也是整場對談最關鍵的一句:正因為它快,它可以做一些我這輩子做不到的事。

那些「當年好棒但根本跑不動」的老點子

他舉了兩個 2000 年初的東西。

一個叫 CRAP 分數。做法是把測試覆蓋率跟函式的循環複雜度丟進一個公式,算出這個函式有多爛。概念超讚,但當年他跑完之後,面對一整串爛函式,要一個一個改、測試還要重寫,光想就放棄了。

另一個是 mutation testing(突變測試)。有個程式會去你的原始碼裡亂改:把大於改成小於、等於改成不等於、正號改負號,每改一次就把整套測試跑一遍。照理說測試應該要爆掉,如果沒爆,代表這段程式根本沒被真正測到,那隻「活下來的突變體」就得被解決掉。他當年跑一次要跑整晚。

兩個工具的共同問題都一樣:不是不好,是沒有那個人力去跑。

而 agent 剛好是那種又快、又不會抱怨工作很無聊、你叫它做它就做的勞動力。所以他現在就是叫 agent 寫完 code 之後自己跑 CRAP、自己跑 mutation testing、自己把洞補起來。以前要跑一整晚的,現在半小時。

他現在的目標講得很直接:讓自己完全不用看程式碼。他改成去看 CRAP 分數、偶爾抽查、跑一堆其他的檢查。理由也很誠實——agent 處理程式碼很快,他很慢,那他就不要把自己的慢強加在上面。

等一下,那為什麼還要在乎程式碼乾不乾淨?

這是我最想聽他回答的部分。既然人都不看了,髒就髒吧?

他的答案是:agent 一樣會被爛程式碼拖垮。

他早期讓 agent 一路往前做,不清理,結果就是它開始變慢、開始鬼打牆——改好這邊、弄壞那邊,回頭修那邊、又弄壞這邊,繞圈圈繞不出來。他甚至遇過 agent 直接放棄,講出類似「我搞不定這個了」的話。

所以門檻可能跟人不一樣,但那個門檻是存在的。程式碼可以亂到連 agent 都投降。

別再往 prompt 裡塞規則了

大部分人碰到 agent 亂寫,反應是拚命加指令:claude.md 越寫越長、agents.md 塞滿規矩,看到什麼壞習慣就加一條。

Uncle Bob 一開始也是這樣,寫到五頁十頁在講什麼是 clean code、什麼是 TDD。然後他發現 agent 對這些規則的態度,用他的說法是很「神鬼奇航」——那不是規定,那比較像是參考用的建議。

背後有技術原因,叫 lost in the middle。context window 裡最前面跟最後面的東西比較有份量,中間的會被淡化。而你寫在開頭的東西,只要夠長,隨著 context 累積就會被推進中間,然後就沒了。你的第 50 句、第 80 句規則,基本上不存在。

所以他的做法是兩件事:

  1. 初始 prompt 砍到不能再砍,只留真正重要的,讓它留在「有份量」的位置。
  2. 其他全部交給確定性工具。

工具不會被淡化。工具的做法是把 agent 丟進迴圈:你改,改到這個工具說 OK 為止。於是 agent 就自己在那邊繞——補測試、拆函式、降複雜度——繞到過關。

當然這是拿速度換品質。他也承認總有一天會換過頭,慢到還不如人自己寫,但目前還沒摸到那個點。

他的 agent 流水線

他現在不是一隻 agent 做完全部,是分工:

  • Specifier:把人寫的文件轉成 Gherkin(given/when/then 那種驗收測試)跟一份 QA 流程。而且他要求用「你是一個人類,你正在用 UI 操作這個系統,你要證明它能動」的角度寫。
  • Coder:寫單元測試跟實作,讓 Gherkin 通過。
  • Cleaner:跑 CRAP 分析、做 code review,收拾 coder 留下的爛攤子(他說到這一步一定是一團亂)。
  • Hardener:跑 mutation testing,這隻最狠,每個等號每個小於號都不放過。
  • QA agent:把 QA 文件變成可執行的腳本,實際操作系統跑出結果。

拆開的好處有兩個:可以平行跑,以及每隻 agent 的任務夠窄,context 就控制得住,lost in the middle 沒那麼嚴重,你也才塞得進多一點規則。而且可以讓 agent 用完即死,下一隻拿到乾淨的 context。

代價是啟動成本,每隻開起來、重新理解狀況都要時間。一個單獨 agent 五分鐘(但結果很可疑)能做完的事,這條流水線要跑一小時。不過人自己做要半天,所以還是划算四五倍,而且品質遠比人手工做的高。

「軌跡」這個概念

Matt 丟出一個我覺得很實用的說法:你在控制的不只是 context window 的內容,還有它的軌跡。

你一旦在某個 session 裡把 agent 推往某個方向,之後這個 session 裡所有的事情都會沿著那個方向走。你要它測 UI 一次,接下來它每次都會想測 UI。要清掉軌跡,只能清掉 context。

Uncle Bob 完全同意,還補了一個非工程師也懂的例子:你在跟模型聊咖啡怎麼煮,旁邊有人經過在聊昨天的八點檔,這段話進了 context。從此之後,所有咖啡的討論都會沾上八點檔的味道。模型分不出來哪句話是你說的、哪句是路人說的。

所以重點是讓 context 裡的東西保持方向一致。方向一致,那些莫名其妙的幻覺就少很多。

模組化,還是那個模組化

那如果測試很完整、但 API 設計爛、模組切得亂七八糟呢?

他說理由跟當年講 clean code 一模一樣:切得好、介面乾淨的東西,人才抓得住,因為人是靠分區塊在理解事情的。模型也一樣。模組如果塞滿了不相干的東西,agent 進去也會茫然。這就是咖啡跟八點檔的問題換個地方發生而已。

他的做法蠻硬派的:

  • 叫 agent 幫他做了一個架構檢視器,會畫出類 UML 的模組圖,可以點進去看子模組、再點下去看程式碼,想看多細就多細。
  • 另外寫了一個確定性工具,用一份規格檔定義哪個模組可以依賴誰、不能依賴誰、相依性往哪個方向流。最後有個檢查器在跑,違反了就得想辦法修——反轉相依、插介面、把模組拆兩半之類的。

他說他正在試著把這步也自動化,目前不太順利。誠實。

(對談中也提到 John Ousterhout 的 deep module:介面窄、內部藏很多。這對 agent 特別友善,因為它可以只讀介面就動手,不用讀實作。當然那也是風險,前提是底下的東西真的一致。)

哪些東西該改?

他被問到《Clean Code》裡有沒有東西要修正,講了兩點,我覺得都很有料。

第一,門檻要調。 agent 的短期記憶又大又精準,跟人不是同一個量級。所以他把允許的函式規模放寬了:給人看的話 CRAP 分數他會壓在 4 以下,給 agent 他調到 6,還在考慮要不要推到 8。他也說他跟 agent 辯論過這件事,然後補一句——跟 agent 辯論的結果你不能信,但他還是照辯不誤。

第二,TDD 不要硬套在 agent 身上。 他自己是 TDD 的死忠,但他說那是人類的紀律,是因為人腦就長那樣。叫 agent 寫一行測試再寫一行實作,沒有意義。他允許 agent 用比較 Ousterhout 式的做法:寫完一個函式,測那個函式,再寫下一個。反正就算你叫它嚴格 TDD,它最後也會滑回這條路。

他給了一句我很喜歡的總結:不要把人的「紀律」強加給 agent,但人的「價值觀」該加還是要加。 行為可以不一樣,門檻可以不一樣,在乎的東西不能不一樣。

關於 spec-driven development,他不看好

Matt 問他在丟進流水線之前做多少規劃。他的回答基本上是在潑冷水。

「先規格規格規格,規格完再交出去」這個誘惑很老了,70 年代就有,結果是瀑布式開發,而敏捷就是對它的反擊。現在大家又想對 agent 做同一件事。

他試過,而且說結果永遠是災難,而且災難長得都一樣:你把計畫寫得漂漂亮亮,agent 開跑之後你才發現它根本照著跑不了,因為你沒想到的事很多,而它沒有你聰明。於是它半吊子地往某個荒謬方向衝,你得喊停、倒帶、重寫計畫、重開一次。

所以他放棄了,改回敏捷那套:做一兩個 story,回頭看架構,必要時手動整理一下,再做幾個。

他有個我很愛的比喻。假設蓋房子的任何一次修改都只要一塊錢,包括打地基、蓋屋頂,全部都是一塊錢一次。你會怎麼蓋?你會先花幾千塊請建築師畫一份完美的圖,然後花一塊錢叫工人一次蓋好嗎?還是你會直接跟工人說:地基放這,形狀這樣——欸不對,改一下——廚房放這邊客廳放那邊——不行動線很爛,樓梯移開——

答案很明顯。而修改的成本已經跌到接近零了。既然如此,你為什麼要花大錢在前面規劃?直接調到對為止就好。

他也不留規格。規格是用完即丟的,會一直變。以前原始碼就是最終的規格,因為那是人寫的;現在人不寫了,很多人不習慣沒有一份「人類定義的東西」在最上游,但他覺得不用勉強。

延伸出來的做法也很有趣:他自己寫了一堆工具(CRAP for Clojure / Java / Go、mutation tester、agent harness),但他跟大家說不要下載。那些是為他自己寫的。你該做的是叫你的 agent 去看那些東西,然後幫你做一個你自己的。與其給你成品,不如給你本質,再讓你客製。

一個很好笑的不對稱

Matt 講了一句話我覺得該裱起來:你丟一份長規格給人類,命中率可能 20%,講不定 5%;丟給 agent,它真的會讀完。

Uncle Bob 接下去:反過來,agent 寫的東西,人類根本不讀。

它們期待我們讀完它們寫的所有東西,而我們就是不讀。

那新人要怎麼辦?

如果 agent 已經把「戰術層」的工作吃掉了,那沒經驗的人怎麼練出「戰略層」的判斷?

他老實說他沒有標準答案,但他的想法是這樣:

先寫程式碼,寫個一年,寫到你知道 agent 在面對什麼。然後進到一間重度使用 agent 的公司之後——你應該被當成一隻 agent 對待。帶你的人給你的任務,應該跟他給 agent 的任務一樣;你也要被同一套確定性工具檢查。你會有好幾個月極度沒生產力,但你會學到非常多。撐過那個關卡,也許你才有資格自己操作 agent。

他把這個講成一條完整的路:從二進位、組合語言,到 C 這種基本的東西,再到 Python 這類高階語言,然後才是 agent 跟確定性工具,最後在監督下做戰略性的操作。

順帶一提,他十年前就在講:如果你從沒寫過組合語言,花一個週末寫一次。不然你整天寫 Java,你活在一個幻想世界裡,底下還有你不懂的魔法。

還有一段我覺得是整場最實用的。Matt 問他當初怎麼知道 agent 寫的是垃圾。他說看 code 看出髒東西不是重點,重點是他看得出 agent 在掙扎——那個原地打轉的樣子他認得,因為他自己經歷過。新手的問題不是不會寫程式,是認不出那個掙扎。

要怎麼學?他推薦去翻那些沒人讀的老書,Tom DeMarco、Ed Yourdon、《The Pragmatic Programmer》那一類。裡面有些東西確實過時了,得自己過濾,但這些教訓就是在那個年代學會的。

結論:抽象層又爬了一階,然後呢

他最後把這件事放回歷史線上。

我們的抽象層從二進位到組合語言、到編譯器,現在到了模型這一層。每一次往上爬,站在下一階的人都會說:完了,這下什麼都毀了,工作要沒了,五歲小孩都能寫程式了。當年講這句話的人,嘴裡講的還是二進位。

然後呢?每次都一樣。規則沒變,那些基本功因為同樣的理由繼續存在。

他說軟體大概是人類嘗試過最複雜的東西,而所謂的基本功,就是我們把複雜度整理成「腦袋裝得下」的形狀的方法——不只是人的腦袋,模型也是,畢竟模型某種程度上就是照著人建出來的。

那些現在覺得基本功不重要的人,他說他們會學到教訓,而且不會花太久。他自己撞過那面牆,知道牆在哪,所以不想再撞一次。

他的原話大意是:你現在丟掉的那些規則,一年後你會從地上把它們撿起來,拍掉灰塵,然後想起你為什麼需要它們。


原始對談:Matt Pocock 訪談 Robert C. Martin,2026 年 8 月直播。