當前位置:
首頁 > 最新 > 基於領域驅動模型的園區系統設計

基於領域驅動模型的園區系統設計

1、背景

就在近幾年「DDD+微服務架構」逐漸成為各大小互聯網公司青睞的開發設計方式。

DDD的核心述求就是將業務架構映射到系統架構上,在因業務變化而調整業務架構時,能夠把變化範圍僅僅控制在對應系統架構的限界上下文(BC)內,從而提高業務領域內代碼的可維護性和可擴展性。

微服務架構強調「化整為零,逐個擊破」,把龐大複雜的系統進行微服務拆分,每個服務包含一組特定、相關功能的實現。但是微服務架構本身是一把雙刃劍:濫用微服務架構,會為之付出昂貴的維護代價;而合理的劃分服務是關鍵,劃分好了就能夠受益於微服務的諸多優點,比如隔離性、單一職責的可擴展性、開發高效性等。恰巧DDD為微服務架構提供了劃分服務設計的理論基礎。

因此,儘管DDD(Domain Driven Design,領域驅動設計)和服務化都不是新概念,但是二者組合起來就能顯現出「雙劍合璧,萬邪不侵」的神威了。

隨著園區業務規模的擴大,園區系統在快速的迭代功能需求,隨之將來系統會承載越來越複雜的功能邏輯、需要處理越來越大的數據量。而老園區系統是一個傳統的三層架構的單體應用(有部分功能服務化),在這種架構下有著肥胖臃腫的服務層、有著冗餘的DAO層。程序員們在應付新迭代的需求變更和功能擴展時,都不得不先做三遍深呼吸再從臃腫的Service代碼中尋找突破口。

GIF

如此看來,當前基於領域驅動設計對園區系統進行重構工作已經是了勢在必行了,DDD可以為微服務架構打好基礎,在將來系統的複雜程度和系統規模擴大後,進一步對系統進行微服務化拆分會非常便利。

一般來說領域建模的體系化解決方案步驟分為4步:

首先要了解產品戰略,產品戰略決定產品組合,而產品組合決定用例集合。

進行業務建模也就是找出問題空間模型,包括業務概念模型、業務概念之間的關聯以及業務領域邊界。

進行系統建模即建立解決方案空間模型,包括找出領域類、類的職責分配和系統邊界、並找出類之間的關聯。

就是對數據進行建模,包括關係數據模型、非關係數據模型、分表分庫等等。

本文先按照文中提到的前3步來闡述園區系統的領域服務設計,對於本文未詳盡的設計會在後續的文章中繼續完善。

2.園區系統的戰略分析

進行領域建模首先從園區的戰略討論起,戰略通常是對基於以下幾個問題的分析而得出的。

2.1 應用系統為誰而做的?

園區應用系統主要幫助園區業主做好規範化的訪客和車輛的出入園管理及園內車輛調度管理的業務管理。

2.2它解決了哪些問題?

園區系統提供對進入園區的訪客進行登記管理;對出入園區的車輛進行登記、預約、調度等功能,從而使得園區業主和園區租戶能夠及時了解進出園區車輛的實時信息,並對其進行有效的管控,保證園區在安全、有序的情況下正常運轉。

一方面通過園區系統的信息自動化處理能力,能縮減園區業主在安保方面的人力資源;

另一方面,園區系統也通過微信公眾號、租戶APP為司機和園區租戶建立了線上交互的通道,從而使得租戶能夠對提貨送貨車輛進行電子化管理,提高租戶的工作效率。

此外,隨著園區內的車輛信息數據以及人員信息數據逐步沉澱,系統還可以再基於對數據的統計分析,進一步擴展其他對園區有益的增值業務,例如幫租戶招工、介紹司機拉貨等,當然鋪設的園區足夠多,數據量足夠大才有足夠的想像空間,先打好基礎加油鋪系統吧:)。

2.3 何時需要他以及為什麼需要它?

