背景
在日常業務的研發過程中,由于需求的緊迫性,往往留給研發團隊的時間相對有限。這種情況下,為了確保業務盡快上線,不得不在一定程度上犧牲設計的嚴謹性和技術的前瞻性,雖然短期內看似解決了燃眉之急,但長此以往,卻逐漸累積了大量的技術債務。
技術債,又稱設計債或代碼債,是指在軟件開發過程中為了追求快速交付而采取的非最佳實現方式所帶來的后續成本。這種“債務”可能源于使用了臨時性的解決方案、忽略了代碼質量、或沒有遵循良好的設計原則和實踐。
隨著技術復雜度的逐步提升,系統的可維護性不可避免地受到侵蝕。這種演變并非線性的遞增,而是呈現出指數級的增長趨勢,最終會導致需求吞吐、交付質量雙雙下降。
為進一步提升服務品質和用戶體驗,斗拱進件板塊決定啟動客戶全旅程項目,實施客戶體驗的深度改造。但是在整個項目的研發實施過程中,工程師們發現由于業務邏輯與系統模塊的復雜與緊耦合,在開發的時候碰到了較多的困難與挑戰,包括研發代碼的周期與測試的質量等等,雖然最終有驚無險,順利完成交付,但是我們發現,進件系統的維護與擴展已進入一個新的難度等級,必須啟動戰略性重構升級計劃,為業務可持續發展夯實基礎。
問題分析
經過多年的持續迭代投入,斗拱的整套進件體系功能越來越強大,代碼量也越來越多,一次完整的進件,要由大量的微服務共同協作完成。從應用架構層面,進件系統可分為:以領域層為復用核心,以功能層為交付重心,以交互層為體驗迭代中心,這樣的一套三層架構體系:
● 交互層:包含API、WEB頁、APP等交互邏輯與服務;
● 功能層:組合領域層原子接口,形成業務功能向交互層輸出;
● 領域層:提供抽象過后的原子服務能力,場景關聯性弱;
該分層架構在人員配備充足,業務及團隊穩定的情況下,是能夠充分發揮其設計效能的。然而,隨著斗拱業務規模的持續擴大,面對多產品線高并發迭代的工程挑戰與客戶需求的爆發式增長態勢,研發資源的配置根本滿足不了業務的吞吐速率要求。為確保重要業務目標的順利交付,部分團隊不得不采用敏捷交付機制,在架構設計層面進行必要的動態平衡——通過建立架構治理框架下的技術決策機制,允許在關鍵路徑上實施階段性靈活調整,同時為體系化重構預留技術窗口。
其次,在推進支付平臺化建設的戰略進程中,由于缺乏成熟的范式可供參考,我們特地組建了專門的技術委員會。面對各行各業的多樣化需求、各類用戶角色以及紛繁復雜的場景故事,如何在一套平臺上實現這些功能,成為了委員會頻繁討論的焦點:是沉淀復用還是個性化定制?是僅考慮某一端還是全面支持所有端?是做到交互層、功能層還是領域層?各方觀點不一,但都有其獨到之處。
長期運作下來,進件系統各層級,都在大規模的并行迭代,以致于:
第一,用戶交互層與功能層之間,出現了比較多的冗余邏輯,加劇了系統的復雜度。
第二,功能層與領域層之間,也存在相似的重復代碼現象,技術債務累積。
再者,功能層主要由管理服務和查詢服務兩個團隊負責。其中,管理服務涵蓋了客戶體驗的方方面面,包括但不限于進件材料與流程、業務配置與開通、協議簽署,以及一系列配套的運營支撐功能。這些功能不僅要滿足標準化的業務需求,還需兼顧用戶的功能體驗和重點客戶的個性化定制。隨著時間的推移,管理服務逐漸變得愈加龐大復雜,后續的維護與擴展難度也隨之逐步增加。
最終,管理服務成為了交付瓶頸,需求越積越多。當新增客戶全旅程這樣一個非常大的業務能力時,我們來到了復雜度指數上升的邊沿。
重構思路
重構(Refactoring),即還技術債,是指在不改變軟件外部行為的前提下,對軟件內部結構進行優化和調整的過程。其主要目的是提高代碼的可讀性、可維護性和可擴展性,從而降低后續開發和維護的成本,提升交付質量和效率。
論及重構,領域驅動設計(DDD)無疑是最先映入腦海的方法論。沒錯,我們也正是借助DDD的戰略設計,對子域進行了重新劃分,形成商戶、審核、協議等子域,通過DDD的戰術設計,將一些共通的邏輯提煉出來,形成業務權限、計費等模塊。
領域驅動設計(Domain-Driven Design,簡稱DDD)是一種軟件設計方法論,它強調以業務領域為核心進行軟件設計,通過創建豐富的領域模型來反映業務邏輯,從而實現業務和技術的統一。
整個重構落地也是非常復雜,為了確保業務連續性不受影響,我們通過系統化、工程化的手段,分批次啟動項目實施。整體分為兩大階段:
階段一:領域拆分與沉淀
1、原斗拱進件板塊,按照DDD的設計思想,重新進行領域的劃分;
2、按照新的劃分(子域A、子域B...),將交互層、功能層的邏輯沉淀到各個領域;
3、擴充領域職能,使其不僅提供內部服務,同時提供對外的API及應用組件;
核心思路:把原先按功能職責拆分的橫向切分架構,重構為按領域職責拆分的縱向切分架構,如下圖所示:
階段二:領域模塊升級優化
1、在每個領域內,針對較難維護的領域模塊,進行二次重構、升級、優化;
核心思路:各個領域團隊內部不定期發起重構(可能大可能小),升級優化自身負責的系統代碼,提升其可維護性及可擴展性。
本篇文章中,我們主要探討階段一,后續的重構文章系列中,我們再逐步探討階段二的技術故事。
領域拆分與沉淀
1、領域劃分
在啟動重構之前,至關重要的是要進行廣泛而深入的溝通與交流,以明確各個領域的定義、內容及其邊界。這一過程中,我們應用DDD方法論,圍繞用戶故事對上層服務的業務邏輯,尤其是功能服務進行全面梳理。此環節需大量業務專家及系統負責人的積極參與,經過多輪次的討論與碰撞,最終達成共識,并明確各領域的負責人。
接下來,我們將斗拱進件的對外API接口清單、控臺頁面菜單、內部功能服務接口清單逐一列出,并根據其所屬領域進行歸類。對于那些同時涉及多個領域的頁面、內外接口,就由熟悉相關業務的領導根據其經驗作出決策,給到最合適的領域。
一旦確定了領域歸屬,接下來的任務便是從代碼層面著手,對所有的API服務、頁面及BFF(Backend For Frontend)服務、功能服務進行改造與遷移工作,將其合理地拆分并沉淀到各自對應的領域服務中。
2、代碼實施
整個代碼實施過程,分為五步:著色->代碼拆分->服務拆分>數據庫拆分->整理&優化。
步驟一:著色
對后端BFF服務、功能層服務中,所有Public的API方法、Service方法、Repository方法等,添加自定義@Domain注解,以標識其所屬領域。對于被多個領域同時使用的公共方法,要么標記多個領域名稱,要么標記為All,即所有領域。
說明:此過程同樣涉及大量討論與交流。為了最終達成共識,建議按固定一個人的拆分思路統一開展,出現爭議由其來拍板,以免陷入無休止的爭辯而無法說服彼此的局面。
步驟二:代碼拆分
在不改變服務化結構以及微服務調用入口的前提下,將@Domain標記的代碼及其遞歸引用的私有代碼,全部復制到為各個領域新建的獨立工程目錄中,此時需修改方法提供方及方法調用方相應的import包路徑,標記多個領域的方法就復制多份,標記為All的公共方法,就每個域都復制一份。
說明:這個過程比較復雜的地方是依賴識別,我們是在Idea插件的基礎上自主研發工具實現的。遷移完成后,新版本在生產環境中運行至少兩周,以驗證其穩定性和可靠性。
步驟三:服務拆分
在調用入口不變的前提下,將跨領域的內存調用代碼,轉成微服務遠程調用代碼。此時,微服務的數量會顯著增加,大致等于被拆分微服務個數乘以領域數量,此時每個服務就可以獨立迭代需求了。同樣,該過程也是通過工具完成,微服務調用代碼是按統一模版格式生成的,所以類及方法的命名會存在一些不人性化的情況。
說明:這個過程會遇到比較多的問題,如:內存全局變量問題、數據庫事務問題、抽象繼承類問題、異步通知問題、超時時長設置問題等,我們在后續的重構系列文章中再行展開。遷移完成后,新版本在生產環境中至少穩定運行兩周,代表該階段的完成。
步驟四:數據庫拆分
為各領域創建獨立的數據庫,并將各領域獨有的庫表及數據內容遷移至新庫中。針對那些跨多個領域的共享表,則要進行數據拆分與遷移,該一步驟相比前面的代碼拆分、服務拆分,工作量和復雜度都有顯著上升。鑒于該步驟短期內難以完成,同時考慮到以下實際情況,我們決定暫時擱置,未來擇機實施:
● 對所有數據庫表,進行領域歸屬劃分,每張表僅歸屬一個域,針對該表的結構及關鍵數據變更,均由所屬領域團隊完成,避免引入跨領域協作問題;
● 在服務拆分階段時,大部分跨領域的數據操作都已轉成微服務調用,只有少數因性能、事務等考量的查詢,直接通過Mapper跨庫訪問。
● 跨域共享表的數量不多,由其他域代為維護的規模不大,復雜度尚在可控范圍內;
步驟五:整理&優化
拆到各個領域的微服務,整體是包含了原后端BFF服務、功能服務全部的源代碼,工程包非常大,類也非常多。各個團隊需要手動整理這些代碼,剔除不屬于本領域的部分以及未被使用到的函數和方法。此外,對于那些在服務拆分階段產生的工具型微服務接口,我們使用@Deprecated注解予以標記,明確表示這些接口不再接受迭代更新,若未來有需求要迭代,則按照標準的接口規范重新設計實施,以此逐步淘汰工具型的接口。
3、重構效果
在歷時三個多月的項目實施過程中,我們遇到各種各樣的挑戰,也逐一克服。整個項目的復雜度極高,參與進來的都是各團隊的核心成員及眾多資深架構師。最終,項目也取得了令人矚目的成果。
從業務角度統計,進件相關需求的交付吞吐率提升了30%,缺陷密度(上線100個需求引入的缺陷數)下降30%。
從技術層面來看,日常需求的協作模式從原先前端、功能和領域的多方協作,演變為單個領域團隊為主;所有原領域層研發人員全面參與到業務開發中,顯著提升了他們的業務經驗;所有技術TL積極參與了領域邊界的討論,對各自邊界有統一清晰的認識,很少再出現邊界爭論;原功能層的管理服務,在經過重點拆分和沉淀后,系統的維護復雜度明顯降低。
總結
斗拱進件體系的重構實踐,充分彰顯了直面技術債務的重要性。通過縝密規劃與嚴謹執行,我們不僅實現了重構的目標,還顯著提升了業務和技術效能。這不僅是對技術架構的一次優化,更是團隊協作能力與技術實力的全面提升。
免責聲明:以上內容為本網站轉自其它媒體,相關信息僅為傳遞更多信息之目的,不代表本網觀點,亦不代表本網站贊同其觀點或證實其內容的真實性。如稿件版權單位或個人不想在本網發布,可與本網聯系,本網視情況可立即將其撤除。
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。