蒙亮 胡俊楊
[摘? ? 要] 十三五期間,隨著電網(wǎng)信息化支撐業(yè)務(wù)領(lǐng)域的廣度和深度不斷增強(qiáng),傳統(tǒng)IT架構(gòu)如何適應(yīng)“互聯(lián)網(wǎng)+電網(wǎng)”形勢(shì)下的戰(zhàn)略轉(zhuǎn)型,成為電網(wǎng)信息化管理過程中的迫切需求和需要思考的問題。本文基于許多大型電網(wǎng)企業(yè)多年來的架構(gòu)應(yīng)用實(shí)踐,詳細(xì)闡述了如何以領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(簡(jiǎn)稱:DDD)為指導(dǎo)思想,對(duì)復(fù)雜的應(yīng)用系統(tǒng)進(jìn)行服務(wù)拆分。
[關(guān)鍵詞] IT架構(gòu);領(lǐng)域驅(qū)動(dòng);服務(wù)拆分
doi : 10 . 3969 / j . issn . 1673 - 0194 . 2018. 21. 033
[中圖分類號(hào)] F270.7;TP393.09? ? [文獻(xiàn)標(biāo)識(shí)碼]? A? ? ? [文章編號(hào)]? 1673 - 0194(2018)21- 0085- 03
1? ? ? 前? ? 言
1.1? ?背景與意義
隨著網(wǎng)絡(luò)安全法的發(fā)布實(shí)施、大數(shù)據(jù)、云計(jì)算、移動(dòng)互聯(lián)網(wǎng)、物聯(lián)網(wǎng)、人工智能等新技術(shù)發(fā)展日新月異,供給側(cè)結(jié)構(gòu)性改革、電力體制改革、國(guó)資國(guó)企改革、“一帶一路”、“互聯(lián)網(wǎng)+”等新政策的不斷推進(jìn),許多電網(wǎng)企業(yè)的發(fā)展處于重要戰(zhàn)略機(jī)遇期、轉(zhuǎn)型升級(jí)期、改革深化期。內(nèi)外部環(huán)境的深刻變化,直接對(duì)電網(wǎng)企業(yè)信息化建設(shè)提出了新要求。大多數(shù)電網(wǎng)企業(yè)需要信息化手段來支撐主營(yíng)業(yè)務(wù)的深化改革及競(jìng)爭(zhēng)型業(yè)務(wù)的創(chuàng)新發(fā)展。
IT架構(gòu)升級(jí)是大型電網(wǎng)企業(yè)推進(jìn)信息化建設(shè)過程中必不可少的環(huán)節(jié)之一,它除了需要充分考慮業(yè)務(wù)轉(zhuǎn)型與新技術(shù)應(yīng)用的發(fā)展外,還涉及基礎(chǔ)設(shè)施、運(yùn)行時(shí)環(huán)境、服務(wù)框架、數(shù)據(jù)訪問框架、工作流程、工作臺(tái)和云管理等基礎(chǔ)性軟硬件平臺(tái)和關(guān)鍵技術(shù)的整合應(yīng)用。關(guān)于服務(wù)如何抽象,應(yīng)用系統(tǒng)架構(gòu)如何進(jìn)行應(yīng)用化改造,是IT架構(gòu)升級(jí)過程中的關(guān)鍵問題。
1.2? ?主要工作
本文針對(duì)IT服務(wù)架構(gòu)中最為關(guān)鍵的服務(wù)抽象設(shè)計(jì),引入領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)技術(shù),實(shí)現(xiàn)服務(wù)和組件的拆分。主要的研究?jī)?nèi)容包含以下幾個(gè)方面。
(1)戰(zhàn)略設(shè)計(jì)模式理論包括:識(shí)別領(lǐng)域、劃分子域、尋找核心域、支撐域和通用域、劃定限界上下文和建立上下文映射圖。戰(zhàn)略設(shè)計(jì)模式是系統(tǒng)的業(yè)務(wù)框架設(shè)計(jì),保證了領(lǐng)域模型的完整性。
(2)戰(zhàn)術(shù)設(shè)計(jì)模式理論主要包括:實(shí)體、值對(duì)象、聚合、識(shí)別領(lǐng)域事件等。戰(zhàn)術(shù)模式解決了領(lǐng)域的最小業(yè)務(wù)單元高內(nèi)聚[1]。
2? ? ? 技術(shù)發(fā)展分析
自Eric Evans提出新的軟件開發(fā)方法DDD后,在國(guó)內(nèi)外出現(xiàn)許多DDD理論的研究者和實(shí)踐者。
國(guó)外有許多專家對(duì)DDD的發(fā)展做出了卓越貢獻(xiàn),例如Greg Young對(duì)Betrand Meyer的CQS模式進(jìn)行改造,提出CQRS模式,Vaughn Verno完善了DDD思想,正式提出了領(lǐng)域事件模式以及六邊形架構(gòu)風(fēng)格實(shí)現(xiàn)DDD。
隨著國(guó)內(nèi)的互聯(lián)網(wǎng)公司逐漸深入實(shí)體經(jīng)濟(jì),業(yè)務(wù)日益復(fù)雜,領(lǐng)域模型在一個(gè)復(fù)雜的體系里變得尤為重要。國(guó)內(nèi)的盒馬鮮生已經(jīng)成功將DDD運(yùn)用到實(shí)際的開發(fā)中,在互聯(lián)網(wǎng)架構(gòu)下完整實(shí)施具有阿里特點(diǎn)的領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)模式。目前已經(jīng)有許多開發(fā)人員嘗試著將DDD應(yīng)用到銀行、航空、物流及信息系統(tǒng)等項(xiàng)目中,隨著云計(jì)算、微服務(wù)框架等新技術(shù)發(fā)展完善,DDD將有更多的應(yīng)用場(chǎng)景。
3? ? ? 必要性分析
“十二五”期間,許多電網(wǎng)企業(yè)信息化處于大建設(shè)期,與應(yīng)用系統(tǒng)的大規(guī)模建設(shè)的現(xiàn)實(shí)相適應(yīng),電網(wǎng)企業(yè)選擇成熟穩(wěn)定、為人熟知、IDE友好、便于共享、易于開發(fā)、部署和測(cè)試的單塊架構(gòu),采用傳統(tǒng)軟件開發(fā)方法開展企業(yè)級(jí)應(yīng)用建設(shè);上述模式在大建設(shè)期充分發(fā)揮了其自身特點(diǎn),促進(jìn)了電網(wǎng)企業(yè)應(yīng)用建設(shè)的迅速開展。
隨著業(yè)務(wù)的不斷擴(kuò)大,需求功能的持續(xù)增加,單塊架構(gòu)已經(jīng)很難滿足業(yè)務(wù)快速變化的需要。一方面,代碼的可維護(hù)性、擴(kuò)展性、靈活性在降低;而另一方面,系統(tǒng)的測(cè)試成本、構(gòu)建成本以及維護(hù)成本卻在顯著增加。因此,隨著項(xiàng)目或者產(chǎn)品規(guī)模的不斷擴(kuò)大,單塊架構(gòu)應(yīng)用的改造與重構(gòu)勢(shì)在必行。
4? ? ? 規(guī)劃方案
垂直拆分:依據(jù)領(lǐng)域驅(qū)動(dòng)理念,收集資料,了解系統(tǒng)背景,識(shí)別領(lǐng)域通用語(yǔ)言。識(shí)別領(lǐng)域,劃分子域,尋找核心域、支撐域和通用域,圍繞這些子域劃定限界上下文,建立上下文映射圖。以戰(zhàn)略模型為基石,進(jìn)行戰(zhàn)術(shù)建模:識(shí)別實(shí)體、值對(duì)象,劃分聚合,識(shí)別領(lǐng)域事件。戰(zhàn)術(shù)的成果幫助概念分離,分析設(shè)計(jì)原因和領(lǐng)域特征,厘清模型內(nèi)對(duì)象的關(guān)系、各種業(yè)務(wù)規(guī)則、數(shù)據(jù)一致性的設(shè)計(jì)以及測(cè)試用例的設(shè)計(jì)。
領(lǐng)域服務(wù)、倉(cāng)儲(chǔ)和工廠的設(shè)計(jì),幫助分離服務(wù)。以“低內(nèi)聚,高耦合”為原則,建立服務(wù)與服務(wù)之間的關(guān)系,實(shí)現(xiàn)事務(wù)的一致性。聚合內(nèi)的服務(wù)要求事務(wù)高度一致,關(guān)鍵聚合根的扭轉(zhuǎn)實(shí)現(xiàn)了動(dòng)態(tài)模型的設(shè)計(jì)。設(shè)計(jì)是否符合需求的場(chǎng)景要求,通過場(chǎng)景走查檢驗(yàn)一切的設(shè)計(jì)符合度和用戶體驗(yàn)度。
其總體設(shè)計(jì)如下圖所示:
4.1? ?資料收集
明確背景和定位,收集業(yè)務(wù)需求描述,繪制用例及核心業(yè)務(wù)流程圖。
4.2? ?識(shí)別通用語(yǔ)言
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的一個(gè)核心的原則是使用一種基于模型的語(yǔ)言。使用模型作為語(yǔ)言的核心骨架,要求團(tuán)隊(duì)在進(jìn)行所有的交流中都使用一致的語(yǔ)言,在代碼中也是這樣。在共享知識(shí)和推敲模型時(shí),團(tuán)隊(duì)會(huì)使用演講、文字和圖形。這兒需要確保團(tuán)隊(duì)使用的語(yǔ)言在所有的交流形式中看上去都是一致的,這種語(yǔ)言被稱為“通用語(yǔ)言”。
4.3? ?戰(zhàn)略建模
戰(zhàn)略建模是從宏觀的角度來劃分和集成限界上下文,它包括領(lǐng)域識(shí)別,子域及限界上下文劃分(分析出子域、核心域、支撐域)、上下文映射圖。
4.3.1? ?識(shí)別領(lǐng)域
一個(gè)領(lǐng)域本質(zhì)上就是一個(gè)問題域,只要是同一個(gè)領(lǐng)域,那問題域就相同。只有確定系統(tǒng)所屬的領(lǐng)域,才能進(jìn)而了解系統(tǒng)的核心業(yè)務(wù),即要解決的關(guān)鍵問題、問題的范圍邊界。
一個(gè)領(lǐng)域內(nèi)可以包含1個(gè)或者多個(gè)子域。子域又分核心域、支撐子域、通用子域。按照實(shí)際功能將這些交織的模型劃分成邏輯上相互分離的子域,從而在一定程度上減少系統(tǒng)的復(fù)雜性。
4.3.2? ?劃分子域
一個(gè)領(lǐng)域內(nèi)可以包含1個(gè)或者多個(gè)子域。理論上一個(gè)子域?qū)?yīng)一個(gè)限界上下文是最優(yōu)也是最理想的情況,但是有時(shí)又要考慮到業(yè)務(wù)關(guān)聯(lián)度需要做出權(quán)衡。子域又分核心域、支撐子域、通用子域。
4.3.3? ?尋找核心域、支撐域和通用域
所有子域按照子域類型的定義劃分成核心域、支撐域和通用域,具體的內(nèi)容如下:
核心域:它是整個(gè)業(yè)務(wù)領(lǐng)域的一部分,也是業(yè)務(wù)成果的主要促成因素。在實(shí)施DDD時(shí),主要關(guān)注的核心。
支撐域:對(duì)應(yīng)著業(yè)務(wù)的某些重要方面,但卻不是核心,那么他便是一個(gè)支撐子域。
通用域:如果一個(gè)子域被用于整個(gè)業(yè)務(wù)系統(tǒng),那么這個(gè)子域便是通用子域。
4.3.4? ?劃定限界上下文
限界上下文是一個(gè)由顯式邊界限定的特定職責(zé)。領(lǐng)域模型存在于邊界之內(nèi)。在邊界內(nèi),每一個(gè)模型概念,包括屬性和操作,都具有特殊的含義。
一個(gè)業(yè)務(wù)領(lǐng)域包含多個(gè)限界上下文,與一個(gè)限界上下文溝通,需要通過顯式邊界進(jìn)行通信。系統(tǒng)通過確定的限界上下文解耦,每一個(gè)上下文內(nèi)部緊密組織,職責(zé)明確,具有較高的內(nèi)聚性。
4.3.5? ?劃分聚合
與值對(duì)象相反,聚合是實(shí)體的合并。聚合是一組相關(guān)對(duì)象的集合,我們把它作為數(shù)據(jù)修改的單元。一個(gè)聚合包括至少兩個(gè)實(shí)體與一個(gè)根, 根包含了聚合內(nèi)所有實(shí)體的引用,并作為聚合的代表供外界訪問,外界只能通過根來訪問聚合內(nèi)的實(shí)體,而聚合內(nèi)的實(shí)體之間可以隨意互相訪問。包含在聚合內(nèi)的實(shí)體構(gòu)成了一個(gè)整體,當(dāng)聚合消亡時(shí),它們也將隨之消亡。聚合使得實(shí)體間的關(guān)系網(wǎng)大大簡(jiǎn)化了,聯(lián)系緊密的實(shí)體可以被放入聚合內(nèi)部封裝起來,聚合之間的聯(lián)系則通過根變得清晰而有條理[2]。
4.3.6? ?識(shí)別領(lǐng)域事件
領(lǐng)域事件定義領(lǐng)域?qū)<宜P(guān)心的事件的對(duì)象。當(dāng)關(guān)心的狀態(tài)由于模型行為而發(fā)生改變時(shí),系統(tǒng)將發(fā)布領(lǐng)域事件。
4.3.7? ?模型詳細(xì)說明
模型詳細(xì)說明主要描述了設(shè)計(jì)的原因、模型內(nèi)對(duì)象的關(guān)系、各種業(yè)務(wù)規(guī)則、數(shù)據(jù)一致性規(guī)則、測(cè)試用例等。
(1)緩存存儲(chǔ)。緩存是領(lǐng)域?qū)ο笤趦?nèi)存中的生存場(chǎng)所,是一種面向業(yè)務(wù)的存儲(chǔ)方式,而同時(shí)我們的領(lǐng)域模型也是一種面向業(yè)務(wù)的模型,有了面向業(yè)務(wù)的存儲(chǔ)以后,我們就可以進(jìn)行面向業(yè)務(wù)的運(yùn)算,而正是這種面向業(yè)務(wù)的運(yùn)算使得我們的系統(tǒng)具有更好的伸縮性和擴(kuò)展性。因?yàn)榇藭r(shí)的領(lǐng)域?qū)ο笸ㄟ^緩存都是跑在中間件中,而在負(fù)載增多的時(shí)候,通過水平的增加中間件服務(wù)器來進(jìn)行水平伸縮。
(2)數(shù)據(jù)庫(kù)設(shè)計(jì):①打破外鍵關(guān)系。讓一個(gè)服務(wù)的代碼通過另一個(gè)服務(wù)暴露的API來訪問數(shù)據(jù),而不是直接訪問數(shù)據(jù)庫(kù)。這個(gè)API調(diào)用會(huì)成為微服務(wù)化的第一步。這時(shí)候可能會(huì)有性能擔(dān)憂,可以做一個(gè)性能測(cè)試,如果這個(gè)“慢”在可接受的范圍內(nèi),就沒有問題。②共享靜態(tài)數(shù)據(jù)。把一些些共享的靜態(tài)數(shù)據(jù)放入代碼,比如放在屬性文件中,或者簡(jiǎn)單地放在一個(gè)枚舉中。③共享數(shù)據(jù)。共享的可變數(shù)據(jù)對(duì)于分離系統(tǒng)來說通常是一個(gè)麻煩。領(lǐng)域概念不是在代碼中進(jìn)行建模,相反是在數(shù)據(jù)庫(kù)中隱式地進(jìn)行建模,這里缺失的領(lǐng)域概念是中間服務(wù)。④共享表。兩個(gè)業(yè)務(wù)共用一個(gè)表,但是每個(gè)業(yè)務(wù)的關(guān)注點(diǎn)不同,我們可以采取行動(dòng)把它們存儲(chǔ)在不同的上下文中,從而分離出兩張表,分別在對(duì)應(yīng)的兩個(gè)服務(wù)中。各自依據(jù)各自的關(guān)注點(diǎn)來建表結(jié)構(gòu),進(jìn)行表建模。
(3)事務(wù)邊界的處理。事務(wù)控制需要注意的事項(xiàng):①在事務(wù)中,不要運(yùn)行昂貴而不必要的、與事務(wù)無關(guān)的操作指令,如日志記錄,其磁盤讀寫代價(jià)高,非常消耗資源。②不要在瀏覽數(shù)據(jù)的時(shí)候打開事務(wù)(設(shè)置值@TransactionAttribute(NOT_SUPPORTED))。
事務(wù)控制的邊界位于服務(wù)層。事務(wù)邊界的處理主要有以下幾種方式:
①再試一次??梢詫?duì)某一個(gè)業(yè)務(wù)先做一次操作,操作終止后,再對(duì)另一個(gè)業(yè)務(wù)做另一次操作,這時(shí)可以把這部分操作放在一個(gè)隊(duì)列或者日志文件中,之后再嘗試對(duì)其進(jìn)行觸發(fā)。對(duì)于某些操作來說這是合理的,但要保證重試能夠修復(fù)這個(gè)問題。②終止整個(gè)操作。另一個(gè)選擇是拒絕整個(gè)操作。在這種情況下,需要把系統(tǒng)重置到某種一致的狀態(tài),要么重試補(bǔ)償事務(wù),要么使用一些后臺(tái)任務(wù)來清除這些不一致的狀態(tài)??梢越o后臺(tái)的維護(hù)人員提供一個(gè)界面來進(jìn)行該操作,或者將其自動(dòng)化。③使用分布式事務(wù)。手動(dòng)編配補(bǔ)償事務(wù)非常難以操作,一種替代方案是使用分布式事務(wù)。分布式事務(wù)會(huì)橫跨多個(gè)事務(wù),然后使用事務(wù)管理器的工具來統(tǒng)一編配其他底層系統(tǒng)中運(yùn)行的事務(wù)。就像普通的事務(wù)一樣,一個(gè)分布式的事務(wù)會(huì)保證整個(gè)系統(tǒng)處于一致的狀態(tài)。唯一不同的是,這里的事務(wù)會(huì)運(yùn)行在不同系統(tǒng)的不同進(jìn)程中,通常它們之間使用網(wǎng)絡(luò)進(jìn)行通信。
(4)測(cè)試用例。微服務(wù)架構(gòu)中的測(cè)試類型主要包括:?jiǎn)卧獪y(cè)試、接口測(cè)試、集成測(cè)試、組件測(cè)試和端到端測(cè)試。
(5)模塊、倉(cāng)儲(chǔ)、工廠、領(lǐng)域服務(wù)。①模塊:模塊為人們提供了兩種觀察模型的方式,一是可以在模塊中查看細(xì)節(jié),而不會(huì)被整個(gè)模型淹沒,二是觀察模塊之間的關(guān)系,而不考慮其內(nèi)部細(xì)節(jié)。模塊之間應(yīng)該是低耦合的,而在模塊內(nèi)部則是高內(nèi)聚的。模塊并不僅僅是代碼的劃分,而且也是概念的劃分。②倉(cāng)儲(chǔ):倉(cāng)儲(chǔ)是一組負(fù)責(zé)領(lǐng)域?qū)ο蟮某志没姆?wù)。從架構(gòu)角度來看,倉(cāng)儲(chǔ)用于連接領(lǐng)域?qū)雍突A(chǔ)結(jié)構(gòu)層,領(lǐng)域?qū)油ㄟ^倉(cāng)儲(chǔ)訪問存儲(chǔ)機(jī)制,而不用過于關(guān)心存儲(chǔ)機(jī)制的具體細(xì)節(jié)。按照DDD設(shè)計(jì)原則,倉(cāng)儲(chǔ)的作用對(duì)象的領(lǐng)域模型的聚合根,也就是說每一個(gè)聚合都有一個(gè)單獨(dú)的倉(cāng)儲(chǔ)[3]。③工廠:工廠模式(Factory Pattern)是Java中最常用的設(shè)計(jì)模式之一,在DDD中也被廣泛使用,它是一種體現(xiàn)封裝思想的設(shè)計(jì)模式。工廠的作用是將創(chuàng)建對(duì)象的細(xì)節(jié)隱藏起來,當(dāng)創(chuàng)建一個(gè)對(duì)象時(shí),如果創(chuàng)建工作很復(fù)雜,或者暴露了過多的內(nèi)部結(jié)構(gòu),則可以使用工廠進(jìn)行封裝。事實(shí)上除了通過工廠來創(chuàng)建對(duì)象,大部分情況下領(lǐng)域?qū)ο蟮膭?chuàng)建都不會(huì)太復(fù)雜,所以我們只需要簡(jiǎn)單地使用構(gòu)造函數(shù)創(chuàng)建對(duì)象就可以了。④領(lǐng)域服務(wù):當(dāng)領(lǐng)域中的某個(gè)操作過程或轉(zhuǎn)換過程不是實(shí)體或值對(duì)象的職責(zé)時(shí),便應(yīng)該將該操作放在一個(gè)單獨(dú)的接口中,即領(lǐng)域服務(wù)。如果勉強(qiáng)地把這些重要的領(lǐng)域功能歸為實(shí)體或值對(duì)象的職責(zé),那么不是歪曲了基于模型的對(duì)象的定義,就是人為地增加了一些無意義的對(duì)象。應(yīng)確保領(lǐng)域服務(wù)和通用語(yǔ)言是一致的,并且保證它是無狀態(tài)的[4]。
(6)動(dòng)態(tài)模型設(shè)計(jì)。動(dòng)態(tài)模型設(shè)計(jì)包括業(yè)務(wù)流程設(shè)計(jì)、設(shè)計(jì)關(guān)鍵聚合根的狀態(tài)流轉(zhuǎn)圖。
(7)場(chǎng)景走查。確定領(lǐng)域模型、領(lǐng)域服務(wù)、倉(cāng)儲(chǔ)等完成系統(tǒng)用例以及關(guān)鍵業(yè)務(wù)流程,確認(rèn)領(lǐng)域模型是否能滿足領(lǐng)域中的業(yè)務(wù)場(chǎng)景和業(yè)務(wù)流程。
最常用的就是通過序列圖來走查場(chǎng)景,對(duì)創(chuàng)建的領(lǐng)域模型進(jìn)行逐步驗(yàn)證。
(8)實(shí)現(xiàn)架構(gòu)設(shè)計(jì)。依據(jù)前面的所有分析和設(shè)計(jì),最終實(shí)現(xiàn)架構(gòu)設(shè)計(jì)。部署打包方式為:Jenkins自動(dòng)化打包,實(shí)現(xiàn)持續(xù)集成與發(fā)布。
5? ? ? 結(jié)? ? 語(yǔ)
電網(wǎng)企業(yè)業(yè)務(wù)復(fù)雜,應(yīng)用系統(tǒng)較多,本文提出的應(yīng)用系統(tǒng)服務(wù)化改造方法作為一種指導(dǎo)思想,可以有序推動(dòng)大型電網(wǎng)企業(yè)的IT架構(gòu)升級(jí),確保IT建設(shè)資產(chǎn)與實(shí)際業(yè)務(wù)的符合,有效支撐企業(yè)業(yè)務(wù)運(yùn)轉(zhuǎn),完成從企業(yè)信息化到信息化企業(yè)的跨越,最終打造安全、可靠、綠色、高效的智能電網(wǎng)。
主要參考文獻(xiàn)
[1][美]Eric Evans.領(lǐng)域驅(qū)動(dòng)設(shè)計(jì): 軟件核心復(fù)雜性應(yīng)對(duì)之道[M].修訂版.趙俐,譯. 北京:人民郵電出版社,2016.
[2][美]Vaughn Vernon.實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)[M]. 滕云,譯. 北京: 電子工業(yè)出版社,2014.
[3]黃文光,金義富. 基于領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)構(gòu)建企業(yè)級(jí)Web平臺(tái)的應(yīng)用[J]. 實(shí)驗(yàn)室研究與探索,2013,32(8):72-75.
[4]王忠,程磊. 基于領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的軟件開發(fā)[J]. 軟件導(dǎo)刊,2008, 7(2):37-39.