本文首先介紹了遺留代碼的概念,並對遺留代碼進行了分類。針對不同類型的遺留代碼,提供了相應的處理策略。此外,本文重點介紹了靈碼在維護遺留代碼過程中能提供哪些支援。
什麼是遺留代碼
與過時技術相關的代碼:
與不再受支援的作業系統或軟體庫相關的代碼。
依賴於已淘汰的技術棧或程式設計語言的代碼。
為相容老舊功能而保留的代碼:
在現代軟體中為了相容舊版本功能而保留的程式碼片段。
為了確保向後相容性而不得不保留的代碼。
缺乏文檔和維護的代碼:
沒有良好文檔支援的舊代碼。
缺乏現代開發實踐(如單元測試、代碼審查等)的代碼。
解決遺留代碼的方法
解決遺留代碼有以下三種常見的處理方法:
處理方式 | 利弊 |
推翻重來 | 成本高,系統正在運行,會帶來代碼風險。 |
進行重構 | |
補充單元測試 | 通過單元測試識別現有代碼中的問題,為未來可能的代碼變更提供品質保障。 |
根據上述描述,補充單元測試是一種有效解決遺留代碼問題的方法。然而,這種方法仍然存在一些問題:
大量遺留代碼缺少單元測試,並且由於代碼間的複雜依賴關係,進行測試的成本非常高。
具體的衡量標準卻不夠清晰,無法定義好的單元測試。
哪些代碼需要添加單元測試?
單元測試常見的誤區
缺乏斷言的假單元測試:開發人員可能會採取僅調用函數而不進行斷言的方式,以提高覆蓋率指標,導致了許多無效的單元測試。
把單元測試當成白盒測試:一些觀點將單元測試歸類為白盒測試,但實際上應將其視為針對函數簽名的黑箱測試。
依賴真實環境的單元測試:阻礙單元測試的主要因素包括惰性和依賴環境配置。若不使用Stub或Mock解除對外部環境(如網路IP、資料庫)的依賴,單元測試將難以達到FIRST原則(快速、獨立、可重複、自我驗證、及時性)。
選擇性的進行單元測試
單元測試除了帶來收益外,本身也會產生一定的成本。如果從收益與成本的角度分析遺留代碼,將有助於明確為遺留代碼補充單元測試的策略,此策略被稱為選擇性單元測試。那麼,如何界定成本與收益呢?
遺留代碼單元測試的成本收益象限分類
針對遺留代碼的單元測試,可以根據其成本和收益進行象限分類。根據下圖,對分類標準和各象限進行詳細說明:

分類標準
X軸(成本):代碼依賴程度越高,測試成本越大。
Y軸(收益):代碼複雜度越高,品質收益越大。
四個象限
代碼分類 | 特性 | 描述 | 收益 | 成本 |
演算法類代碼(Algorithms Code) | 循環複雜度高,扇入大。 | 包含較多條件判斷和迴圈語句,依賴其他代碼少,但被大量代碼依賴。 | 高 | 低 |
瑣碎代碼 (Trivial Code) | 循環複雜度小,扇入大。 | 通常是一些簡單的方法,只有一兩行代碼。 | 低 | 低 |
協調類代碼(Coordinators Code) | 循環複雜度小,扇出大。 | 處於調用關係的上層,通過調用其他代碼來反映特定業務情境。 | 低 | 高 |
複雜代碼(Overcomplicated Code) | 循環複雜度大,扇出大。 | 邏輯複雜,依賴多,函數冗長且參數繁多,是典型的代碼異味。 | 高 | 高 |
循環複雜度與依賴的概念理解
循環複雜度(Cyclomatic Complexity):衡量代碼中邏輯分支的數量。
扇入(Fan-In):直接調用該模組的上級模組的個數,扇入大表示模組的複用程度高。
扇出(Fan-out):一個模組直接調用的其他模組的數量,扇出大表示該模組依賴其他模組越多。
不同類型代碼的處理策略
根據上述的分析,遺留代碼的處理策略就變得十分明確:
演算法類代碼(Algorithms Code):產生單元測試。
協調類代碼(Coordinators Code):進行介面測試。
複雜代碼(Overcomplicated Code):尋找合適的機會進行重構。
瑣碎代碼(Trivial Code):不做處理。

使用靈碼處理遺留代碼
1. 瞭解專案工程
在維護一個工程的遺留代碼,首先可通過 @workspace 功能瞭解整個工程的目的及其涉及的各個模組。

2. 對不同類型代碼進行處理
針對演算法類(Algorithms)代碼產生單元測試
選中需要基於生產代碼進行代碼產生的部分。在產生時,請注意所需的架構及Mock等依賴資訊,可以通過產生單元測試命令後追加相關資訊進行補充。如 /generate unit testingCppUTest。

一般而言,基於現有代碼產生的單元測試用例數量通常較為有限。如果對單元測試的測試情境及用例數量有具體要求,可以在新產生的單元測試檔案中,通過測試函數的續寫方式產生更多的單元測試。在續寫過程中,靈碼將儘可能遵循已有用例,以此作為上下文進行參考。

針對協調類代碼(Coordinators)進行介面測試
對於協調類代碼而言,單元測試並不是一種理想的解決方案,由於存在過多的依賴,測試成本顯著提高。針對此類代碼,應該採用介面測試或功能測試的方式進行覆蓋,然而在編寫自動化測試案例時,開發人員常常會遇到相關問題。因此,可以通過靈碼,快速掌握並理解測試架構。

針對用例的編寫,可以選擇相應的被測函數,並在問答區中直接提問:基於Robot Framework產生以下代碼的測試案例。沿著這一思路,同樣可以實現相應的Keywords等內容。
超複雜的代碼(Overcomplicated Code)找機會進行重構
針對超複雜的代碼,可以使用通義靈碼的 /generate optimization 命令,以獲得針對所選代碼的最佳化建議。代碼審查與最佳化將從文法問題、異常改進、代碼整潔度、安全性及風險等多個維度給出相應的最佳化建議。

針對複雜遺留代碼的最佳化,並不建議開發人員們盲目進行全面的最佳化和重構。遺留代碼的變更可能會帶來巨大的風險。因此,開發人員應根據具體情況,在合適的機會,遵守童子軍法則,進行重構和最佳化。在這一過程中,靈碼也將為您提供有力支援。
結語
以上便是在處理遺留代碼時可參考的實踐。處理遺留代碼需要深入代碼的複雜結構,細緻地追蹤每一個可能的分支節點。在這一過程中,除了識別並修複潛在的缺陷外,還必須在有限的時間內完成所有任務。為了避免這一局面的發生,最佳的策略是預防代碼的腐化,善用工具,並在編寫初期遵循良好的編程原則。