對於管理規範的園區都會做對出入園區的人員、車輛可知可控的安保工作。目前還存在不少管理不規範的園區,他們的安保工作通常是形同虛設,一旦出了安全事故通常都不可追溯,這會嚴重影響到園區的聲譽,從而也會直接影響到園區的經濟效益。

隨著電商業務的發展,物流業務和園區業務也逐漸繁忙,規範化的園區管理必然是大趨勢,際鏈園區系統可以為管理規範的園區提供標準且可定製的自動化出入園管理方案,提高管理效率;也能為還未進行規範化管理的園區提供可借鑒的標準化出入園管理解決方案,降低他們的學習成本並縮短推行規範工作的周期。

2.4 它是如何工作的?

園區系統由伺服器端應用、租戶APP、物業APP和微信公眾號幾部分功能組成。

伺服器端應用:面向的主要用戶是園區業主、園區租戶和系統管理員。

系統提供了錄入園區、租戶初始化基本數據的界面,可以在web端定製園區的管理規則;

系統還提供了對出入園區的人員、車輛信息的實時查詢以及車輛預約、場站調度等實時業務處理的功能;

系統還提供了對出入園的人員、車輛信息的歷史數據的統計分析功能,以及基於此擴展的其他業務功能。

物業APP:面向的主要用戶是園區門口的安保人員。安保人員基於此app監控園區內的實時車輛情況、進行車輛登記,可以通過APP了解到進出園區的車輛到門口前的登記信息、預約信息以及調度相關信息。基於APP上看到的信息信息,安保人員可以很方便的對進出的車輛做出決策進行管控。

租戶APP:面向的主要用戶是園區內的租戶。他們使用該APP可以對來訪問自己的人員車輛進行進出授權,此外基於該APP還可以獲得園區系統針對租戶的其他服務,例如倉配相關的需求等。

微信公眾號:主要面向訪問園區的到訪人員和司機。他們可以在微信公眾號上獲得出入園申請、查看預約信息、獲取調度通知等服務,能夠及時與園區和租戶進行交互並獲得反饋,從而能夠方便快捷的進出園作業。

2.5 戰略分析小結

總結而言,園區系統的戰略映射到業務領域可以分為兩大方面:

一方面是通過先進的軟硬體技術(如智能道閘、IoT方案以及AI技術等)為服務園區業主和園區租戶提供一套規範化、自動化的園區人員及車輛的管控和調度服務管理解決方案,提高物流園區及各類生產園區管理的現代化和規範化水平並降低園區管理成本。當前團隊正在研發的業務用例集合就體現在這一方面。

另一方面,隨著園區系統業務規模的增大,系統將會沉澱大量的到訪園區的車輛信息、司機信息、到訪人員等數據,基於這些資源數據的統計分析也可能為園區運營擴展出其他的增值業務。園區系統未來將會研發的重點業務用例集合就體現在這一方面。

至此第一步的任務已經完成。

3、業務領域建模

本小節進入領域設計的第二步:對園區系統進行業務領域建模,找出業務概念和業務之間的關聯和業務領域邊界。

根據上一節中的戰略分析可知園區系統分為兩大業務領:

一是為園區提供服務的業務領域;

二是基於數據分析的運營及其他可增值業務領域。

目前園區團隊已經開發完成了第1個業務領域,只是還有待進一步完善。如圖2-1綠色部分所示這個業務領域可以被劃分成3個子領域:園區實時業務子領域、園區基礎數據子領域、用戶中心子領域。

圖2-1:園區業務系統子領域

3.1 園區系統基礎數據子領域

園區基礎配置上下文:包括園區基本信息、大門信息、道閘信息、倉庫信息、車位、園區業務配置等等。該子領域的防腐層(ACL)對外提供基礎數據的訪問能力。

物業/園區租戶基礎數據上下文:包括物業基本信息、園區租戶基本信息、租戶的業務配置。該子領域的防腐層(ACL)對外提供基礎數據的訪問能力。

