“軟件和大教堂是類似的,都是先構(gòu)建,然后祈禱”?!狤arl Everett
關(guān)于技術(shù)債務(wù)的討論時而蔓延時而消退,技術(shù)債務(wù)仿佛是個筐,什么東西都可以往里裝,然而當(dāng)我們企圖倒光筐里東西的時候,卻發(fā)現(xiàn)每人看到的東西都不一樣,甚至有時候都數(shù)不清里面都有些什么。 作為一個半吊子全棧工匠,試圖從一個老碼農(nóng)的視角審視一下技術(shù)債務(wù)。
一個比喻導(dǎo)致的分歧
技術(shù)債務(wù)是由敏捷先驅(qū) Ward Cunningham(https://en.wikipedia.org/wiki/Ward_Cunningham)
在1992年的一個報告中的一個比喻,大意是做了錯誤的或不理想的技術(shù)決策所導(dǎo)致的債務(wù)。由于是個比喻,所以產(chǎn)生了每個人眼中的哈姆雷特。
首先,Steve McConnell將技術(shù)債務(wù)分為兩類:無意的和有意的。
1)無意產(chǎn)生的技術(shù)債務(wù):由于缺乏經(jīng)驗而編寫了低質(zhì)量的代碼。
2)有意產(chǎn)生的技術(shù)債務(wù):根據(jù)當(dāng)前情況進(jìn)行設(shè)計選型,可能很快就能解決當(dāng)前的問題,有時會變得拙劣。
作為《重構(gòu)》一書的作者,Martin Fowler認(rèn)為技術(shù)債務(wù)產(chǎn)生的利息是指由于魯莽的設(shè)計決策導(dǎo)致需要在未來的研發(fā)中付出更多。面對技術(shù)債務(wù),可以持續(xù)付利,也可以通過重構(gòu)一次付清。代碼中的壞味道也是技術(shù)債務(wù),是一種不計后果的債務(wù),會讓問題變得更加嚴(yán)重,進(jìn)而將技術(shù)債務(wù)劃分為4個象限:

