AI 輔助開發

為何生產力指標會懲罰你最出色的工程工作

提交次數和新增的程式碼行數獎勵的是產量,而非進度。這就是為什麼刪除程式碼會吃虧,以及在 AI 撰寫大量程式碼的現在,我們該衡量什麼。

本文由 AI 模型從英文原文翻譯而來,用字可能與原文有所出入。 閱讀英文原文

大多數的軟體生產力指標衡量的是錯誤的東西,而且在機器開始寫程式碼之前,它們就已經錯了。提交次數、新增的程式碼行數、關閉的工單數以及總程式碼量,都獎勵產出更多的東西。但最好的工程工作通常是產出更少的東西。你刪除一個無用的模組、你用一個清晰的服務取代三個糾纏不清的服務、你從根本上修復一個錯誤而不是繞過它打補丁。這些成果中的每一項,在量化指標上都被記錄為負數或零。當你為產出付費時,你就會得到產出,而產出不等於進展。這篇文章是關於哪些指標會扭曲好的工作、為什麼 AI 編碼讓這個問題更加尖銳,以及應該改為衡量什麼。

獎勵錯誤行為的指標

從最常見的儀表板開始看起。新增的程式碼行數。提交次數。燃盡的故事點數。每週關閉的工單數。合併的拉取請求數。這些指標中的每一項看起來都像是價值的代理指標,但每一項都在默默地獎勵著與你期望相反的行為。

思考一個真實的工作樣貌。一位工程師花了四天時間閱讀一個再也沒人懂的子系統,然後刪除了六百行程式碼,並用八十行取而代之。現在這個系統做著同樣的工作,卻有著更少的故障模式,並且對於下一位接手的人來說是可讀的。在儀表板上,這顯示為負五百二十行程式碼、一次提交,以及一整個星期沒有關閉任何功能工單。以任何量化指標來看,那位工程師這週的表現都很差。但實際上,這是團隊中任何人在那一季裡最有價值的一週之一。

現在,再想想另一位工程師,他接了同一個工單,然後在現有的架構上硬是疊加了一個新服務。新增了兩千行程式碼、十四次提交、一個全新的設定檔、一個新的部署目標。儀表板上一片綠燈。系統現在變得更難以理解,也有了更多可能出錯的地方,但這一切在數字上都看不出來,而獎勵結構正好告訴了所有人,這兩種方法中哪一種會被注意到。

為何刪除與簡化總是輸

刪除是指標反向運作最明顯的例子。移除程式碼通常是你能對系統做的影響最大的事,因為你刪除的每一行程式碼,都再也不會產生 bug、拖慢建置、混淆讀者或需要維護。一個在保持其功能的同時縮小的程式碼庫,正變得更健康。然而,沒有任何標準指標會將刪除視為正向貢獻。它最多就是忽略它。通常,它會將其評分為比什麼都不做還少的工作量。

根本原因的修復也以同樣的方式輸掉。一個經過兩天調查後才真正解決的困難 bug,可能只產生三行程式碼的變更。一個隱藏症狀的淺層修補程式,可能會產生五十行程式碼和三次提交,並在之後再次出錯時產生更多工單。指標偏好那個修補程式。它也偏好未來的工單,因為那會是下個月另一個結案的項目。

說不也輸了。一位說服團隊不要開發某個會成為維護負擔的功能的工程師,做了真正有價值的工作。他們預防了成本。但預防的成本是看不見的。你沒有寫的那兩千行程式碼、你沒有部署的那個服務、你永遠不會收到的 on-call 呼叫,都沒有對應的細項。指標只能看見存在的東西,所以打造不必要東西的人,得分會比阻止它的人更高。

這三者背後的模式是相同的。量化指標只能衡量加法,而許多最優秀的工程工作卻是減法。

古德哈特定律如何造成其餘的損害

有一條規則可以解釋,為何情況會隨時間惡化,而非僅僅維持不準確。當一個指標變成了目標,它就不再是一個好的指標了。人們並非被動的。當一個數字決定了你的考績、你的獎金或你的地位時,你就會開始迎合那個數字,而那個數字也就不再能描述現實了。

以 commit 數量為目標,會教人將一個變更拆成八個 commit。一個以增加程式碼行數為導向的文化,會教人透過撰寫更多程式碼來解決問題,因為獎勵在於數量,而非清晰度。以關閉 ticket 數量為目標,會教人將工作切成許多小 ticket,並避免處理那些會拉低他們每週計數的、深入的單一 ticket 問題。這一切都不需要任何人不誠實。它只需要他們對激勵措施做出反應,而每個人都會如此。

所以,一個數量指標不僅無法捕捉到好的工作成果。它還會主動地訓練團隊去產出那種能得到高分的工作,也就是那種被填充、過度建構、易於計算的類型。這個指標劣化了它本應觀察的事物。你最終得到的是一個為儀表板而最佳化的程式碼庫。

