淺談活動中臺系統技術債管理實踐
在項目研發過程中,由于時間、能力等因素往往會出現設計方案沒有做到最好或最優、編碼質量不夠好等問題,技術債的出現是不可避免的,并且隨著時間的推移,技術債對系統的影響會越來越大,同時使得對代碼和架構設計的更改越來越困難,想要進一步提升效能必須要對技術債進行管理,本文通過在活動中臺系統的技術債實踐經驗,介紹技術債的含義、分類和管理。
一、技術債的含義
1.1 技術債的含義
關于技術債的概念可以追溯到1992年,沃德·坎寧安(Ward Cunningham)首次提出,第一次發布代碼,就好比借了一筆錢。只要通過不斷重寫來償還債務,小額負債可以加速開發。但久未償還債務會引發危險。復用馬馬虎虎的代碼,類似于負債的利息。整個部門有可能因為松散的實現,不完全的面向對象的設計或其他諸如此類的負債而陷入窘境[1]。
《維基百科》中提出,技術負債(Technical debt),又稱技術債,也稱為設計負債(design debt)、代碼負債(code debt),是程序設計及軟件工程中的一個比喻。指開發人員為了加速軟件開發,在應該采用最佳方案時進行了妥協,改用了短期內能加速軟件開發的方案,從而在未來給自己帶來的額外開發負擔。這種技術上的選擇,就像一筆債務一樣,雖然眼前看起來可以得到好處,但必須在未來償還。軟件工程師必須付出額外的時間和精力持續修復之前的妥協所造成的問題及副作用[3]。
如下圖所示,技術債在研發人員的日常工作付出中占據了一定的比例。
1.2 技術債的危害
我們可以從效率、質量、體驗三個方面來看:
1.2.1 效率
這是最直接的影響,當技術債不斷增加,軟件系統會變得非常脆弱。這種脆弱主要是由不良的架構設計或代碼設計導致,不管最初是選擇了劃分良好的微服務架構,還是單體架構,技術債不斷打破設計原則,讓原則不復存在,以至于很難理清系統組件之間的關系和職責。當修改其中的一部分組件時,其他組件也會牽連,可能會陷入惡性循環。
1.2.2 質量
以上圖為例,從研發持續交付角度來分析的話,在項目版本迭代前期,業務功能較少的情況下,高質量要求的項目可能會比低質量要求的項目迭代速度慢一點,但是隨著項目逐漸發展,高質量要求的項目對比低質量要求的項目迭代速度顯著提升,技術債的持續累積是導致質量下降的關鍵原因,技術債是無法避免的,因此技術債的有效管理和消除是我們保障高質量軟件的必不可少的方式之一。
1.2.3 體驗
軟件產品需要不斷演進才能在長時間后依然還能適應市場,才能具有較強的生命力。相反,有的軟件在經過幾年的開發之后,隨著技術債的增加,已經變的很難維護,很多時候只能被推倒重寫,主要是不斷疊加的技術債導致。技術債的疊加不斷增加系統的復雜性,從而開發的成本逐漸增高,每次迭代都需要解決設計不足或技術所帶來的問題。
二、技術債是怎么產生的?
技術債的出現是不可避免的,但是不同的場景下會產生不同的技術債,帶來的影響也是不一樣的,如果按照健康角度分類的話,對于研發人員允許出現的技術債可以劃分為健康的一類,對于研發人員盡量避免的技術債則劃分為不健康的一類。我們可以從以下四個維度進行分析。
2.1 沖動/有意 - “沒有做更好的設計”
研發團隊雖然識別到這樣做會導致技術債的積累,但是不清楚帶來的后果,沒有去做更好的設計方案。比如項目在線上運行時,突然出現了一個線上問題,如果不盡快修復上線,就會造成很大的損失,這種情況下,已經無法再針對問題作詳盡的設計方案,現在需要以最快的方式修復上線,這種情況下往往不會考慮更好的設計方案,而是以最快捷的方式解決問題。對于當下的臨時方案在未來會帶來什么技術債,研發人員并沒有關注。
2.2 謹慎/有意 - “必須盡快交付”
當研發團隊面臨業務壓力時,例如在發布新產品時需要快速上線以占領市場時,快速解決問題的重要性常常超越了更好的實踐。在這種情況下,團隊往往會選擇快速完成產品交付,然后再處理技術債務。團隊清楚這樣做會帶來技術債務,也知道逾期還債的具體后果,以至已經安排好了未來的改進計劃。這種場景很常見,是已知技術債的一種主要來源。
2.3 沖動/無意 - “不知道怎樣設計更好”
這個維度技術債務產生的原因通常是由于人員技能的不足。在實際研發中,不可能保證所有人的水平都是一樣的,由于缺乏相關技能,研發人員可能不清楚如何編寫更優秀和精煉的代碼,不知道如何設計更好的架構或者給出更佳的解決方案,這種情況下,研發人員按照自己的理解和設計方案進行工作,可能會帶來一部分技術債。不管怎樣的團隊,人員的更替都是避免不了的,可能對項目不夠熟悉,對某一塊功能不夠熟悉,短時間內快速理解并給出設計方案,可能會有很大難度,個人的經驗不同,認知不同,在實現相同的功能時選擇的方案也是不同的。
2.4 謹慎/無意 - “現在有更好的方案”
隨著團隊成員的能力提升或者行業技術上的演進,對于之前認為的最佳方案現在看來并不是最好的解決方案。但在當時,可能并不知道有更好的做法。這種技術債確實也是無法避免的,甚至會經常遇到,最簡單的是基于當下的經驗甚至業界最優的一些實踐選擇技術方案或者技術框架。可能在之前做這塊功能的時候,團隊成員已經對當時的方案達成了一致,認為是最優的方案,但是現在突然發現有更優的方案,那么為了項目的長遠發展、穩定迭代,同樣需要對項目作最優方案的替換。
以上將技術債務分為四類。我們通常認為,健康的技術債是右邊的兩個維度,不健康的技術債是左邊的兩個維度。基于此我們可以分析技術債產生的原因并制定相應的改進措施。
- 對于沖動/有意類型的技術債,我們可以在日常的研發過程中擬制嚴格的規范,加強流程化的研發管理,讓我們的研發人員對最優設計達成習慣和規范;
- 對于謹慎/有意類型的技術債,我們可以和產品達成一致,每次面臨這種緊急需求,或者需要快速上線而沒有采取最優方案的情況,可以直接記錄,后續盡快優化;
- 對于沖動/無意類型的技術債,我們可以對所有的項目成員進行能力和認知的提升,盡可能讓研發人員在熟悉功能和項目的情況下進行研發,另外可以增加設計方案評審流程和代碼提交評審流程,有效減少這種類型的技術債;
- 對于謹慎/無意類型的技術債,我們需要在識別到的時候第一時間記錄下技術債,并且根據研發排期合理的安排時間進行修復。
為了保證產品持續的競爭力,上面幾點只是方法,如果沒有成本上的投入,只能淪為空談。從整個產品團隊,都要提升對技術的正確理解,技術的構建并不是一勞永逸的,是需要不斷的成本投入來維護的。
三、技術債管理實踐
3.1 一個技術債真實案例
下面以一個項目中遇到的真實技術債案例來介紹,活動中臺系統是一個面向用戶的中臺項目,可能每天都會產生大量的活動數據,即使進行了大量的分表處理,但是動輒千萬級的數據仍然給數據庫操作帶來了一定的負擔,所以我們目前沉淀了一套通用的數據庫數據清理方案,根據不同類型的表配置不同的清理策略,基本參考維度是數據的產生時間和活動狀態,如果一個已經結束的活動且數據產生時間大于半年則直接刪除。這種方案雖然通用,但是在線上發現了嚴重的慢SQL問題,即使是通過離線庫操作,仍然會讓系統存在一定的風險,顯然這個問題需要關注。
3.2 原來的做法
在原本的做法中,研發團隊對于項目產生的技術債采取的方案是隨機修復,也就是發現后會簡單的記錄下,如果是緊急問題則會同步項目組盡快上線,如果是非緊急問題,則會在下次版本迭代涉及該模塊時進行修復,或者在版本gap期間隨機進行修復,缺乏系統性的管理,往往可能會導致問題的遺漏,并且對于技術債的修復缺乏系統的分析和判斷,雖然在有意識的修復技術債,但是效益容易被忽略,往往看不到真正的價值。
對于這個數據清理帶來的慢SQL問題,雖然會產生慢SQL,但是對線上業務影響較小,所以優先級不高,暫時擱置,待到項版本有空閑人力再去優化,這個問題由于是技術側單純的技術優化,所以沒有納入需求列表,單純的依賴開發人員人工記憶,等到人力空閑時再想是否有問題需要優化,這個時候才想到塵封已久的問題。方案的變動需要測試的介入來回歸功能,這個時候開發人員想要優化,可能測試人力緊張,沒能及時開發和測試,功能的上線又會擱置。
3.3 新的做法
按照現有方案,我們已經形成了一套穩定的技術債機制,相應的按照以下步驟進行處理:
3.3.1 識別技術債
想要管理技術債,首先就是要識別技術債,技術的持續改進離不開團隊中每個人的努力,因此需要每個成員都積極參與。通常我們在識別技術債的時候可以從以下幾個類別去篩查。
當我們發現這個數據清理問題時,可以直接記錄在技術債跟蹤列表中,記錄技術債的所屬項目、問題描述、創建人、處理人、創建時間、修復時間、技術債狀態、規劃版本、備注等屬性,便于技術債的跟蹤和審視。這種跟蹤表只是一種方式,我們還有各種看板、空間可以用來記錄,項目內達成一致即可。
3.3.2 分析技術債
記錄技術債之后,時常會遇到的問題是,需要改進的地方太多,尤其是對于遺留系統。怎么辦?分析優先級。我們可以基于價值/成本矩陣來評估改進任務的價值和成本。基于下圖的價值-成本矩陣,我們會:
- 優先解決高價值+低成本的技術債;
- 嘗試將高價值+高成本的技術債拆分為高價值+低成本的技術債,逐步解決;
- 在沒有高價值+高/低成本的技術債時,再來考慮低價值+低成本的技術債;
- 最后如果只剩下低價值+高成本的技術債,還是先拆分,再解決,或可考慮直接移除。
3.3.3 解決技術債
分析完技術債的價值、成本、優先級、方案,我們可以在版本的gap期間跟隨版本修復技術債,如果某部分功能剛好規劃在版本中,那我們技術債的修復剛好由測試一起回歸,這樣可以做到工作量最小化,如果是高優的技術債,我們就需要盡早安排修復,緊急線上問題更是需要迅速迭代小版本上線。當然,修復完一定要及時更新技術債的狀態。對于數據清理這條技術債,我們分析后得出結論:對于系統穩定方面有影響,需要一次性徹底優化,價值較高,優先級較高但是無需緊急修復上線,所以在下一個版本人力空閑期間就可以伺機修復上線。
這里要注意的是,對于同一條技術債,記錄的人、修復的人可以不是同一人,這里需要技術債記錄詳細,便于方案的執行。數據清理這條技術債我們在隨后的一段時間內就整改上線,完成了這條技術債的修復。
3.3.4 階段審視
在實行技術債機制的管理過程中,建議進行階段審視,查漏補缺。我們已經詳細記錄了技術債的所屬項目、問題描述、創建人、處理人、創建時間、修復時間、技術債狀態、規劃版本、備注等屬性,便于技術債的跟蹤和審視。可以從多方面審視,一個是統計數據,如下表,可以看出每個階段的修復數量、新增數量、上線總數、正在修復的數量和待開始的數量。這也是衡量項目質量的影響指標之一。
另外一種是趨勢圖,我們可以從下圖這樣的折線圖明顯看出不同狀態的技術債的趨勢,包括不同階段的技術債新增數量、修復數量、修復中數量和技術債總數趨勢變化。
除此之外我們可以觀察團隊成員在修復技術債方面的工作量體現,比如統計一年不同季度、不同團隊成員每個季度對于技術債的修復數量,都是一些階段審視的方式。
3.4. 技術債管理機制
3.4.1 明確管理機制和責任分配
團隊在針對技術債的治理過程中一定要確定主要責任人,雖然解決團隊技術債問題是所有團隊成員的責任,但是為了管理流程化、合理化、最優化,往往需要指定一個負責人專門跟蹤技術債的管理。除此之外,技術債的管理機制要在團隊內部達成高度一致,整個團隊對于技術債問題的認知、修復、管理都是經過正式裁決的。
3.4.2 主動預防原則
通常來說,開發人員能直觀感受到技術債的壞處,大都愿意去償還技術債,所以技術債累積的主要原因是,沒有認識到技術債累積給業務發展帶來的巨大壞處。這也就意味著,解決技術債的第一步就是,要意識到償還技術債的重要性,從而愿意投入資源去解決。對主動引入的技術債,要盡量讓管理層和產品團隊了解技術上的捷徑將會帶來的長期危害,盡量減少技術債的引入。
3.4.3 高價值優先原則
需要遵循高價值優先的原則來優先修復技術債,上面我們已經分析過技術債問題的價值/成本矩陣,對于分析結果,我們在版本中解決技術債問題的時候就要嚴格按照高價值優先的原則去修復,而不是根據技術債發現的時間,或者是成本低的技術債優先修復,切忌隨機修復技術債。
四、經驗總結
4.1 技術債是不是越少越好?
當然不是!提到技術債,我們想到的往往是它的壞處,比如難以維護、難以增加新功能等,但實際上它也有好處。關于技術債的好處,我們可以對應著金融領域的經濟債務來理解。我們都知道,經濟債務最明顯的好處在于,可以幫助我們完成很多本來不可能完成的任務,比如貸款買房。相應的,技術債可以在短期內幫我們快速完成業務開發,滿足用戶需求,就類似房貸的作用。當研發團隊面臨業務壓力時,例如在發布新產品時需要快速上線以占領市場時,快速解決問題的重要性常常超越了更好的實踐。在這種情況下,團隊往往會選擇快速完成產品交付,然后再處理技術債務。團隊清楚這樣做會帶來技術債務,也知道逾期還債的具體后果,只要有計劃的進行優化即可。
4.2 持續管理技術債帶來的益處有哪些?
- 提升系統穩定性:不斷規范化的解決更多的技術債有利于系統更加穩定;
- 形成穩定機制:活動中臺系統經過長時間的實踐,逐漸形成穩定的技術債管理機制,面對項目中的技術債不再頭疼如何跟蹤;
- 提升項目質量:隨著技術債機制的實行,項目成員在迭代時就會更多的考慮技術債方面的問題,久而久之項目質量也會有所提升。
4.3 技術債是否可以作為項目管理的重要指標之一?
技術債已經成為很多項目管理的一個重要指標,用來衡量項目整體的研發效能,雖然本文沒有過度涉及技術債在研發效能工具方面的體現,但是在這個過程中工具很重要。
五、參考文檔
[1]Ward Cunningham,《WyCash 投資組合管理系統》,ACM SIGPLAN OOPS Messenger4, no.2 (1992)
[2]https://www.productplan.com/glossary/technical-debt/
[3]https://zh.wikipedia.org/wiki/%E6%8A%80%E6%9C%AF%E8%B4%9F%E5%80%BA#cite_note-oopsla92-1
[4]Philippe Kruchten, Rod Nord, and Ipek Ozkaya, 《管理技術債務:減少軟件開發中的摩擦》(Addison-Wesley, 2019)