系統用戶及組織機構機構上下文:系統用戶和組織機構主要是調用用戶中心的服務實現的,圖中單獨畫了一個用戶中心子領域。而園區基礎數據上下文和物業/園區租戶基礎數據上下文對此都是強依賴(CF)關係。

3.2 園區實時業務子領域

出入園管理上下文:包括基於配置的出入園放行邏輯、拍照上傳邏輯、微信端登記、PAD端出入園登記/排隊、出門條管理及授權以及人員登記。出入園放行的邏輯依賴於(CF)園區基礎配置上下文和物業/園區租戶基礎數據上下文。

預約管理上下文:車輛入園預約、微信端的預約信息、結合調度信息的擴展預約。

預約管理的處理邏輯依賴於(CF)租戶的基礎設置數據;

車輛預約之後可以入園作業,因此預約管理上下文與出入園管理上下文有上下游依賴(CSD)關係

預約的車輛可以參與園區內的場站監控/調度,因此預約管理上下文與場站監控/調度上下文有上下游依賴(CSD)關係。

場站監控/調度管理上下文:車位監控、調度管理,該子領域一定程度上依賴於預約和出入園管理子領域。場站監控/調度管理主要是對在園車輛以及待入園車輛的調度管理,因此場站監控/調度管理上下文與出入園管理上下文有上下游依賴(CSD)關係。

3.3 數據分析及擴展業務子領域

業務數據管理和分析上下文:包括沉澱園區內人、車信息數據,對單園區內人、車到訪各租戶的情況分析,以及針對系統內所有園區的人、車信息的統計分析。這些對數據的統計分析可以用於支撐運營決策以及其他擴展業務,因此該上下文與基於數據擴展的增值業務上下文具有上下游依賴(CSD)的關係。

基於數據擴展的增值業務上下文:有了數據可以想像的業務空間就大了,例如可以搭建園區租戶的用人、用車需求與起關注園區公眾號的到訪的工人或司機的匹配橋樑,等等。

4、系統建模

本小節進入領域設計的第三步:對園區系統進行系統建模,分析出各個子領域內的聚合根、值對象、實體對象和領域服務,進一步劃分出應用層和領域層的分工。

園區系統的基礎數據領域內的實體相關性較小,目前基本穩定了,這裡就不做詳細分析了。

本文重點對目前正在開發完善過程中的園區實時業務領域進行分析建模,以期將來根據分析結果進一步重構和完善現有的園區代碼,實現園區系統核心代碼按照應用層和領域層分層,使得代碼按照業務領域解耦。一方面可以提高各個業務領域的擴展性;另一方面若將來園區系統的複雜度擴展到一定程度時候,也便於開發者進行微服務拆分。

圖3-1:明細的園區實時業務上下文

4.1 領域服務之出入園管理限界上下文:

園區的安保管控,無非是對到訪的人和車信息進行管理,據此可以分兩類領域服務:訪客出入管理領域服務和車輛管理領域服務。園區車輛管理涉及到園區內的場地佔用,一方面要對進出園區的車流量進行記錄和管控,另一方面又要服務於租戶和司機,為他們提供便捷的出入園管理服務,據此又可以將園區車輛管理領域服務分為出入園管理領域服務和出入園相關其他業務領域服務。出入園管理上下文的領域服務、實體和聚合根劃分如圖3-1左側所示。

車輛出入園記錄是一個聚合根,車輛入園信息實體、車輛出園信息實體和車輛登記信息實體都是對應著一條車輛出入園記錄實體。

訪客出入園管理領域服務(VisitorService)會包含對訪客人員信息實體和訪客登記記錄實體的操作。

車輛出入園管理領域服務(VechileInOutService)會基於車輛黑名單實體、車輛白名單實體、園區進出園規則設置實體、租戶進出園規則設置實體實現在園區門口的車輛出入園規則,同時會管理車輛基本信息實體和車輛進出園記錄聚合根。

出入園相關其他業務領域服務(InoutBizService)則會處理園區內外的相關業務如排隊叫號、授權出園等,主要涉及到排隊號實體和授權出園信息實體。