Bob大叔則認(rèn)為壞味道并非技術(shù)債務(wù)。技術(shù)債務(wù)的評價標(biāo)準(zhǔn)是真實的項目約束,這些約束是風(fēng)險和好處并存的。壞味道是由懶惰和外行導(dǎo)致的,總是意味著損失。技術(shù)債務(wù)要求牢記保持代碼的整潔,就好像一個人在背負(fù)巨大的抵押債務(wù)時需要時刻保持警醒一樣。
關(guān)于技術(shù)債務(wù)的更多定義討論參見http://wiki.c2.com/?TechnicalDebt。
技術(shù)債務(wù)的現(xiàn)象與類型
將一個比喻作為定義是不嚴(yán)謹(jǐn)?shù)?,而且很多人對定義的重要性并不是很關(guān)注。于是,可以從現(xiàn)象和構(gòu)成的角度來看待技術(shù)債務(wù)。
如何認(rèn)識無意產(chǎn)生的技術(shù)債務(wù)呢?當(dāng)出現(xiàn)如下現(xiàn)象的時候,說明技術(shù)債務(wù)開始累積:
1)類似的代碼在不同的項目/產(chǎn)品間遷移
2)代碼已經(jīng)穩(wěn)定但回歸測試的陳本在增加
3)每一次交付的成本逐漸增加
4)類似feature 開發(fā)的周期開始變長
5)在既有代碼上開發(fā),還不如推到了重來
技術(shù)債務(wù)的類型是由產(chǎn)生的原因和方式來定義的,其中一種分類如下:
- 戰(zhàn)略債務(wù):為了戰(zhàn)略利益(例如首次上市)故意為之,并長期存在。
- 戰(zhàn)術(shù)債務(wù):在知情的情況下為了快速收益而產(chǎn)生,適用于短期。
- 疏忽債務(wù):在不知情的情況由于缺乏知識和意識而產(chǎn)生。
- 增量債務(wù):定期不慎產(chǎn)生的而導(dǎo)致增量債務(wù)。
技術(shù)債務(wù)包括那些現(xiàn)在選擇不做的內(nèi)部事務(wù),但會影響未來的開發(fā)工作,例如延遲重構(gòu)。不包括推遲的功能實現(xiàn),除非交付功能對客戶來說“足夠好”的情況下,但不滿足某些標(biāo)準(zhǔn)(例如,UI元素不完全符合某些UI標(biāo)準(zhǔn))。
技術(shù)債務(wù)的組成
技術(shù)債務(wù)是多方面的,涉及技術(shù)的多個維度,這也是每人眼中都有著自己的哈姆雷特的一個重要原因。
現(xiàn)羅列自己經(jīng)歷或者看到過的一些方面:
- 代碼債務(wù):代碼重復(fù)、違反靜態(tài)分析工具和代碼異味等。
- 設(shè)計債務(wù):設(shè)計異味、違反設(shè)計規(guī)則等
- 架構(gòu)債務(wù):違反架構(gòu)規(guī)則,對非功能性約束認(rèn)知不足等。
- 測試債務(wù):缺乏測試、測試覆蓋面不足和不正確的測試設(shè)計等。
- 質(zhì)量債務(wù):缺乏穩(wěn)定性和健壯性的技術(shù)驗證,QA的自動化不足等
- 配置債務(wù):版本控制的模糊,環(huán)境參數(shù)的混淆等
- 平臺債務(wù):平臺經(jīng)驗的匱乏,云服務(wù)融合與應(yīng)用不足等
- 文檔債務(wù):存在重大問題的文檔、缺乏文檔和文檔過期等。
針對每一類技術(shù)債務(wù),都有著相應(yīng)的原則和處理方法,有時間再仔細(xì)展開。
技術(shù)債務(wù)的度量之痛
No measurement,No management。令人遺憾的是,很難有相關(guān)工具或者框架來提供量化數(shù)據(jù)對其進(jìn)行準(zhǔn)確而完整的分析。
技術(shù)債務(wù)并沒有一個普遍接受的范圍定義,甚至認(rèn)為已知的bug也構(gòu)成了技術(shù)債務(wù)。當(dāng)前可用的技術(shù)債務(wù)量化工具僅僅關(guān)注幾個維度,比如代碼債務(wù)和一定程度的設(shè)計債務(wù)和測試債務(wù)。對于同其它維度相關(guān)的問題,比如架構(gòu)債務(wù)或文檔債務(wù),這類工具并沒有提供全面的檢測支持。實際上,已支持的維度的全面性也是有問題的。
一般,技術(shù)債務(wù)的量化工具通常會轉(zhuǎn)換成償還這些債務(wù)所需的工作量,而工作量會隨問題的嚴(yán)重性、范圍、平臺、技能等的變化而不同。這樣所產(chǎn)生的估計值與實際情況大不相符,最多只是一種近似,而不是準(zhǔn)確的結(jié)論。
任何類型的債務(wù)都會包含本金和利息,而當(dāng)前的一些所謂的量化工具都關(guān)注與技術(shù)債務(wù)相關(guān)的本金,而忽視了利息部分,從而并不可信。利息部分關(guān)系到了理解的難度等因素,越發(fā)難以準(zhǔn)確地量化。
技術(shù)債務(wù)很好地充當(dāng)了溝通拙劣設(shè)計結(jié)果和持續(xù)重構(gòu)需求的隱喻。但試圖測量和量化技術(shù)債務(wù)時,變得同準(zhǔn)確測量軟件生產(chǎn)力或者量化軟件質(zhì)量一樣困難!
技術(shù)債務(wù)的現(xiàn)金衡量
當(dāng)然,技術(shù)債務(wù)的貨幣化有助于了解技術(shù)債務(wù)的嚴(yán)重程度,提供了一種跟蹤技術(shù)債務(wù)償還進(jìn)度的方法。不過,需要謹(jǐn)慎對待這些成本和工作量估計。
一旦有了與技術(shù)債務(wù)直接相關(guān)的金錢數(shù)目,關(guān)于軟件的多種復(fù)雜而麻煩的問題就可能得到答案。Israel Gat提出:除非對于技術(shù)債務(wù)有一個量化的賬單,否則團(tuán)隊都會忽略其重要性。他提到了以金錢方式計算技術(shù)債務(wù)的需要,以金錢方式計算技術(shù)債務(wù)有如下好處:
- 能夠告訴團(tuán)隊何時停止開發(fā),開始重構(gòu)。團(tuán)隊進(jìn)入重構(gòu)過程,除非債務(wù)得以償還,否則不加入任何功能。
- 客戶對于軟件的風(fēng)險得以了解。
- VC們可以以此判斷向某項軟件產(chǎn)品中投入資金是否理智。
- 有助于判斷軟件的支付能力,判斷在重構(gòu)和重寫這二者之間做出選擇
有哪些有效的方式可以用來將技術(shù)債務(wù)以金錢衡量呢?
Sonar中的技術(shù)債務(wù)插件是一種方式。在Sonar的站點上,已經(jīng)有了對于項目的技術(shù)債務(wù)分析。要計算成本,首先要使用下面的方式找出債務(wù):
債務(wù)(人/天)=修復(fù)重復(fù)部分的成本
+修復(fù)違規(guī)的成本
+為公共API做注釋的成本
+修復(fù)未發(fā)現(xiàn)的復(fù)雜性的成本
+帶入低于閾值復(fù)雜性的成本
+在包的層面上切斷生命周期的成本
對于每個小時的成本有個默認(rèn)值,例如人工200塊每小時。與之類似,就可以做出各種情況的現(xiàn)金分析,并可以計算出技術(shù)債務(wù)的總和。
因此,以金錢方式計算技術(shù)債務(wù)能夠深入理解與軟件相關(guān)的潛在成本。對于所有希望監(jiān)控技術(shù)債務(wù)成本并將其保持在一定限額內(nèi)的敏捷團(tuán)隊來說,這很關(guān)鍵。
直面技術(shù)債務(wù)
面對已知的技術(shù)債務(wù),普遍的經(jīng)驗是防止技術(shù)債務(wù)的積聚,以及有計劃地償還技術(shù)債務(wù)。
防止技術(shù)債務(wù)產(chǎn)生的主要方法是了解開發(fā)團(tuán)隊存在的技術(shù)債務(wù)。開發(fā)團(tuán)隊必須了解技術(shù)債務(wù),它的各種方面和類型,以及債務(wù)對他們的項目的影響。他們必須具備完善的設(shè)施與代碼質(zhì)量的概念,干凈的編碼習(xí)慣、設(shè)計嗅覺、以及如何重構(gòu)它們。合適的流程可以幫助開發(fā)團(tuán)隊避免技術(shù)債務(wù)積累,例如代碼、設(shè)計、架構(gòu)和測試的審查等。然而,這些流程必須是務(wù)實的,否則事與愿違。
對于償還技術(shù)債務(wù)而言,首先同樣是識別并記錄現(xiàn)有債務(wù),優(yōu)先處理異味,在每個迭代中分期償還債務(wù)。如果一個研發(fā)團(tuán)隊的以團(tuán)隊交付功能的數(shù)量或修復(fù)bug的數(shù)量為考核標(biāo)準(zhǔn),那么團(tuán)隊將只專注于增加功能和修復(fù)bug。但實際上,做好它和完成它同樣重要。同時,留意可能出現(xiàn)的大規(guī)模債務(wù)償還,屬于不同維度的債務(wù)實例相互影響。在某些情況下,即使債務(wù)很高,也不值得償還技術(shù)債務(wù)。這些情況包括原型、概念實現(xiàn)和即將廢棄的產(chǎn)品所產(chǎn)生的技術(shù)債務(wù)。此外,如果計劃為一個傳統(tǒng)項目遷移到一個新的技術(shù)、平臺或架構(gòu),不償還的技術(shù)債務(wù)是明智的,因為相關(guān)的債務(wù)可以在遷移過程中解決的。
管理他人的技術(shù)債務(wù)
由于不提倡重復(fù)造輪子,我們所使用的第三方軟件和開源軟件產(chǎn)生的技術(shù)債務(wù)同樣會對我們造成影響。它們的Bug會成為我們的Bug,安全漏洞也會成為我們的安全漏洞,錯誤決定會成為了我們的錯誤決定。
我們所使用其他軟件的代碼量可能會非常大,由此產(chǎn)生的技術(shù)債務(wù)也可能大,甚至超過自己所編寫的代碼量。根據(jù)Sonatype的一項調(diào)查顯示,80%的Java應(yīng)用都是由開源組件與框架裝配起來的,一個大型系統(tǒng)甚至?xí)褂?0多個不同的庫或組件。
要想了解這種債務(wù)問題的嚴(yán)重性,需要審查代碼中使用了哪些第三方開源包與依賴。一旦清楚了其他人的軟件可能會造成的影響,就需要評估由此所帶來的風(fēng)險和問題了,并需要緊密追蹤這些軟件的補(bǔ)丁、升級信息及Bug報告等,這確實不太容易。
知道問題的嚴(yán)重性是一方面,修復(fù)問題則是另一方面。對最新的發(fā)布打補(bǔ)丁并非易事。最好能在外圍打補(bǔ)丁,因為補(bǔ)丁并非總是適合于我們所使用軟件的方式:Apache、Tomcat、Web Service庫、客戶端組件等。我們需要更加謹(jǐn)慎地管理這些后端代碼。如果每當(dāng)出現(xiàn)一個Linux補(bǔ)丁時需要立刻打上,那就說明架構(gòu)可能有些問題。
升級更是一個大問題了,升級到最新的OS、RDBMS、VM等都涉及到很高的代價與風(fēng)險。雖然可以通過升級的方式獲得在可伸縮性、管理性及新特性等方面的一些優(yōu)勢,不過升級項目還需要更加關(guān)注一些潛在的問題:功能回歸、兼容性問題、操作流程的變化、對其他系統(tǒng)的依賴變化等等。升級之后,大多數(shù)軟件會變得更大而不是更好,也許會加入很多新特性,不過可能壓根就用不上這些特性,這也意味著需要花更多的時間進(jìn)行安裝、配置和測試。我們需要搞清楚變化的地方,重新進(jìn)行測試和調(diào)優(yōu)。
技術(shù)債務(wù)的價值
把技術(shù)債務(wù)和金融債務(wù)來類比,貸款就會產(chǎn)生債務(wù),如果定期還款,那么債務(wù)是可接受的,不會產(chǎn)生進(jìn)一步的問題。但是,如果他不還款,就會以利息作為懲罰,并隨著不還款次數(shù)的增加而增加。如果很長一段時間不能支付任何款項,那么應(yīng)計利息使得債務(wù)更難以償還。
同樣地,當(dāng)我們采用一個非最優(yōu)或次優(yōu)技術(shù)決定,就引入了技術(shù)債務(wù)。在很長一段時間未償還累計的技術(shù)債務(wù)的情況下,軟件越來越難以改變,在極端情況下,軟件產(chǎn)品變得在技術(shù)上已經(jīng)破產(chǎn),往往會導(dǎo)致項目終止。利息有復(fù)合的性質(zhì):開發(fā)團(tuán)隊越是忽略或推遲它,隨著時間的推移,債務(wù)變得越大。因此,是利息使得技術(shù)債務(wù)成為一個顯著問題。
我們談及技術(shù)債務(wù)的時候往往都清楚它的種種弊端,卻缺乏主動使用技術(shù)債務(wù)的勇氣。 債務(wù)具有著現(xiàn)金價值,在金融領(lǐng)域中,貨幣杠桿的作用顯著。 對企業(yè)而言,現(xiàn)金流更是關(guān)鍵因素, 所以,沒有必要談債色變,沒有債的企業(yè)未必都是一流的好企業(yè)。
合理使用技術(shù)債務(wù),在這個快節(jié)奏的時代,我們有責(zé)任迅速為客戶提供價值。在這種追求中,有各種情況團(tuán)隊必須選擇快速或者骯臟的解決方案。需要注意的是,在這種情況下,需要我們以勤奮和務(wù)實的態(tài)度處理技術(shù)債務(wù)。