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