技術債務與程式設計師的信用
當我們在埋怨上一個程式設計師留下的系統時,是在埋怨什麼?是債務,技術債務。我在曾經的文章裡寫過,程式碼既是資產也是債務,資產的部分屬於公司,債務的部分屬於我們。
債務
技術債務來自於對金融債務的比喻,它指的是在程式設計與開發過程中,做出的錯誤或不理想的技術決策,由此帶來的後果,逐步累積,就像債務一樣。
技術債務的產生,可能是有意的,也可能是無意的。有意產生的債務,一般是根據實際專案情況(資源與期限)做出的妥協。而無意產生的債務,一般就都是經驗缺乏引入的。不管怎麼說,只要程式設計師在不斷的生產程式碼,他們就是在同時創造資產與債務。
那如何知道技術債務已經積累到了需要去警示並著手計劃進行還債的階段了?一般來說,我們直覺都是知道的。舉個例子,好幾年前我們接手繼續開發並維護一個系統,系統的業務開始發展很快,不停的新增功能, 每週都要上好幾次線。一年後,還是每週都要上好幾次線,但每次上線的時間越來越長,迴歸測試的工作量越來越大。再後來,系統迎來了更多的新業務,我們不得不復制了整個系統的程式碼去修改再重新部署,以免影響現有線上系統的正常執行...
到了這樣的狀況,每個人都知道,債務在報警了,債主找上門了。一次重大的還債行動計劃開始了,還債的名聲不太好聽,所以我們喜歡叫:架構升級。架構升級除了還債,還是為未來鋪路 —— 當然,前提是要有未來,如果未來還能迎來更大的業務爆發增長,架構升級就是為了在那時能消化更多的長短期債務。
之前看過一篇寫技術債務的文章,也是一個老碼農寫的,名字就叫《老碼農看技術債務》,文中把技術債務分成了好幾類,大概記得如下:
戰略債務
戰術債務
疏忽債務
戰略債務,老碼農說是為了戰略利益故意為之,並長期存在。我理解就是在公司或業務高速發展的階段,主動放棄了一些技術上的完備與完美性,而保持快速的迭代與試錯性。這個階段公司的戰略利益是業務的搶佔,所以這個階段的公司都有一些類似的口號,比如:先完成,再完美;優雅的介面,狗屎的實現。戰略債務的特點是,負債時間長,但利息不算高且穩定,只要保持長期“付息”,不還本金也能維持下去。
戰術債務,一般是為了應對短期緊急情況採取的折衷方法。這種債務的特點就是高息,說高利貸也不為過。舉個例子,曾經做電信專案時,系統處理工單,主流程上有缺陷,對某一類工單處理會卡住。這時又不太方便停機更新程式,就基於系統的動態指令碼能力去寫了個指令碼臨時處理這類工單,可以應對當時業務經營的連續性,缺陷是資源開銷大,當超過一定量時 CPU 也就滿了。這樣的技術方案就屬於戰術債務的應用,當天半夜的業務低谷,就重新修復了程式,歸還了這筆短期臨時債務。
疏忽債務,這類債務一般都是無意識的。從某種意義上來說,這就是程式設計師的成長性債務,隨著知識、技能與經驗的積累,這類債務會逐步減少。
對於不同的角色,關注的債務分類與形態也不太一樣,比如架構師關注的更多是戰略債務,保持系統能夠健康長期演進的債務平衡。作為架構師,就像 CFO,需要長期持續的關注系統的資產負債表。戰略債務可能更多體現為架構、設計與互動方面的形態。而具體某個功能實現層面的程式碼債務,則更多落在相關開發工程師的關注範圍內。測試工程師,會關注質量方面的債務,而一到交接時,各種文件債務就冒出來了。
分析了這麼多關於技術債務的方方面面,那麼程式設計師該如何面對技術債務,該怎麼還債?
信用
擁有債務,並不代表信用差。而一個程式設計師的信用體現在面對技術債務的態度與方法。
現實生活中,債務依附於借債的主體方,比如金融債務依附於個體或組織,但如果個體死亡或組織破產了,債務就失去了依附體(此類情況不考慮擔保,擔保是一種依附的轉移),自然也就消失了。
而技術債務的依附體,並不是程式設計師,而是依附於程式構造的產品或系統,所以當產品或系統的生命週期結束,相應的技術債務也會消失。因而,此種情況下,程式設計師是有充足的理由不還技術債的,這是技術決策的一種,並不會降低程式設計師的信用。
任何一個程式系統或其一部分都會與某一個程式設計師建立關聯,這個程式設計師此時就負責這部分系統。那麼程式設計師在此基礎上繼續創造程式碼時,既增加了資產也可能引入了新的債務,那麼他的一個重要職責就是,維持好資產與債務的平衡關係,如果在此期間,系統的債務失衡導致“破產”(需要被迫大規模重構或重寫),那麼這個程式設計師的信用必將受到關聯傷害。
所以,我們才需要謹慎且持續的關注與管理程式系統的技術債務問題。
對於戰略債務,長期來說都是持續付利。就像現實中一些大企業從銀行借錢經營發展,每年按期付息,但基本不還本金。支援公司快速發展到了一定階段,基本進入成熟期後(市場大局已定),再主動降低負債風險和經營成本。創業公司從小到大的發展過程中,技術上的戰略債務與之類似。
而疏忽債務,作為有信用的程式設計師,需要堅持成長性歸還策略。一旦發現過去的自己寫下了愚蠢的程式碼,就需要主動積極的確認並計劃歸還。
如上,我們首先要認識理解技術債務,還要有效識別技術債務,最後就是合理的還債計劃了。
還債
在產品突進,四處攻城略地時,還需要配合週期性的還債,保持債務平衡,才能保證整體健康的快速發展。
還債時,我們主要考慮債務的大小和還債的時機,在不同的時間還債也許研發成本相差不大,但機會成本相差很大。而按不同債務按大小,又可以分為大債務和小債務。一般,我把需要以周為單位計算的債務算作大債務,而只需一個程式設計師幾天時間歸還的債務算作小債務,所以這不是一個精確的定義。
小債務的歸還,基本都屬於日常的重構活動,侷限在區域性區域(模組、子服務)的實現層面。而大債務 —— 架構升級還的一般都是大債務 ——的歸還,需要仔細的考慮和分析機會成本與潛在收益,所以大債務歸還要分三步走:
規劃:代表願景,分析哪些債務需要在什麼時間還,機會成本的損失與預期收益
計劃:代表路徑,細緻的債務分期償還計劃
跟蹤:真正上路了,確認債務的償還質量與到位情況
如今微服務架構的流行,基本把小債務鎖定在了一個或幾個微服務體內。即使碰上沒有信用的程式設計師把自己負責的微服務搞爛了,形成債務破產,這時的還債方式無非就是完全重寫一個,在微服務拆分合理的情況下,一個服務的重寫成本是完全可預期和可控的。
做一個有信用的程式設計師的關鍵是:知道何時引入債務解決緊急情況,之後立刻還債;無意識引入的負債,當時看不見,也許多年後你成長了,看見了,但別假裝看不到啊。
...
再有程式碼潔癖的人也沒法寫出無債務的程式碼,寫出無債務的程式碼可能是一種極限,我們一直在追求與接近,卻很難達到。而無債務的系統也不存在,其實負債高的系統往往活力還比較強。就像人一樣,年輕時可以適當戰略負債,等老了,債也還得差不多了,負債的意義也不大了。
此刻瞬間
把債務當作一門工具,而不是一種負擔,那麼就又獲得了新的技能,成長了。
寫點文字,畫點畫兒。瞬息之間,一切都變了。
139 · 心事像羽毛,越飄越逍遙