陳武,汪驥宇,程植
(1.核動(dòng)力運(yùn)行研究所,湖北 武漢 430223;2.中核武漢核電運(yùn)行技術(shù)股份有限公司,湖北 武漢 430223)
數(shù)字經(jīng)濟(jì)時(shí)代的到來(lái),軟件產(chǎn)業(yè)蓬勃發(fā)展,行業(yè)產(chǎn)值發(fā)展迅速,對(duì)軟件工程師的需求日益增加。軟件工程技術(shù)、軟件框架理論實(shí)踐不斷發(fā)展,各種開(kāi)發(fā)框架理論和組件的出現(xiàn),在軟件研發(fā)的各個(gè)領(lǐng)域,產(chǎn)生了巨大的作用,極大促進(jìn)了軟件研發(fā)效率。這些框架的應(yīng)用,能夠降低對(duì)軟件研發(fā)人員的知識(shí)儲(chǔ)備要求,降低了軟件研發(fā)工作的進(jìn)入門(mén)檻。
微服務(wù)架構(gòu)隨著云計(jì)算的興起,已經(jīng)成為企業(yè)應(yīng)用中的主流技術(shù)。在微服務(wù)架構(gòu)應(yīng)用中,廣泛地應(yīng)用了各種開(kāi)發(fā)框架、組件,其主要應(yīng)用于SaaS 層應(yīng)用的開(kāi)發(fā)。Spring Cloud、MyBatis 框架組件是在微服務(wù)應(yīng)用開(kāi)發(fā)中,使用最為廣泛的框架。
這些開(kāi)發(fā)框架帶來(lái)極大便利,同時(shí)也產(chǎn)生了許多新的問(wèn)題。特別是在大型軟件項(xiàng)目中,對(duì)軟件質(zhì)量管理的能力要求高,特別是在工期、資源緊張的情況下,代碼規(guī)范性執(zhí)行力下降,導(dǎo)致軟件代碼的價(jià)值繼承性、可維護(hù)性降低。另外,在后期軟件新功能開(kāi)發(fā)、系統(tǒng)功能維護(hù)過(guò)程中,也會(huì)進(jìn)一步加劇這些問(wèn)題。
研究這些問(wèn)題解決方法具有很高的工程實(shí)踐意義,通過(guò)對(duì)軟件代碼的重構(gòu)[1],解決或有效緩解這些問(wèn)題,能夠極大提高軟件質(zhì)量。軟件重構(gòu)[2]理論有許多的模式,判斷如何使用、何時(shí)使用的問(wèn)題,需要設(shè)計(jì)人員和開(kāi)發(fā)人員的有很高的要求,在工程實(shí)踐中希望有一個(gè)有效的、易操作的方法指導(dǎo)軟件重構(gòu)工作。
本文通過(guò)對(duì)某核電軟件研制工程項(xiàng)目中近百個(gè)采用了這兩個(gè)架構(gòu)的微服務(wù)項(xiàng)目研究、分析,總結(jié)出在軟件研發(fā)過(guò)程經(jīng)常發(fā)生幾個(gè)典型問(wèn)題,提出微服務(wù)項(xiàng)目5分離法迭代重構(gòu)模式,指導(dǎo)微服務(wù)項(xiàng)目進(jìn)行重構(gòu),提高軟件的質(zhì)量。
在某核電軟件研制工程項(xiàng)目中的微服務(wù)工程,在微服務(wù)設(shè)計(jì)中采用了領(lǐng)域驅(qū)動(dòng)設(shè)計(jì),以及典型的4層微服務(wù)架構(gòu)如圖 1所示。架構(gòu)模型中包括接口層、應(yīng)用層、領(lǐng)域?qū)印⒊志脤?,另外還有一個(gè)貫穿四層的基礎(chǔ)設(shè)施層。
1) 接口層:提供前端適配,實(shí)現(xiàn)針對(duì)不同的前端應(yīng)用請(qǐng)求提供服務(wù),實(shí)現(xiàn)對(duì)象轉(zhuǎn)換,以及數(shù)據(jù)組裝等場(chǎng)景。防止核心業(yè)務(wù)邏輯暴露、數(shù)據(jù)外泄,同時(shí)保證下層的穩(wěn)定。
2) 應(yīng)用層:提供應(yīng)用服務(wù),鏈接接口層和領(lǐng)域?qū)?,主要?shí)現(xiàn)服務(wù)協(xié)同聚合、服務(wù)編排、服務(wù)組合,以及安全校驗(yàn)等邏輯處理。
3) 領(lǐng)域?qū)樱禾峁┖诵臉I(yè)務(wù)服務(wù),通過(guò)各種領(lǐng)域?qū)ο髽?gòu)建領(lǐng)域模型,各種對(duì)象的方法調(diào)用實(shí)現(xiàn)業(yè)務(wù)邏輯,對(duì)應(yīng)用層提供服務(wù)。另外調(diào)用持久層服務(wù),實(shí)現(xiàn)業(yè)務(wù)對(duì)象持久化。
4) 持久層:提供數(shù)據(jù)持久化服務(wù),將數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)中。
5) 基礎(chǔ)設(shè)施層:提供基礎(chǔ)公共服務(wù),主要包括配置類(lèi)、工具類(lèi)、基礎(chǔ)公共模塊、其他公共模塊。
這種分層架構(gòu)是一個(gè)弱耦合架構(gòu),層與層之間向下依賴(lài),下層對(duì)上層無(wú)依賴(lài),基礎(chǔ)設(shè)施其他層無(wú)依賴(lài)。這樣的分層架構(gòu)帶來(lái)很多好處,如開(kāi)發(fā)人員可以只關(guān)注整個(gè)結(jié)構(gòu)中的其中某一層;可以很容易地用新的實(shí)現(xiàn)來(lái)替換原有層次的實(shí)現(xiàn);可以降低層與層之間的依賴(lài);有利于標(biāo)準(zhǔn)化;利于各層邏輯的復(fù)用[3]。
圖1 4層架構(gòu)
在軟件研發(fā)項(xiàng)目中,依據(jù)范圍、進(jìn)度、成本等方面要求,需要先選擇微服務(wù)工程進(jìn)行重構(gòu)任務(wù)的驅(qū)動(dòng)。另外,軟件重構(gòu)管理是一個(gè)持續(xù)的工作,作為以下重要的任務(wù)進(jìn)行跟蹤。每個(gè)迭代中會(huì)進(jìn)行重構(gòu)任務(wù)分析,確定是否進(jìn)行重構(gòu),對(duì)哪一個(gè)項(xiàng)目進(jìn)行重構(gòu),重構(gòu)的目標(biāo)是什么。本節(jié)介紹一個(gè)在工程實(shí)踐中使用的簡(jiǎn)易工程選擇模型,可以初步確定本迭代需要的微服務(wù)工程。在該模型中,涉及7 個(gè)元素,包括工程規(guī)模(代碼量)、人員更替次數(shù)、迭代次數(shù)、測(cè)試Bug 數(shù)、工程重要程度、重構(gòu)次數(shù)。
如表1 所示,列出在本項(xiàng)目過(guò)程中某個(gè)迭代的分析結(jié)果。
表1 項(xiàng)目代碼分析表
根據(jù)情況選擇重構(gòu)緊迫度排名以及項(xiàng)目組開(kāi)發(fā)進(jìn)度,選擇緊迫度高的項(xiàng)進(jìn)行重構(gòu)分析。在分析過(guò)程中,一般關(guān)注重要、核心業(yè)務(wù)相關(guān)實(shí)現(xiàn)代碼。
通過(guò)對(duì)微服務(wù)項(xiàng)目中重構(gòu)實(shí)施的總結(jié),得到5 個(gè)典型問(wèn)題:超大類(lèi)、規(guī)則劃分混亂、參數(shù)傳遞對(duì)象未區(qū)分、邏輯分層不清晰、業(yè)務(wù)規(guī)則重復(fù)。
隨著功能、業(yè)務(wù)規(guī)則不斷增加,業(yè)務(wù)類(lèi)包括的功能越來(lái)越大,主業(yè)務(wù)類(lèi)的邏輯非常復(fù)雜、龐大,導(dǎo)致超大類(lèi)的出現(xiàn)。類(lèi)太大會(huì)引發(fā)的問(wèn)題一系列問(wèn)題,如維護(hù)困難、規(guī)則修改困難,影響虛擬機(jī)運(yùn)行,會(huì)導(dǎo)致內(nèi)存頻繁地被占用和回收,類(lèi)加載會(huì)消耗更多時(shí)間,占用更大內(nèi)存,容易引起內(nèi)存回收。
在開(kāi)發(fā)過(guò)程中,隨著功能的迭代、邏輯的增加,會(huì)增加新的實(shí)體對(duì)象、事件對(duì)象、服務(wù)對(duì)象,來(lái)實(shí)現(xiàn)新的業(yè)務(wù)規(guī)則,也可能在原來(lái)的類(lèi)中增加方法來(lái)實(shí)現(xiàn)新的規(guī)則。在這個(gè)過(guò)程沒(méi)有對(duì)模型進(jìn)行重構(gòu),導(dǎo)致規(guī)則的歸屬出現(xiàn)混亂。
在4層模型中,前端展示層和接口層通過(guò)視圖對(duì)象(VO) 對(duì)象傳遞數(shù)據(jù),接口層將對(duì)象轉(zhuǎn)換為數(shù)據(jù)傳輸對(duì)象(DTO) 傳遞給應(yīng)用層,再轉(zhuǎn)換為領(lǐng)域?qū)ο?DO) 傳遞給領(lǐng)域?qū)?,最后通過(guò)持久化對(duì)象(PO) 傳遞給持久層進(jìn)行持久化。
最常見(jiàn)的問(wèn)題是一個(gè)對(duì)象穿透4層,容易導(dǎo)致業(yè)務(wù)邏輯的失控、信息安全失控、靈活性丟失等問(wèn)題。
邏輯分層不清晰,在開(kāi)發(fā)過(guò)程,未遵照分層的模型,將相應(yīng)的業(yè)務(wù)邏輯在對(duì)應(yīng)的層中實(shí)現(xiàn)。最常見(jiàn)的是在應(yīng)用層的類(lèi)方法中,實(shí)現(xiàn)領(lǐng)域模型的業(yè)務(wù)規(guī)則,這樣導(dǎo)致在其他應(yīng)用服務(wù)需要相同的領(lǐng)域服務(wù)時(shí),需要重寫(xiě)一遍相關(guān)的規(guī)則代碼,導(dǎo)致模型的失控。為后續(xù)維護(hù)、新功能開(kāi)發(fā)埋下隱患。
業(yè)務(wù)規(guī)則重復(fù),在開(kāi)發(fā)、運(yùn)維過(guò)程中,采用敏捷開(kāi)發(fā)的過(guò)程中,每一個(gè)開(kāi)發(fā)人員會(huì)去寫(xiě)自己的業(yè)務(wù)邏輯,往往一個(gè)業(yè)務(wù)規(guī)則會(huì)在不同的方法、不同的類(lèi)中實(shí)現(xiàn)。另外在運(yùn)維過(guò)程中,一個(gè)功能在開(kāi)發(fā)過(guò)程、運(yùn)維過(guò)程中的人員變化,導(dǎo)致問(wèn)題修復(fù)功能優(yōu)化時(shí),往往采用復(fù)制的方法開(kāi)發(fā)新的方法。
本重構(gòu)模式包括重構(gòu)流程和設(shè)計(jì)模式兩個(gè)方面的內(nèi)容。重構(gòu)流程定義了重構(gòu)工作的工作流程,設(shè)計(jì)模式定義的重構(gòu)的設(shè)計(jì)方法。
一項(xiàng)工作完美執(zhí)行需要有一個(gè)有效的工作組織管理過(guò)程,在重構(gòu)中按照?qǐng)D 2 所示的流程組織,有效地進(jìn)行服務(wù)項(xiàng)目的重構(gòu)工作。包括模型回顧、關(guān)鍵方法分析、調(diào)用鏈分析、重構(gòu)、測(cè)試5個(gè)環(huán)節(jié)。
圖2 重構(gòu)流程
1) 模型回顧,重構(gòu)開(kāi)始時(shí),需要對(duì)服務(wù)的模型進(jìn)行完整的梳理,出現(xiàn)需要重構(gòu)的情形往往伴隨著模型的滯后。這需要重新梳理,完善模型,做好重構(gòu)準(zhǔn)備。同時(shí)還需要做好確定本重構(gòu)的目標(biāo),確定迭代的計(jì)劃。
2) 關(guān)鍵方法分析,在本步驟中對(duì)需要重構(gòu)的內(nèi)容進(jìn)行分析,確定服務(wù)、對(duì)象的關(guān)鍵方法,需要重構(gòu)的方法。
3) 調(diào)用鏈分析,確定需要重構(gòu)的方法后,需要分析重構(gòu)方法的調(diào)用鏈,識(shí)別使用情況,從而進(jìn)步與確定該方法涉及的相關(guān)功能以及相關(guān)測(cè)試用例。
4) 重構(gòu),依照本文提到的重構(gòu)設(shè)計(jì)模式,完成模型重構(gòu)設(shè)計(jì)。然后進(jìn)行代碼的開(kāi)發(fā),最終實(shí)現(xiàn)代碼的重構(gòu)。
5) 測(cè)試,本步驟是需要依據(jù)前面步驟分析出的相關(guān)測(cè)試用例進(jìn)行測(cè)試,從而驗(yàn)證重構(gòu)工作是否成功。
為解決本文中提到的問(wèn)題,設(shè)計(jì)如圖3 所示的微服務(wù)5分離迭代重構(gòu)模式,在該模式中采用多次迭代,5方法循環(huán)應(yīng)用。在重構(gòu)過(guò)程中,根據(jù)實(shí)際情況,通過(guò)分步迭代的方式,達(dá)到最終的重構(gòu)目標(biāo)。5 方法包括類(lèi)分離、方法分離、數(shù)據(jù)分離、規(guī)則分離、代碼分離5種方法,這五種方法互為補(bǔ)充,靈活應(yīng)用。
圖3 微服務(wù)5分離迭代重構(gòu)模式
1) 類(lèi)分離
《公務(wù)員法》規(guī)定公務(wù)員的薪酬由基本工資、補(bǔ)貼、津貼和獎(jiǎng)金組成,并不包含福利和保險(xiǎn),但是,隨著社會(huì)的發(fā)展,福利在總薪酬中占比例越來(lái)越大,現(xiàn)代薪酬理論普遍接受全面薪酬或者總薪酬的概念,認(rèn)為薪酬應(yīng)該是包括基本薪酬、可變薪酬、福利和服務(wù)以及一次性獎(jiǎng)金、股票期權(quán)等多種經(jīng)濟(jì)型報(bào)酬。
對(duì)超大類(lèi)首先采用類(lèi)分解的方法,進(jìn)行拆分,可以參考所示的模式進(jìn)行分解??梢园凑諏?duì)象基礎(chǔ)類(lèi)、查詢(xún)類(lèi)、高級(jí)查詢(xún)類(lèi)、添加類(lèi)、修改類(lèi)、校驗(yàn)類(lèi)、審批類(lèi),以及其他類(lèi)等模式進(jìn)行分解。最終形成一個(gè)對(duì)象類(lèi)族。一般實(shí)施步驟如下:
①進(jìn)行分類(lèi),將方法進(jìn)行分類(lèi),然后根據(jù)分類(lèi)創(chuàng)建類(lèi)。
②然后將各種方法遷移到各自的類(lèi)中。調(diào)整模型內(nèi)部的代碼結(jié)構(gòu),修復(fù)方法遷移導(dǎo)致的相互引用的失敗錯(cuò)誤。
③再修復(fù)上層調(diào)用中因?yàn)榉椒ㄟw移導(dǎo)致的錯(cuò)誤。
④最后進(jìn)行服務(wù)測(cè)試。
2) 方法分離
如果業(yè)務(wù)方法實(shí)現(xiàn)過(guò)程中,出現(xiàn)規(guī)則劃分混亂的問(wèn)題時(shí),需要通過(guò)方法轉(zhuǎn)移的方式來(lái)糾正該問(wèn)題,從而理順模型的規(guī)范性。一般做法如下:
②測(cè)試修改后的功能。
3) 數(shù)據(jù)分離
當(dāng)發(fā)生傳遞參數(shù)對(duì)象未區(qū)分問(wèn)題時(shí),需要通過(guò)數(shù)據(jù)類(lèi)型分解的方式,來(lái)處理該問(wèn)題。一般做法如下:
①確定需要修改的相關(guān)業(yè)務(wù)服務(wù),分析VO 和DO,確定雙方的差異。
②重新構(gòu)造VO,構(gòu)造數(shù)據(jù)類(lèi)型轉(zhuǎn)換類(lèi)方法。
③修改接口層、服務(wù)層接入數(shù)據(jù)對(duì)象,增加數(shù)據(jù)轉(zhuǎn)換方法調(diào)用。
④進(jìn)行功能測(cè)試。
4) 規(guī)則分離
當(dāng)發(fā)生邏輯分層不清晰問(wèn)題時(shí),需要進(jìn)行重構(gòu),厘清規(guī)則的分層。一般做法如下:
①理清應(yīng)用層邏輯中屬于領(lǐng)域部分的規(guī)則代碼。
②將該部分代碼抽取出,封裝到獨(dú)立的方法中。
③將該方法轉(zhuǎn)移到領(lǐng)域模型對(duì)應(yīng)的類(lèi)中。
④測(cè)試修改后的功能。
5) 代碼分離
如果存在較多的重復(fù)代碼塊,引發(fā)了業(yè)務(wù)規(guī)則重復(fù)的問(wèn)題,如兩次以上超過(guò)10行的重復(fù)代碼,可以通過(guò)采用重復(fù)代碼抽取的方式。將重復(fù)的代碼抽取到公共的方法中,減少重復(fù)率,提供代碼的可讀性、可維護(hù)性。一般做法如下:
①同一個(gè)類(lèi)型中的重復(fù)代碼抽象到公共的私有方法,將業(yè)務(wù)規(guī)則抽象封裝。
②如果該方法在同一個(gè)對(duì)象族中的其他類(lèi)中也用到相同的規(guī)則,那么將這幾個(gè)類(lèi)中的共同方法,根據(jù)方法的作用,轉(zhuǎn)移到相關(guān)的類(lèi)型中。如公共校驗(yàn)方法轉(zhuǎn)移到校驗(yàn)類(lèi)中,公共賦值方法轉(zhuǎn)移到基礎(chǔ)類(lèi)或賦值類(lèi)中。
③如果業(yè)務(wù)對(duì)象的類(lèi)中使用到相同的規(guī)則,那么將這個(gè)共同規(guī)則方法,轉(zhuǎn)移到領(lǐng)域基礎(chǔ)類(lèi)中。
④修改相關(guān)調(diào)用規(guī)則的代碼為調(diào)用公共方法。
⑤最后進(jìn)行服務(wù)測(cè)試。
在面向?qū)ο?、領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)[4]的理論中,以及典型設(shè)計(jì)模式理論[5]中,各種對(duì)象有明確的邏輯職責(zé)劃分,各層也有相應(yīng)的劃分,數(shù)據(jù)的傳遞也有理論要求。軟件重構(gòu)意味著需要更多的投入,在工程實(shí)踐中,往往并不能按照這些要求來(lái)判定是否需要重構(gòu)。設(shè)計(jì)人員、開(kāi)發(fā)人員還需要依據(jù)項(xiàng)目的實(shí)際情況,考慮業(yè)務(wù)的復(fù)雜度、重要度、使用情況等因素,確定是否重構(gòu)。
本文中總結(jié)的問(wèn)題,在很多工程中都存在,一般是隨著項(xiàng)目推進(jìn),工程規(guī)模不斷增大,這些問(wèn)題才會(huì)顯現(xiàn)出來(lái)。對(duì)于一個(gè)規(guī)模小的項(xiàng)目,即使出現(xiàn)這些問(wèn)題,對(duì)業(yè)務(wù)實(shí)現(xiàn)并沒(méi)有影響,對(duì)軟件質(zhì)量也影響較小,不需要啟動(dòng)重構(gòu)的。
開(kāi)發(fā)框架的使用,能夠極大地提高開(kāi)發(fā)效率、降低開(kāi)發(fā)人員要求,快速交付,從而能夠以較小的成本較短的周期完成項(xiàng)目。設(shè)計(jì)人員、開(kāi)發(fā)人員在研發(fā)過(guò)程中需要不斷對(duì)代碼進(jìn)行檢查,適時(shí)啟動(dòng)代碼重構(gòu)優(yōu)化,從而提高軟件質(zhì)量。本文的模式可以對(duì)這個(gè)過(guò)程提供一定的指導(dǎo)。