為何 AI 編碼會完全打破產量指標

在人類親手撰寫每一行程式碼的時代,上述的一切都是事實。AI 程式碼助理採用了同樣破碎的指標,並剝奪了它們僅存的最後一點意義。

原因是 AI 讓產量幾乎變得免費。一個模型可以在一分鐘內生成五百行程式碼。它可以在午餐前就產生相當於十次提交的變更量。如果你的指標獎勵新增的程式碼行數或提交次數,那麼助理現在可以自行滿足該指標,而坐在它旁邊的人類,幾乎不需思考,就能產出三年前看起來堪稱英雄的數字。產出已與努力脫鉤,甚至更進一步地與價值脫鉤。

機器不會做的是決定什麼應該存在。在 AI 輔助的工程中,稀缺的工作是判斷力。正確地定義問題。決定什麼不該建構。批判性地閱讀生成的程式碼,並丟棄錯誤、不安全或過於龐大的部分。將模型過度生成的解決方案刪減至實際符合系統的版本。這些任務決定了 AI 是讓程式碼庫變得更好還是僅僅是更大,而它們沒有一項會以產量呈現。如果說有什麼影響的話,那就是做好這些事反而會降低你的程式碼行數和提交次數,因為對生成程式碼的良好審查,主要意味著拒絕和精簡它。

因此,在 AI 時代,產量指標不僅僅是持續錯誤。它們現在獎勵已變得廉價的事物,並懲罰已變得稀缺的事物。一個以產出衡量的團隊會用 AI 讓自己被程式碼淹沒。一個以成果衡量的團隊會使用同樣的 AI,最終用更少的程式碼完成更多的事。

那麼該衡量什麼

解決方法是衡量工作的成果,而非產出工作的過程。成果指標更難被操弄,因為它們與實際情況的改善有關,而不是與看似忙碌的活動有關。

最強烈的信號是關於系統是否正常運作,以及你能多快地安全變更它。服務有多可靠。一個變更從想法到上線生產需要多長時間。部署造成事故的頻率有多高。有多少比例的變更被還原。當出現問題時,需要多長時間才能恢復。這些描述了系統的健康狀況和工作流程,你無法透過填充 commits 來改善它們。你只能透過真正地讓系統變得更好來改善它們,而這才是重點。

除此之外,要明確地重視簡化。將一個保留行為的刪除視為第一流的貢獻,並在審查和晉升中如此說明。計算你拒絕的範疇,而不僅僅是你交付的範疇。當有人阻止了一個會成為負擔的功能時,這個決定應該是可見且值得讚揚的,就像一個已交付的功能一樣。如果唯一受獎勵的動詞是「建置」,你就會得到建置,包括那些本不該發生的建置。

以下用簡單的詞語來對比。

不好的指標(獎勵數量) 較好的指標(獎勵成果)
增加的程式碼行數 變更還原率
每週 commits 數 從想法到上線生產的前置時間
關閉的 tickets 數 每次 deploy 的事故率
合併的 pull requests 數 從故障中恢復的時間
總程式碼量 運行中系統的可靠性
交付的功能數 拒絕了會增加成本的範疇

右側的指標沒有一項可以透過為了寫而寫更多程式碼來滿足。當你寫得更少時,其中大部分指標反而會改善。這就是你想要的特性。一個好的指標應該讓刪除、簡化和克制看起來和它們實際上所是的一樣好。

指標是場對話,而非計分板

最後一點是關於如何使用這一切。即使是再好的指標,一旦成為目標,也會變得有害,因為古德哈特定律(Goodhart's law)並不在乎你選擇了哪個數字。復原變更率可以透過從不交付任何有風險的東西來操弄。前置時間可以透過縮減審查來操弄。任何單一數字,一旦變成決定薪酬和地位的計分板,就會被不斷優化,直到它失去原有的意義。

所以,指標的正確角色是作為問題的開端,而非判斷的終點。不斷上升的事件發生率是個探問「發生了什麼變化」的理由,而不是一根棍子。一週的負行數是個提示,該去看看哪些地方被簡化了,而不是一個紅字標記。數字告訴你該往哪裡看。但仍需要有人去看。當你跳過這一步,讓儀表板直接為人們評分時,你得到的將是那種由數量指標一直以來所產生的、被填充、過度建構、為儀表板量身打造的工作成果,而現在,一台樂於提供你所要求之任何數量的機器,正以前所未有的速度生成這些成果。

整件事可以歸結為一個指令。在這個機器讓數量幾乎免費的時代,停止衡量產出了多少。衡量系統是否變得更好,肯定那些使其更簡單的工作,並將每個數字都視為一個討論的話題,而不是追逐的目標。少,但做得對,才是真正的工作。指標應該要能反映這一點。