4.2 領域服務之預約管理限界上下文:

園區內的預約管理包括租戶預約管理、普通的入園預約管理以及根據租戶第三方系統調度信息擴展的預約服務。具體的實體和領域服務劃分如下(詳見圖3-1右上角):

租戶預約設置信息實體:包含對各類預約服務的靈活配置。

預約管理領域服務(ReserveBizService):預約領域服務處理對以上各類預約服務相關的操作,包括操作預約信息實體、基於預約的調度實體、預約消息通知實體等

4.3 領域服務之場站監控及調度限界上下文:

場站監控及調度是園區業務的重點服務,隨著各物流園區的現代化程度提高、園區引入更多的IoT設備,這個服務的複雜程度也會提高。現階段該上下文的領域服務和實體劃分如下詳見圖3-1右下角):

功能區實體:包括功能區的基本信息及監控信息;

車位實體:包括車位的基本信息及監控信息;

車輛調度記錄實體:基於功能區和車位佔用情況發起的調度信息;

場站監控調度目前包括場站調度領域服務(DispatchBizService):該領域服務會根據從出入園管理上下文中獲取的園區及住戶的調度配置,基於功能區、車位的監控信息和進行車輛調度管理。

5. DDD的園區系統分層架構設計

根據上述幾個小節的分析,園區系統的領域服務層已經比較清晰了。下一步就可以整理出如何將老園區系統的傳統三層架構轉換成基於領域驅動設計的分層結構,以及每一層具體的分工。

5.1 老園區系統的結構和存在的問題

如圖5-1所示左側,老園區系統是傳統的三層架構:DAO層、Service層和Controller層,存在的不同類型的業務邏輯代碼的毫無規則的混雜在不同的Service類中,造成維護和擴展困難的問題。具體分析如下:

Controller層,調用Service層的介面組合面向表現層的業務流程,對外提供介面。

Entity層:系統的Entity層僅僅是包含業務對象的屬性和getter、Setter方法,是點醒的「失血模型」,僅僅作為Controller層和Service層傳遞參數的對象。

Service層,負責所有的業務邏輯實現,園區系統基本上是每一個Service類對應一個DAO類,每一個DAO類對應一個數據表。而主要問題就是出在這一層——大多Service都是「名不符實」的,導致維護和擴展困難。

因為多數業務邏輯都是需要處理若干個表的數據,從名稱看Sevice是對應一個數據表相應的實體,但是該Service里會注入若干個其他Service實例和若干個DAO實例,並且這些Service類中會毫無規則的混雜著若干業務領域的邏輯。在開發階段,多個開發者同時開發時,可能會在不同的Service類中用不同的方法寫同樣的邏輯,造成代碼冗餘,可維護性不好。「鐵打的銀盤,流水的兵」,若系統開發階段的人和後期系統維護和擴展階段不是同一撥人,維護者去找修改或者擴展代碼時會覺得找到散落在各個Service的同一類業務邏輯會比較困難,即使找到了代碼,想要擴展代碼也是難於下手的。

DAO層,基本上是按照每個實體表對應一個DAO類,但是若其對應Service需要處理多個數據實體的數據,DAO層中也可能會「名不副實」的處理多個數據表中的數據,但是同Service層面臨的問題一樣因為沒有一個具體的規則,以後擴展和維護都會比較困難。

圖5-1:基於DDD重構改造老園區系統的分層架構

5.2 基於DDD的園區系統分層結構設計

針對上一小節提到的老園區系統維護和擴展困難的問題,可以通過基於領域驅動設計的方式解決。對園區系統進行改造按照DDD的4層結構設計,如如圖5-2右側所示:

UI層:對應於老園區的Controller層,它仍然負責組合面向表現層的業務流程,以RestFul形式對外提供API介面。根據對外暴露的介面類型不同,它可以分別調用Application層的服務、Domain Service層的服務以及Infrastructure層的服務。

