本質是一種技術債務,產生原因一方面是業務原因:如業務本身場景繁多、流程複雜等;另一方面是技術原因:如程式碼不規範、設計不合理、祖傳程式碼檔案註釋缺失等。它會影響我們的程式很多方面:如可讀性、可修改性、可複用性、可維護性、可測試性等。
劃分為梳理->重構/重寫->替換/驗證三個階段
遺留程式碼的處理是一種逆向工程,從已有的程式碼+資料模型+檔案倒推出業務模型、互動和規則,在保真的前提下再重新構建程式碼+資料模型+檔案。
我們這裡可以參考下DDD領域驅動設計裡戰略設計部分常用的工具(事件風暴法)來進行這部分梳理工作。
事件風暴本質上是一種系統建模的方法,與它處於對等位置的,會有「UML建模」、「事件驅動建模」等。事件風暴跟敏捷開發裡的一些理念(如使用者故事)的產生背景類似,都是在理性思考無法應對變化頻繁且文字難以描述的情況下,通過一些輔助性的提示卡片、視覺手段,輔以相關人員的集中、高頻溝通來完成對於業務的準確把握和抽象建模。
事件風暴的過程:
事件風暴的產物:
梳理結果範例:
通過重構/重寫對軟體要素進行重新組織,使其不改變外部行為的情況下,提升程式碼的可讀性或使其結構更合理。
針對不同層次的軟體要素要做不同的處理和控制:
並且整個重構/重寫過程有些需要遵照的原則:
其中有兩點落地細節我們具體分析下:
大概分為以下幾個要點:
可藉助過程管理工具如PDCA法進行管理
原始需求:案例為一個轉賬服務,使用者可以通過銀行網頁轉賬給另一個賬號,支援跨幣種轉賬。同時因為監管和對賬需求,需要記錄本次轉賬活動。
原始架構:是一個傳統的三層分層結構:UI層、業務層、和基礎設施層。上層對於下層有直接的依賴關係,導致耦合度過高。在業務層中對於下層的基礎設施有強依賴,耦合度高。我們需要對這張圖上的每個節點做抽象和整理,來降低對外部依賴的耦合度。
重構關鍵設計點:
重構後程式碼特徵:
業務邏輯清晰,資料儲存和業務邏輯完全分隔。
Entity、Domain Primitive、Domain Service都是獨立的物件,沒有任何外部依賴,但是卻包含了所有核心業務邏輯,可以單獨完整測試。
原有的轉賬服務不再包括任何計算邏輯,僅僅作為元件編排,所有邏輯均delegate到其他元件。
原始需求:現有幾個策略實現類,被很多程式碼使用。現在需要根據不同的業務方在每個策略執行前做不同的前置邏輯處理。
解法分析:儘量避免把邏輯耦合到已有的實現類中。引入外部類進行控制反轉。這裡我們使用存取者模式。
存取者模式把資料結構和作用於結構上的操作解耦合,使得操作集合可相對自由地演化。存取者模式適用於資料結構相對穩定演演算法又易變化的系統。因為存取者模式使得演演算法操作增加變得容易。若系統資料結構物件易於變化,經常有新的資料物件增加進來,則不適合使用存取者模式。存取者模式的優點是增加操作很容易,因為增加操作意味著增加新的存取者。存取者模式將有關行為集中到一個存取者物件中,其改變不影響系統資料結構。其缺點就是增加新的資料結構很困難。
具體實現:
重構後程式碼特徵:
可以通過存取者對老程式碼邏輯進行編排,將修改外接,減少對老邏輯的影響
通過java8預設介面實現提供預設存取行為,避免大量策略子類的感知,只需要需要提供自己實現行為的子類對預設實現進行覆寫
遺留程式碼的處理能力一方面是對技術的要求,另一方面也是對業務掌握的挑戰。希望我們可以跨越荊棘、穿過迷霧,順利到達成功的彼岸!