選單

我常遇到的三種技術債務:程式碼、資料和架構

我常遇到的三種技術債務:程式碼、資料和架構

作者 | Nicholas Charriere

譯者 | 王強

策劃 | 曉旭

本文最初發佈於作者

個人部落格

,經授權由 InfoQ 中文站翻譯並分享。

在軟體工程中,我們經常面臨各種權衡取捨,用長期來看最佳的技術選項換取短期內的速度提升。借用金融術語的一種常見說法是把它叫做承擔

技術債務

這篇文章中我不會涉及意外和故意的技術債務,也不會給出什麼決策框架。那都是單獨的主題,而且要具體情況具體分析。

本文要講的是一個思維框架,我認為這個框架在不同的團隊、程式碼庫和系統中都能適用。我將技術債務分為三類:

程式碼、資料和架構

。現在我們透過一些例子來具體回顧這幾個類別。

程式碼技術債

這可能是最常見的,也是大家第一個能想到的。這種債務的形式是我們提交的次優程式碼。一些例子包括:

先複製貼上一些程式碼,稍後重構

編寫一個可以完成所有事情的大函式

匯入一個巨大的庫,卻只是為了一個很小的功能需求

擴充套件函式簽名以管理邊緣情況

大家都可能見過很多這樣的程式碼:

程式碼技術債務往往最容易被提到,因為在審查他人的程式碼或粗略瀏覽程式碼庫時很容易看出這些債務。它是 3 大類中最“可見”的。它往往也很容易修復,因為你可以透過測試和重構來包裝你的邏輯,在一次程式碼更改中搞定修復,或者通過幾次外科手術來處理(TDD 為充斥著技術債務的程式碼庫創造了很多奇蹟)。無論是用哪種方式修復,要處理的都只是程式碼,所以這一塊技術債承擔和償還起來都沒有太大的負擔。很多時候,當人們談到“技術債務”時,他們實際上是在考慮這個分類的問題。但我希望情況不是這樣,因為這個類別是危害最小的!

架構技術債務

這是軟體專案承擔的一種不太常見但非常關鍵的債務形式。它與系統架構、執行時選擇、介面、服務設計、儲存決策等設計考慮相關。

一些例子:

這個程序在什麼執行時中執行?

我們如何在程序 / 服務之間傳遞訊息?

我們是採用單體策略、共享庫還是面向微服務的架構?

這應該是離線作業還是線上服務?

這些 worker 應該是無狀態還是有狀態?

我們應該採用輪詢模型(pull)、觸發器(push)還是事件驅動模型 (pub/sub)

我常遇到的三種技術債務:程式碼、資料和架構

這些架構決策可以將專案推向完全不同的方向。以上面的例子為例,在流量平穩且 QPS 較低的情況下使用中間釋出 / 訂閱佇列,可能會以維護和除錯的形式增加架構債務。但是,如果流量非常陡峭並且服務 B 無法處理峰值負載,那麼推送模型將是這一領域產生債務最多的。

架構債務的償還通常跨越更長的時間週期。長反饋迴圈更難學習,而且這種架構債務很容易被忽略。SWE 在矽谷的平均任期為 18 個月,但發現早期架構決策的問題可能需要更長的時間!當優步發展到 1000 個微服務和 2000 位工程師時發生的 事情 就是一個完美的例子。走微服務路線確實在短期內提高了他們的速度,但後來這條路線為整個系統帶來了可除錯性和延遲方面的債務。

架構債務的成本可能很高(糟糕的 on-call 計劃,系統僵化且難以推理,缺乏可除錯性),並且與程式碼債務相比更難償還。深入分析你們正在應對的系統,並瞭解專案做出了哪些影響服務特性(可維護性、靈活性、可靠性等)的關鍵決策(不管這些決策明確與否),在任何時候都是非常有價值的行動。其中一些決策可能是故意為之的,並帶來了有趣的後果。

最後,即使人們在試圖避免架構技術債務時,這些債務也可能會偷偷增加。過早的最佳化通常會導致我們最終產生債務。一個例子是為 10k QPS 設計的一個 Web 服務,最後只用來應對 1/100 的流量。許多架構決策可能會各自衝突,而且很容易因為不必要的複雜性而產生債務。

資料和建模技術債務

資料建模似乎不像以前那麼常見了。曾經有一段時間,大多數工程師都要定期從事資料建模工作。現在人們通常將其委託給一個特殊的團隊(“使用者服務來處理”),或者使用一些允許他們完全忽略這類問題的工具(在這方面的例子有 graphQL、mongoDB)。

資料建模的影響在短期和長期範圍都存在。從短期來看,在模型和型別上花費大量時間會讓人感覺成本很高,因此人們很容易選擇一些非常靈活的東西來最佳化早期迭代和靈活性。然而,我已經看到這是錯誤的方式(把所有內容都放在一個 JSON 中,並在客戶端上進行所有過濾工作),最後我們會在回填、資料完整性修復和重構方面多做很多工作。良好的資料建模對程式碼和系統架構都有正面影響,也就是說這 3 類技術債務其實是相互關聯的。然而,資料是最難做對的事情之一,也是最難改變的事情之一。所以資料技術債務應該被認真對待、積極識別、正確處理。實際上,當你想要更改你的資料模型時,這種更改的依賴關係圖通常是非常模糊的。它需要涉及程式碼更改、資料庫遷移和回填,所有這些都可能具有複雜的依賴關係,並且可能影響多個系統、團隊或服務。

我個人認為,這個技術債務類別的偶然性是最大的。理解讀寫模式和資料模型之間的關係可以幫助你有效預防這種債務方面,或者至少有意識地承擔它。預測哪裡需要靈活性、哪裡不應該存在靈活性是非常微妙的問題。隨著時間的推移,人們處理這種問題時會更有經驗,但必須有意識地應對它們才行。

小結

我們提到了程式碼、資料和架構類別的技術債務。下次你做設計決策或審查程式碼時,可以試著找出你所承擔的債務,並就此作出明確的討論:這些債務可能的後果是什麼?它什麼時候才能得到解決?在日常的開發工作中,架構和資料類技術債務是最難注意到的,但它們以後的消化成本卻是最高的,因此值得你認真應對。

最後我想強調的是,技術債務並不總是壞事。使用 MongoDB 來原型化想法或編寫一個醜陋的函式來解決關鍵錯誤都可以是合理的做法,並且可能是最佳方案。問題是不要故意去做一些增加技術債務的事情。

https://bytesizetheories。com/posts/3-kinds-of-tech-debt/