Application層:負責跨子領域協作的業務邏輯或者非業務領域的業務邏輯,一般來說是通過DTO對象與UI(Controller)層進行交互。

一般來說跨子領域的業務邏輯寫在Application層:例如涉及到跨預約子領域和場站調度子領域的業務邏輯,不需要寫到二者的Domain Service層,可以在Application層進行組合邏輯,這樣代碼層次分工會比較清晰。

非業務領域的業務邏輯,例如微信token的緩存和同步更新、微信程序版本管理等功能。

Domain Service層:這一層中包括充血行模型的領域實例、值對象及領域服務。若不需要跨領域組合邏輯,UI層(Controller)可以直接調用這一層的服務通過DO對象進行交互。

充血型領域實例:實例對象中不僅包含getter、setter方法還包含限界上下文中的所有相關業務邏輯,這樣職責分明了,一個領域實例也名至實歸了。將來維護、擴展代碼事,只要清晰了解限界上下文就很容易找到代碼的邏輯並進行擴展。

子領域服務:對於需要跨領域實例完成的業務邏輯,可以放在子領域服務中。

聚合根:把一組相關對象的集合,作為一個整體被外界訪問,例如園區系統里的出入園記錄就是一個聚合根,入園信息、出園信息以及登記信息都是對應一條出入園記錄的。

Infrastructure層:這一層包括與領域實體、值對象和領域服務想對於的Repository層以及通用的基礎服務。這一層需要定義介面,將Repository資源注入到Service層,避免上而下的級聯修改。

Repository資源庫:Repository對應的是領域實例、值對象或者子領域服務,子領域服務可能對應的是多個數據表實體的數據操作,因此可能被注入多個DAO。相對而言比DAO方法是細粒度的,更接近資料庫,而Repository資源庫的方法的粒度粗一些,更接近領域。

通用的基礎服務:包括基礎框架以及獲取登錄系統用戶信息、消息隊列處理、文件上傳服務等通用服務。

設計過程中需要注意的事項:

對於領域中可能會影響多個其他業務領域的邏輯最好提供Domain Event(領域事件),例如本系統中的出入園記錄的更新就會影響到很多業務包括登記狀態的變更、預約狀態變更、場站調度及園區實時監控和統計數據等,因此對於出園和入園都應用定義領域事件。

分層設計時,應盡量保持層間的隔離,僅使用下層提供的介面,例如可通過依賴倒置來避免自上而下的級聯修改。

分層實現時,注意按照領域設計規則明確各層的分工,避免把領域服務泄露到應用層。

把高度相關的實體封裝到聚合中,為每個聚合根創建一個倉儲,例如文中提到的出入園記錄和入園信息、出園信息和登記信息就是共用一個倉儲。

跨領域或服務之間傳輸數據一般採用DTO對象。

5.3 園區系統的服務化架構

園區系目前是基本上屬於一個單體架構,對於需要提供給外部的服務統一包裝成一個SpringCloud服務暴露出去。目前基於領域驅動設計可以大體按照業務領域分為出入園管理、場站調度和預約三大業務領域。現階段出入園及預約管理的功能範圍基本比較穩定了可以劃分為一個服務。隨著園區的先進化程度的提高,園區內會引入一系列IoT設備和解決方案,基於IoT的場站調度管理將會是近期的發展重點會做大量的擴展工作,因此考慮把場站調度作為獨立的服務。隨著園區系統的鋪設規模擴大和數據量積累,基於數據分析的運營及其他擴展業務會成為重點,因此考慮把數據分析處理及其他擴展業務獨立成一個服務。

考慮到網路狀況不同,為了提高現場工作效率,目前園區現場的物業APP同時支持調用區域網介面和外網介面,目前在agent端和server端有兩套冗餘的介面。服務化改造後考慮把agent端的服務也註冊到Eureka中,無論物業APP走區域網還是Internet訪問都訪問agent提供的服務。

圖5-2 園區系統服務化架構

6、小結

