[翻譯] 如何解決技術負債
Posted on October 11th, 2013
原作者: Henrik Kniberg
- henrik.kniberg@spotify.com
- http://www.crisp.se/henrik.kniberg
原文:http://blog.crisp.se/2013/07/12/henrikkniberg/the-solution-to-technical-debt
你是否試圖在你的軟體開發團隊中,導入敏捷式開發呢?如果是,當下次所有成員齊聚一堂的時候,問問看:
**你覺得我們的程式碼目前品質如何?**
讓每個人都給個 1 到 5 之間的分數。5 代表「太棒了,我以我們的程式為榮!」,1 則是「根本是團垃圾」。如果你看到大多是 4 到 5 分,沒有人給少於 3 分,那接下來的章節你就沒有必要看下去了。
如果分布很不平均,有些是 5,有些是 1,那你就有必要做一番探索。這些分數不平均的地方,是否分散在整個軟體專案的不同部分呢?如果如此,為什麼每個部分的程式碼品質不一?還是,其實是團隊成員對同一塊程式給予的評價不一?若是如此,不同成員所給的不同評價,又到底代表什麼?
而很有可能,你看到的分數,大約都只有 2 分或是更低,鮮少有 4 到 5 分。這種狀況,叫做「技術負債」( Technical Debt),但因為本文的特別意圖,我在這邊直接稱之為「爛程式」( Crappy Code)。
恭喜,你剛剛發現了一個嚴重的問題!你甚至已經把問題量化了。要做這件事,只需要花上一分鐘,而且什麼人都可以做,完全不需要有敏捷教練(Agile Coach)或是 Scrum Master 幫忙。我們接下來更進一步,釐清問題-把剛才的統計結果寫在一面白板上,放到牆上。將問題視覺化,可是解決問題的一大步!
別擔心,你並不孤單,這是個常見的問題。(不過,這也是個很愚蠢而沒有必要的問題,我一直搞不懂為什麼會這麼常見。)
現在,你要開始問自己一些嚴肅的問題。
## 我們想這樣下去嗎?
如果不是,那,我們希望我們的程式碼,具有怎樣的水準?大多開發者都會希望有 4 到 5 分,是的,即便這個標準非常主觀,仍然是個有用的標準。
如果每個人意見差距很大,你就應該就所謂的程式碼品質的意義,以及你希望在團隊中發揮
## 造成問題的原因是什麼?
這只是一個修辭學的問題而已,因為答案很清楚。
事情會是這樣,因為他們就是這樣演變的 - Jerry Weinberg
程式碼裡頭出現垃圾,那是因為 *軟體工程師把垃圾放了進去*。也就是說:**垃圾程式都是工程師寫出來的**。是由軟體工程師透過確實存在的鍵盤把確實存在的程式碼輸入到確實存在的電腦裡。不管什麼其他的環境因素,軟體工程師的行動,決定了程式碼的品質。
要解決技術負債的第一步,就是承認與接受事實。
「不過,這些爛程式並不是我們寫的,是前人留下來的!」
好,的確如此。如果是這樣,問題就會是「程式碼品質後來有改善,還是愈來愈糟?」我們再來打一個 1 到 5 的分數(1 是「飛快地變糟」, 5 則是「飛快地變好」)。然後,我們用評分的結果,重新看本文提到的內容。
## 我們為什麼在製造爛程式?
答案可能有很多種。不過,當我問過自己這個問題很多次之後,我發現有股明顯的趨勢。
可能並不是你「想」寫爛程式。我從來沒有遇過喜歡寫爛程式的開發者。
可能並不是因為你不知道「怎麼」寫乾淨的程式碼。雖然每個人寫程式的技術能力不同,但是每個團隊中都一定會有人知道怎麼撰寫乾淨的程式碼,而且其他人都應該學習的技術。養成程式碼審核(code review)或是配對撰寫程式(pair programming)的習慣,幾乎所有的團隊只要花上點時間,都具有把程式品質提昇到自認 4 到 5 分水準的能力。
可能只是因為 [破窗效應](http://en.wikipedia.org/wiki/Broken_windows_theory) 。爛程式的存在導致出現了更多的爛程式,人們在寫新的程式碼的時候,覺得只要跟原本的程式碼是同一個品質就可以了。如果你意識到這件事,你可以決定馬上 [停止](https://www.youtube.com/watch?v=Ow0lr63y4Mw) 這樣下去,並且透過程式碼審核與配對撰寫程式約束自己。
不過,最有可能造成寫出爛程式的原因是:「壓力」。
我經常聽到有人說「我們沒有 *時間* 撰寫乾淨的程式碼」。(這種說法是從最壞的角度說根本是種謊言,從最好的角度也只是個藉口。)真相是,你跟所有人一樣,每天都有 24 小時,而且由你決定你要做些什麼事。面對以下事實:你根本就有時間撰寫乾淨的程式碼,只是你決定不這麼做而已。-我們繼續來看看所謂的「壓力」是怎麼一回事。
## 壓力從何而來?
你可能會想要做一下 [成因分析](http://blog.crisp.se/2009/09/29/henrikkniberg/1254176460000) (cause-effect analysis)。是產品所有者給你壓力嗎?為什麼?誰又給了產品所有者壓力?誰又給了這個給產品所有者壓力的人壓力?我們來把壓力的連鎖畫成圖表。
然後問問自己,「真的」有壓力嗎?這些人真的「要」你去寫爛程式嗎?他們真的知道寫了爛程式之後,會造成什麼後續問題嗎?(我敢打賭你可以列出一堆後續問題),他們真的覺得這樣值得嗎?可能不會。那,你就走到他們前面,把事情問清楚。
有時候,壓力的來源只是工程師自己而已。發展一項新功能所需要的時間,往往比我們想像中來得久,我們又想要當「好工程師」好讓持股人高興,所以,壓力並不是外來的,而都是內部產生的。
附註:有時會寫出爛程式確實有其商業考量。我們可能要用最少成本達成某個重要的短程目標,或是我們只是想寫一個雛形丟到市場上試試水溫。但這些只能夠是 *例外*,而非常態。如果你在達成短期目標之後可以清理程式碼,或是你把原本的雛形丟掉重寫,你就不會陷在爛程式的泥沼中。
## 我們該馬上決定停止寫爛程式嗎?
這是最重要的問題。
如果你是工程師,你身為工程師這件事情造就了前述的問題,可說是件好消息。因為你就具備了解決問題的能力。解決問題的方法也很簡單:
**不要再寫爛程式了**
(這個世界需要的就是這麼簡單的幾個字)
「但是但是但是但是…我們沒有時間…公司要上市上櫃…我們的產品釋出時間…」
別再扯什麼理由,就是不要再寫爛程式!
好吧,你可能決定繼續寫爛程式,你可能覺得不值得改善程式品質,這都是你的決定。不過,如果是這樣,起碼你就不要再說你們是個敏捷開發團隊,也不要讓別人以為你們是敏捷開發團隊。敏捷軟體開發的基本原則之一就是「穩健的步伐」( Sustainable Pace),如果你盡寫些爛程式,開發速度最後就會愈來愈慢。這麼做不符合任何的商業邏輯,也根本稱不上敏捷。
但,如果你真的想停止寫爛程式,我們可以看到會發生什麼事。
作為軟體開發團隊,你們可以把「我們不要再寫爛程式」寫成匾額掛在牆上,然後握手同意以後都這麼做。然後在進度追蹤系統上,把「不再有更多技術負債」列入到「完成」的定義中。
告訴全世界,包括那些你覺得造成你在寫程式時製造壓力的人:「我們寫了不少爛程式,真抱歉,但我們不會這麼做了。」大聲講出來吧!感覺真好!
## 不要再寫爛程式
我們來看看以下兩條曲線:
的確,這張圖表過分簡化了,但是當中的差別確實存在。如果你繼續寫爛程式,你的開發速度會愈來愈慢(因為你需要花上更多時間與程式碼糾纏),如果你不再寫爛程式,你會有更穩定的開發步伐。但這是從長期來看-你的短期開發速度可能會變慢。
作為團隊,應該要決定一次要放多少工作-放入多少工作的原則是敏捷開發與精實創業的基礎。在敏捷方法中,已經建有了這一環,比方說,在每一輪 Scrum 衝刺計畫(Scrum Sprint Planning)中,成員就會決定要在這一輪衝刺中處理多少待辦事項,極限開發計畫遊戲(XP Planning Game)同樣如此。在看板方法中,團隊會有工作中事項的上限,只有在其中一項完成時,才能夠放入新的項目。基本上,團隊應該要用全副心力,專注在程式碼品質上。善用這些工具的力量吧!
用比較確切的詞彙來說,如果你使用 Scrum 方法,而你已經在每次衝刺中都交付了 8 到 10 項功能,試著減少功能的數量。在下次衝刺中,不管有多少壓力,都只放進六條使用者故事。在每次回顧衝刺的時候,問你自己「我們這輪衝刺的程式碼品質如何?」(1-5分),如果低於 4 到 5 分,下一輪衝刺就做更少的功能。繼續嘗試,直到找到屬於自己的穩定步調為止。
但當然這也會牽扯到商業實務。產品所有者(product owner,或是任何一位負責做商業優先決策的人)在安排事務優先順序時會更加困難。他過去可能習慣在每次 sprint 衝刺中看到有八到十項使用者故事完成,但現在可能只會有六到七項,他因此必須決定[哪些事情不要做](http://blog.crisp.se/2012/10/25/henrikkniberg/agile-product-ownership-in-a-nutshell)。
是的,因此你會引來抱怨以及艱困的討論。壓力的真正來源(如果真的有的話)會慢慢清楚浮現。程式品質的價值在短期內是看不見,而且需要被解釋的。但我們還是要勇敢迎戰!在你的決策上站穩,如果工程師不為自己程式碼的品質負責,誰來負責?
## 程式碼品質不等於產品品質
程式碼並非一切,產品開發除工程師之外,還需要很多人共同參與。包括商業分析人員、測試人員、經理人員、系統管理人員、設計人員、營運人員、人力資源人員、庶務人員…等等。
當中,*每個人*都要為產品品質負擔*集體責任*。產品品質不單只有程式碼、圖像設計、資料庫架構、靜態檔案而已,而是包括產品的*整體使用者經驗*以及*商業上的表現*。
程式碼品質只是產品品質的一個子集。就算你寫出優秀的程式碼,但如果你的產品並沒有解決正確的問題,最終還是不會有人願意掏腰包購買。
但反之-你有沒有可能寫出爛的程式碼,卻最終得到成功的產品呢?我很討厭承認,但,對,技術上你的確*可以*用爛程式做出好產品。有些團隊也的確用這種方式做出成績。不過,改進與維護這樣的產品速度緩慢、成本高昂、而且痛苦,因為這樣的產品內部已經腐爛了。這是的雙輸的局面,而且最優秀的開發者最終會選擇離開。
## 如何處理老垃圾(也就是 Legacy Code)?
好,如果你已經停止寫爛程式了,恭喜!你已經停止繼續增加技術負債。雖然你還是要負擔既有的債務,但你起碼已經阻止債務成長。
下一步我們要決定的是:你是否可以容許既有的債務,或你是否想做些事情解決?如果你決定逐步減少技術負債,你可能短期內會減緩開發速度,但長期卻是增進開發效率。如下圖:
這麼做可能值得,也可能不值。答案並不明顯,而由於這也會是商業決策,所以務必與付薪水的人討論。
如果你決定減少目前的技術負債,你就要清楚決定:「 **我們以後都不會寫爛程式,而且最終要把舊程式清乾淨** 」。
如果你們都同意(這是最困難的一點),我們有[很多方法可以嘗試](http://lmgtfy.com/?q=managing+technical+debt)。以下是我所看過兩種特別不錯的方法。
1. 在 Issue Tracker 上,把「減少了技術負債」列為「完成」的標準。也就是說,無論完成哪項功能,或是改動了某個部分的程式,你都把這段程式改得比改動之前來得好。或許是把 method 換成更清楚易懂的名稱,或是把重複的程式碼抽出來共用。這些都是小事,但是如果你的團隊(甚至,每一個團隊)都持之以恆這麼做,過了幾個月,程式品質就會有大幅改善。
2. 對於需要大範圍清理的程式,建立一份「技術待辦事項」(tech backlog),並保留時間完成當中所列出的事項。以方說,列出十塊需要大範圍清理的地方,然後在每週或是每次 Scrum 衝刺 *之前* ,處理其中一塊。
請注意,不管你怎麼做,償還技術負債就代表短時間之內能做的新功能變少,請視狀況調整原本的進度評估與產品釋出計畫。任何一種投資,都會有短期的成本。請確定每個人都有這項共識。
加速之前,你需要先慢下來。
## 結語
總結一句話:「程式碼的品質要由實際負責寫程式的人負責」(也就是 [軟體工程師](http://en.wikipedia.org/wiki/Programmer))。
因為你是軟體工程師,於是你手上會有這樣的問題,但你手上同樣擁有解答。你不用為過去造的孽焦躁或羞愧,反之,你應該驕傲地站出來,用你的力量做些事情-堅決確定你接下來要*不再寫爛程式*。這樣會引發連鎖反應,長期終會開花結果。雖然這麼做很難,也需要勇氣,但我不知道還有什麼別的方法可以解決技術負債。
祝好運!
/Henrik
## FAQ
### 技術負債 *一定* 都不好嗎?
並非如此,稍微有些負債也不見得有問題。我在這邊所談的,是慢性、失控、不停成長的技術負債。我看過很多公司都陷在技術負債中,移動緩慢,失去關鍵開發者,並且為當初並沒有把程式品質當一回事,日後卻要用更高的成本挽救而深深後悔。犧牲程式品質只能獲得短期利益,但長期並非如此,而大多數公司都希望可以長期存活。
### 到底什麼是技術負債?
任何與程式以及開發環境有關,而拖慢你發展的事情都是。例如
* 不清楚、難閱讀的程式碼
* 缺乏自動化測試、自動化編譯、自動化佈署、以及任何無法自動化,你必須手動操作的事情
* 重複的程式碼
* 疊床架屋的架構以及不必要的複雜相依性
* 緩慢、沒有效率的工具
* 沒有註解的程式以及活得太久的分支(這些會隱藏讓你日後速度變慢的種種問題)
* 缺少重要的技術文件,或是文件過時沒有更新
* 缺乏測試環境
* 太長的測試週期,以及缺少持續整合(continuous integration)系統
http://blog.crisp.se/2013/07/12/henrikkniberg/the-solution-to-technical-debt