回想一下有多少次在臨近發(fā)布的時(shí)候你是這樣的狀態(tài):
很多時(shí)候,迫于項(xiàng)目時(shí)間壓力堡掏,我們都會(huì)忍不住走捷徑。先上線吧刨疼,雖然現(xiàn)在的解決方案不是最優(yōu)的泉唁,好歹湊合能用,等有時(shí)間了再重構(gòu)揩慕;先上線吧亭畜,等有時(shí)間了再做自動(dòng)化測(cè)試,也許用戶發(fā)現(xiàn)不了這個(gè)bug迎卤。然后下一個(gè)迭代又有新任務(wù)來(lái)了拴鸵,周而復(fù)始。終于在幾個(gè)迭代以后蜗搔,欠的債越來(lái)越多劲藐,整個(gè)項(xiàng)目沒有人能完全知道這次的發(fā)布會(huì)有什么問(wèn)題,上線后都要拜關(guān)公了樟凄。
第一次發(fā)布代碼聘芜,就好比借了一筆錢。只要通過(guò)不斷重寫來(lái)償還債務(wù)缝龄,小額負(fù)債可以加速開發(fā)汰现。但久未償還債務(wù)會(huì)引發(fā)危險(xiǎn)挂谍。復(fù)用馬馬虎虎的代碼,類似于負(fù)債的利息瞎饲。整個(gè)部門有可能因?yàn)樗缮⒌膶?shí)現(xiàn)口叙,不完全的面向?qū)ο蟮脑O(shè)計(jì)或其他諸如此類的負(fù)債而陷入窘境。[wiki]
Ward Cunningham 不但是個(gè)天才程序員嗅战,也是一個(gè)語(yǔ)言天才妄田,使用了“技術(shù)債”這樣一個(gè)極富畫面感的詞。即使跟非技術(shù)人員交流也不需要過(guò)多解釋這個(gè)詞仗哨,大家都能領(lǐng)會(huì)大體的意思形庭。并且當(dāng)你向老板解釋這個(gè)迭代為什么會(huì)延期時(shí),說(shuō)一句“我們用了一周來(lái)還技術(shù)債”厌漂,比說(shuō)“我們之前的某某設(shè)計(jì)不是很好萨醒,我們花了一周的時(shí)間進(jìn)行了重構(gòu)”有效得多。
書中提到的技術(shù)債的來(lái)源有很多種苇倡,就筆者的實(shí)際項(xiàng)目經(jīng)驗(yàn)看富纸,主要是下面幾種:
1. 前任甩鍋。接手項(xiàng)目的時(shí)候已經(jīng)設(shè)計(jì)實(shí)現(xiàn)成這樣了旨椒,而且當(dāng)初的架構(gòu)師和程序員早就離開團(tuán)隊(duì)了晓褪。項(xiàng)目已上線,服務(wù)不能停综慎,必須在高速公路上換輪子涣仿。
? 我們花了很大力氣重構(gòu)原有系統(tǒng),但是諸如數(shù)據(jù)庫(kù)設(shè)計(jì)不合理等問(wèn)題卻是在當(dāng)前版本不敢輕易去修改的示惊。
2. 測(cè)試不到位好港,基本沒有單元測(cè)試或者測(cè)試用例寫得不夠靈活∶追#回歸測(cè)試沒有實(shí)現(xiàn)自動(dòng)化钧汹,全靠手工完成。驗(yàn)收的時(shí)候只測(cè)試新功能录择,以前功能的測(cè)試用例根本來(lái)不及做拔莱。我們這個(gè)迭代完成了x個(gè)功能(同時(shí)引入了多少個(gè)bu無(wú)人知曉,直到線上出問(wèn)題)隘竭。
? 這仍然是我們的深深痛塘秦!
3. 缺乏工程化的自動(dòng)構(gòu)建持續(xù)集成和自動(dòng)化部署的框架。項(xiàng)目構(gòu)建工具混亂货裹,ant嗤形,maven,gradle弧圆,grunt赋兵,gulp全用上了笔咽,可是關(guān)鍵組件和配置還是得靠手工拷貝。有時(shí)候還只能在開發(fā)者的電腦上構(gòu)建成功霹期,在持續(xù)集成服務(wù)器上構(gòu)建不出來(lái)叶组。部署更是恐怖的事情,好不容易打好包了历造,發(fā)現(xiàn)生產(chǎn)環(huán)境的配置文件還得改甩十。
? 現(xiàn)在這個(gè)債基本還完了,專門讓一個(gè)開發(fā)人員抽出時(shí)間來(lái)做了一個(gè)spike吭产,實(shí)現(xiàn)了一鍵部署侣监。(雖然還有兩個(gè)外包模塊沒搞定。那兩個(gè)模塊得徹底重構(gòu)才行臣淤,一筆巨債伴厦埂!)
4.微服務(wù)架構(gòu)的引入在解決功能模塊間強(qiáng)耦合的同時(shí)邑蒋,不可避免的削弱了項(xiàng)目間的依賴印象姓蜂。開發(fā)人員往往缺乏全局視角,只顧著自己的一畝三分地医吊,對(duì)于其維護(hù)的服務(wù)變更對(duì)系統(tǒng)其它服務(wù)造成的影響缺乏必要的警示钱慢。由于缺乏相應(yīng)的治理工具,以前在大型單體應(yīng)用中能夠在編譯期發(fā)現(xiàn)的問(wèn)題需要到運(yùn)行以后才能發(fā)現(xiàn)卿堂。如果有很好的自動(dòng)化測(cè)試覆蓋率還可以在持續(xù)集成的時(shí)候就發(fā)現(xiàn)問(wèn)題束莫,然而正如第二點(diǎn)所說(shuō)烘豌,并沒有在CI上跑自動(dòng)化測(cè)試拙已,從而未能阻止問(wèn)題代碼上線互拾。
原書里面說(shuō)到有一個(gè)普遍誤區(qū):認(rèn)為減少測(cè)試可以加快速度缕陕。雖然我們都知道減少測(cè)試會(huì)增加技術(shù)債,但大家普遍是將這個(gè)債務(wù)先背著爭(zhēng)取更快上線挂捻。然而作者告訴我們減少測(cè)試不但增加債務(wù),還會(huì)減緩速度。表面上看似乎很難理解揍诽,你看我不做測(cè)試省了好多時(shí)間。其實(shí)我們也是經(jīng)常這樣想的栗竖,所以測(cè)試往往就被犧牲了暑脆。我不知道有沒有團(tuán)隊(duì)將測(cè)試做好以后再來(lái)評(píng)估自己的速度,總之我想接下來(lái)要全面推動(dòng)TDD和自動(dòng)化測(cè)試狐肢,到時(shí)候再分享經(jīng)驗(yàn)添吗。
書中關(guān)于技術(shù)債管理的原則和償還技術(shù)債的策略確實(shí)很值得學(xué)習(xí)。與財(cái)務(wù)債相同的是份名,技術(shù)債不都是壞事碟联。例如舉債買房也是一個(gè)負(fù)責(zé)任的行為妓美。對(duì)于一個(gè)公司來(lái)說(shuō),合理的安全債務(wù)水平恰恰能反應(yīng)他的財(cái)務(wù)能力鲤孵。技術(shù)債也一樣壶栋,我們需要保障寫出clean的代碼,但是不能過(guò)于潔癖普监。
與財(cái)務(wù)債不同的是贵试,有些技術(shù)債真的不需要還。例如一些你認(rèn)為很SB然而不得不做的需求(我通常叫他們偽需求)凯正,不要想那么完美毙玻,怎么簡(jiǎn)單粗暴怎么實(shí)現(xiàn),反正就是演示一下廊散,永遠(yuǎn)也不會(huì)真的被用到桑滩。如果真的被使用了呢?那就再重構(gòu)唄奸汇。
還有一類不需要償還的技術(shù)債就是一次性使用的腳本施符、工具。例如數(shù)據(jù)遷移腳本擂找,通常而言只會(huì)被使用一次戳吝,能完成任務(wù)就行了,沒必要那么完美贯涎,效率能接受即可听哭。
當(dāng)然大部分的技術(shù)債都是要還的,正如題圖所示塘雳,只是遲早問(wèn)題陆盘。我們?cè)撛趺粗贫▋斶€策略?作者給出的指導(dǎo)原則跟財(cái)務(wù)債也有類似的地方败明。例如我們應(yīng)該先還利息高的負(fù)債隘马。什么是利息高的技術(shù)債呢?我相信憑團(tuán)隊(duì)的直覺都能判斷出來(lái)妻顶,抱怨越多的絕對(duì)是利息高的負(fù)債酸员,越快解決越好。分期付款原則也很重要讳嘱,在每個(gè)迭代里面加入一些還債的任務(wù)幔嗦,不知不覺就把債還了。盡量避免出現(xiàn)一個(gè)單純還債的沖刺沥潭,可以讓某個(gè)團(tuán)隊(duì)成員在這個(gè)沖刺中還債而不應(yīng)該使整個(gè)團(tuán)隊(duì)都陷入債務(wù)中邀泉。(嗯,看到這里我打消了封閉還債的計(jì)劃)。