本文分析了老園區系統存在因架構陳舊帶來的維護難、擴展難的問題,提出了基於DDD進行重構的解決方案。從園區系統的戰略分析開始,根據戰略進行了園區系統的業務領域建模和系統建模,逐步呈現了對園區系統進行領域驅動設計的全過程。並且本文對園區系統的下一步服務化改造做出了初步的設計。

7.附錄:領域服務基礎知識

DDD(Domain Driven Design,領域驅動設計)是一種可以幫助開發者設計高質量的軟體模型的軟體開發方法。它的核心述求就是將業務架構映射到系統架構上,在因業務變化而調整業務架構時,能夠把變化範圍僅僅控制在對應系統架構的限界上下文(BC)內,從而提高業務領域內代碼的可維護性和可擴展性。

DDD分層設計:

一般來說DDD的分層架構分為四層:UI層、應用層、領域服務層、基礎設施層:

UI層(或表示層):負責向用戶顯示信息和解釋用戶命令。這裡指的用戶可能是另一個系統,不一定是人。

應用層:定義軟體要完成的任務,並且指揮表達領域概念的對象來解決問題。需要注意的是這一層不包含業務規則或者知識,而只是調用下一層中的領域對象或領域服務,也可以實現跨領域、跨實體的協作。

領域服務層(或模型層):負責表達業務概念,業務狀態信息以及業務規則。它是領域層是業務軟體的核心,領域模型位於這一層。

基礎設施層:向其他層提供通用的技術能力,為應用層傳遞消息,為領域層提供持久化機制等等。基礎設施層還能夠通過架構框架來支持四個層次間的交互模式。

幾個相關的概念:

充血模型:是指領域實體中包含了所有的業務邏輯,包括依賴於持久層的業務邏輯。簡單表示就是 UI層->服務層->領域層->持久層。

失血模型:模型僅僅包含數據的定義和getter/setter方法,業務邏輯和應用邏輯都放到服務層中。

領域實體:有唯一標識的領域概念。需要說明的是領域實體不同於我們傳統三次架構(WEB層、Service層、DAL層)中的實體概念,傳統架構中的實體只是用來裝數據的容器,而領域實體中是內聚的業務邏輯。

值對象:當一個對象用於對事務進行描述而沒有唯一標識時,被稱為值對象(值對象創建後就不能修改,不允許被外部修改),謹慎使用值對象,可能將來會需要唯一標識。

聚合根:就是一組相關對象的集合,作為一個整體被外界訪問。

領域服務:領域中的一些概念不太適合建模為對象,即歸類到實體對象或值對象,因為它們本質上就是一些操作,一些動作,而不是事物。這些操作或動作往往會涉及到多個領域對象,並且需要協調這些領域對象共同完成這個操作或動作。採用微服務架構風格,一切領域邏輯的對外暴露軍需要通過領域服務來進行。

領域事件:是對領域內發生的活動進行建模。

限界上下文之間的映射關係:

合作關係(Partnership):兩個上下文緊密合作的關係,一榮俱榮,一損俱損。

共享內核(Shared Kernel):兩個上下文依賴部分共享的模型。

客戶方-供應方開發(Customer-Supplier Development):上下文之間有組織的上下游依賴。

遵奉者(Conformist):下游上下文只能盲目依賴上游上下文。

防腐層(Anticorruption Layer):一個上下文通過一些適配和轉換與另一個上下文交互。

開放主機服務(Open Host Service):定義一種協議來讓其他上下文來對本上下文進行訪問。

發布語言(Published Language):通常與OHS一起使用,用於定義開放主機的協議。

大泥球(Big Ball of Mud):混雜在一起的上下文關係,邊界不清晰。

另謀他路(SeparateWay):兩個完全沒有任何聯繫的上下文。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 全球大搜羅 的精彩文章:

馬蓉對二審判決感到失望,採訪中爆王寶強與美女過七夕,稱有證據
丹麥vs袋鼠軍團

TAG:全球大搜羅 |