Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 亚洲精品免费视频,91精品国产91,成人欧美一区二区三区黑人3p

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          如何從0到1實踐DDD

          輯導語:DDD(Domain-driven design,領域驅動設計)是一種架構設計方法論,通過邊界劃分,將復雜業務領域簡單化,幫助我們設計出清晰的領域和應用邊界,保證業務模型與代碼模型的一致性。本文作者結合實際經驗,介紹了如何從0到1實踐DDD,一起來看看吧。

          隨著業務的不斷發展,我們發現自己的系統開始變得有點臃腫,為了減少復雜性,我們嘗試借助DDD來改善我們的系統。本文記錄了自己對DDD的理解和實踐過程,歡迎大家一起探討。見識所限,難免有理解不到位,希望路過的大佬不吝賜教。

          一、為什么需要DDD

          • 當朋友和你聊工作時,你能否一語中的,說清你在開發中的業務內容及其價值?
          • 當產品和你聊需求時,你是否遇到過反復溝通之后才發現講的不是同個東西的情況?
          • 當你在做需求評估時,你是否經常發現一個小的需求改動,總是牽一發動全身?
          • 當你在快樂寫代碼時,你是否經常覺得有些類可有可無,有些接口望文不知義?

          如果你有以上的一些疑問,那你可以試試領域驅動設計:

          DDD(Domain-driven design,領域驅動設計)是一種架構設計方法論,通過邊界劃分,將復雜業務領域簡單化,幫助我們設計出清晰的領域和應用邊界,保證業務模型與代碼模型的一致性。

          在細看這個定義之前,我們可以思考一下,為什么我們的業務系統會慢慢變得復雜?

          常見的情況是,業務在發展過程中為了探尋發力點,需要不斷地試錯迭代,調整方向,而系統在設計之初,難以預期到后面的瞬息萬變,為了應付業務,修修改改,久之,系統也變得復雜起來。

          可以怎么辦呢?及時重構唄——不改變軟件系統外部行為的前提下,改善它的內部結構。

          然而重構是從技術層面上抽煉出來的模型,往往不具有實際的業務含義,其他同學可能難以自然地將業務問題映射到對應的設計模型。另外,如果不能如實映射業務模型,隨著業務方向調整,代碼可能又開始腐敗……有點像芝諾悖論中,阿基里斯永遠追不上小烏龜。

          那DDD怎么搞?

          DDD是這么想的:”將業務架構映射到系統架構上,在響應業務變化調整業務架構時,也隨之變化系統架構”。可能大家平時有這樣的想法,但是比較模糊,未形成體系,而DDD就提供了一套完整的方法論。從業務角度去審視我們的系統,從而實現高內聚低耦合的代碼。

          整體而言,領域驅動設計包括戰略建模和戰術建模: 戰略設計側重于高層次、宏觀上去劃分和集成限界上下文,而戰術設計則關注更具體使用建模工具來細化上下文。

          二、 如何實現DDD之戰略建模

          1. 基本概念

          1)領域、子域

          在討論問題之前,我們需要先定義好問題。

          領域即問題域,通常是根據一個組織所處的行業進行識別,它基于業務的愿景,定義了系統要解決的現實問題的目標和范圍。領域越大,業務的范圍也越大,大的領域可以拆分成小的問題域,稱之為子域。根據子域重要性和功能屬性劃,可以將其分為三類。

          核心域、支撐域和通用域:

          • 核心域:決定產品核心競爭力的子域
          • 支撐域:實現核心域目標所需的,但重要程度不如核心域的子域,一般具備強烈的個性化需求
          • 通用域:具有通用功能,可被多個子域使用的的是通用域。該子域所解決的問題一般是業界常見問題,有成熟的解決方案,可直接購買或簡單修改來使用

          這個幾個概念其實很容易理解,不過在劃分的時候,注意要從業務的視角,而不是技術功能模塊來劃分。

          2)限界上下文

          我們語言博大精深,同樣的話在不同語境下就可演變出不同含義,這在溝通時總是帶來不必要的麻煩。為了準確地溝通,我們需要統一語言的邊界,在相同的語言邊界內溝通,才不容易出差錯。

          一則阿凡提當理發師懲罰一個狡猾牧師的趣事:理發時,阿凡提刮臉時問牧師:“牧師,是否要眉毛?”牧師答:“這還用問,眉毛豈能不要?”.“好,你要我就給你!”,說著就把牧師的眉毛刮下來遞到他手里,牧師氣得說不出話來,誰叫自己說要呢。阿凡提又問:“牧師,胡子要嗎?”.“不要,不要!”牧師連忙說。“好,你不要就不要。” 嗖嗖幾刀就把牧師的胡子刮下來。

          在一個系統中,一個名詞在不同語境可能有不同的含義,我們對它關注的屬性和行為也有所不同。例如,在電商系統中,對于產品Product, 在采購上下文,需要關注產品的進價、最小起訂量與供貨周期;在市場上下文中,則關心產品的品質、售價,以及用于促銷的精美圖片和銷售類型;在倉儲上下文中,倉庫工作人員更關心產品放在倉庫的哪個位置,產品的重量與體積,是否易碎品以及訂購產品的數量。

          限界上下文在《實現領域驅動設計》中,用了很大篇幅去講,它有幾個重要的意義:

          1. 限界上下文是領域概念的語言邊界與業務邊界:在這個邊界內,領域概念的內涵是清晰、無歧義的
          2. 限界上下文是團隊的工作邊界:組織邊界與限界上下文對齊
          3. 限界上下文是技術方案的實施邊界:在這個邊界內,技術方案是獨立自治的,業務邏輯不會落入不同技術邊界的間隙

          經過戰略建模之后,我們可以得到以下的一個模型:

          2. 業務實踐

          為了更好地理解,我們對手上的一個項目:“IoT設備增值產品管理系統”進行實踐。該項目中,我們提供給商戶在IoT設備上管理增值運營產品的能力。這里的IoT設備主要是微信支付刷臉設備等。商戶可以在系統中創建我們業務中的增值運營產品,如電子海報、互動海報等,創建完之后,相關的增值產品會被投放到IoT設備上,進行展示、運作:

          一開始我們從業務的用例出發,認為我們的系統主要是商戶在我們頁面網站使用,以及IoT設備通過接口連接我們后臺服務,認為這兩個分屬不同的子域,然后梳理了一些支撐的功能:

          畫完草圖之后,感覺不是很確定,于是便去咨詢部門的DDD專家王老師(十分感謝王立老師的指導),得到了一些寶貴的建議:我們應該避免直接從表現層去看業務,表現層就像是冰山露在水面上的棱角,這些棱角看起來毫不相干,但是實際上底層是連成一塊的,這些才是我們需要關注的。

          就像這個項目,表面上商戶和設備是分開的,實際上它們在操作都是我們的增值運營產品,應該看成我們的系統提供統一對外的服務,然后商戶和設備來使用我們的服務。UGC內容存儲業務用例其實沒有涉及到的,屬于實現時候的東西。一番建議讓我們理清了思路,于是重新梳理,得到以下的戰略建模圖:

          整體而言,我們將整體系統梳理為8個子域:

          1. 增值運營服務子域:核心域,是我們業務主要競爭力。從業務上來講,我們的核心是通過提供業務中IoT設備上的增值運營服務
          2. 增值運營產品子域:支撐域,這里主要是我們提供增值運營產品,如電子海報、互動海報等
          3. 生效場景子域:支撐域,業務中增值運營產品有不同生效場景,這里統一進行管理
          4. 準入子域:支撐域,現主要是業務中對使用者的一些限制規則
          5. 權限管理子域:支撐域,基于角色來管理使用者的權限
          6. 商戶信息子域:支撐域,提供商戶的信息
          7. IoT設備信息子域:支撐域,提供IoT設備的信息
          8. 風險識別子域:通用域,識別業務中一些安全風險,如不合規的UGC素材等。這部分是業界常見問題,可以使用通用方案來解決,實際上我們也是接入TEG的能力來實現

          其中我們系統中的商戶信息依賴了微信支付商戶賬號信息和IoT設備鋪設服務信息,這里使用防腐層進行隔離,將外部的商戶信息“翻譯”為我們業務中的商戶信息。三、如何實現DDD之戰術建模梳理清楚上下文之間的關系后,我們基本了解業務的概貌,接下來需要細化上下文,進一步完善我們的模型。這里也需要用到DDD的一些基本概念。

          3. 基本概念

          1)實體、值對象

          實體和值對象是組成領域模型的基礎單元。當一個對象由其標識(而不是屬性)區分時,這種對象稱為實體。如在校園教務系統中,每個賬戶是對應著一個學生,根據學號來唯一標識,可以認為是一個實體。傳統的數據建模大多是根據數據庫范式設計的,每一個數據庫表對應一個實體,每一個實體的屬性值用單獨的一列來存儲,一個實體主表會對應 N 個實體從表。

          與其不同,DDD 是先構建領域模型,再將業務對象映射為持久化對象。這可能導致DDD建立出來的實體,映射到具體數據庫表時,可能是1對多,多對1的關系。

          如一個賬戶實體,有它的基本信息和權限角色信息,可能就對應了2個持久化對象。另一方面,有時候為了某些查詢場景的方便,會把教師賬戶、學生賬戶等對應成一個持久化對象,就成了多對1。

          通過對象屬性值來識別的對象,則可以認為是一個值對象。如地址信息{“省”: “廣東省”,”市”:”深圳市”},我們是通過它的屬性來區分出不同的地址。值對象實際上是想把一些不變的屬性組合起來,減少系統的復雜性。在設計值對象的時候,需要滿足以下的特性:

          1. 值對象相等性:可以通過對其屬性的比較,來區分不同的值對象
          2. 不變性:需要保證值對象創建后就不能被修改,即不允許外部再修改其屬性
          3. 可替換性:值對象是一個整體,當其描述的對象有變化時,需要用一個新的值對象來替換對于值對象,由于其具有不變性,且是通過屬性來判斷相等的,在設計對應的數據庫持久化對象時,可以將其以JSON形式存儲在數據庫表的某一字段中

          2)聚合、聚合根

          在 DDD 中,實體和值對象是基礎的領域對象。實體一般對應業務對象,它具有業務屬性和業務行為;而值對象主要是屬性集合,對實體的狀態和特征進行描述。但是我們的一個業務流程中,一般會同時涉及多個實體、值對象的操作,這里業務邏輯緊密的實體和值對象便組合成一個聚合。

          從數據層面來看,同個聚合內的數據需要保持強一致性

          每一個聚合有一個聚合根實體,設置聚合根的主要目的是為了避免由于復雜數據模型缺少統一的業務規則控制,而導致聚合、實體之間數據不一致性的問題。聚合根可以看成是聚合的管理者,或是說handle。對內其協調實體和值對象完成業務邏輯。對外則提供通過聚合ID供其他聚合關聯引用,屏蔽外部對內部實體的直接訪問和修改。

          建議的聚合設計原則:

          1. 在一致性邊界之內確保不變性:聚合用來封裝真正的不變性,而不是簡單地將對象組合在一起。聚合內有一套不變的業務規則,各實體和值對象按照統一的業務規則運行,實現對象數據的一致性。
          2. 設計小聚合:如果聚合聚合包含過多的實體,會提高管理實體的復雜性,高頻操作下容易并發沖突,降低了系統的性能。
          3. 在邊界之外使用最終一致性:不同的聚合之間不要求強一致性,保證最終一致性。一次事務操作中,只修改一個聚合實例,如果需要修改多個實例,可以考慮通過異步的方式保證最終一致性。

          3)領域服務

          領域服務的定義:領域中的服務表示一個無狀態的操作,它用于實現特定于某個領域的任務。當某個操作不適合放在聚合(實體)或值對像上時,最好的方式便是使用領域服務。

          舉個例子,在一個路線導航的項目中,“路線”可能是其中的一個實體,如果業務中有“推薦路線上相關的美食”這樣一個功能,那我們會想,這個功能應該歸給哪個領域對象,給“路線”實體嗎?有點不合適,應該路線本身關注的是起終點,時間人物等。

          此時可以將其這個功能歸為領域服務,它是一個路線狀態無關的服務,輸入路線各個節點,來得到沿路的各種美食。當然,要注意不要過度地使用領域服務,因為這很可能導致你把實體的行為都放在里面了,實體本身都變成了一些只有getter和setter的“貧血模型”。

          4)領域事件

          領域事件是領域模型中非常重要的一部分,用來表示領域中發生的事件。一個領域事件將導致進一步的業務操作,在實現業務解耦的同時,還有助于形成完整的業務閉環。

          領域事件含義很廣泛,可以是業務流程的一個步驟,也可以是一個事件發生后觸發的后續動作,繳費完成之后,觸發短信通知;上面在設計聚合的時候,我們提到一個原則:在邊界之外使用最終一致性,一次事務最多只能更改一個聚合的狀態。如果一次業務操作涉及多個聚合狀態的更改,應通過領域事件,達到最終一致性。

          實際上是通過事件驅動的這種異步方式,對系統進行解耦。當然,如果你覺得某兩個步驟,業務流程上不允許是不一致的,那就得重新考慮將其歸在同個聚合中了。

          4. 業務實踐

          我們以增值運營服務上下文為例,根據上面的理解,結合業務實際,得到以下模型:

          其中增值產品是其中的一個聚合根,通過該聚合根進行各種領域操作。海報縮略圖是其中的一個領域服務,通過輸入產品素材中的海報url,來得到一個海報的縮略圖。

          四、工程實踐

          傳統的三層架構和DDD的分層結構:

          在《領域驅動設計——軟件核心復雜性的應對之道》一書中,Eric提出了這樣的一種分層結構,將整個系統劃分為四層:用戶接口層、應用層、領域層和基礎設施層。

          用戶接口層:用戶接口層負責向用戶顯示信息和解釋用戶指令。

          應用層:應用層相對來說是較“薄”的一層,主要是部署了應用服務。應用服務的實現中,它負責編排和轉發下一層的領域層的接口,將要實現的功能委托給一個或多個領域對象來實現,本身只負責處理業務用例的執行順序以及結果的拼裝。

          領域層:領域層是比較“厚”的一層,它包含聚合根、實體、值對象、領域服務等領域模型中的領域對象,實現了核心的業務邏輯。領域層和應用層的職責看起來有點模糊。

          個人覺得,可以理解是應用層描述了一個具體操作從開始到結束的每一個環節,而領域層則是對其的細化,用來處理具體的某一個環節。

          比如,比如線上購物中,購物車結算這一場景可看成是一個應用行為。而這個行為又主要包括金額計算、支付、生成訂單,這些子環節就可以理解為一個領域層的服務了。

          基礎設施層:可以看到上面三層都有箭頭指向基礎設施層,它的作用就是為其它各層提供通用的技術和基礎服務,如數據持久化、消息中間件等DDD 分層架構中的要素與傳統三層架構(用戶界面層、業務邏輯層、數據訪問層)還是挺相似的,一個主要的變化是將業務邏輯層的服務拆分到了應用層和領域層。應用層響應業務用例的變化,領域層關注不變的領域模型。

          圖片來自極客時間

          《DDD實戰課》在實際的代碼工程便是按照這樣的目錄來劃分,最近部門在推的整潔Git,也是這樣劃分目錄:

          接下來,便是將領域對象映射到實際的類,實現對應的屬性和行為。當然,具體實現中有很多范式可參考和討論,我們也在摸索中,待后續慢慢補充……

          五、總結

          DDD首先不是關于技術的,而是關于討論、聆聽、理解、發現業務價值的。——Vaughn Vernon《實現領域驅動設計》

          如Vernon所說的,DDD首先是關注業務的價值的。一開始我們對業務的邊界、目標可能有個大概了解,但是見解還是不盡相同。

          通過一起對業務的討論與思考,我們了解了業務的概貌及核心,明確價值所在。關注到了核心,自然可以幫助我們實現與業務契合的系統。通過這次學習與實踐,我們進一步接觸了DDD。

          當然,這也還只是開始,更多的關聯知識還隱藏在冰山之下。同時我們也明白,DDD也只是一種方法論上的參考,不是“銀彈”,需要不斷地去實踐與思考,才能體會出它的價值。

          參考:

          • Eric Evans.領域驅動設計.趙俐 盛海艷 劉霞等譯.人民郵電出版社,2016.
          • 美團技術團隊.領域驅動設計在互聯網業務開發中的實踐:https://tech.meituan.com/2017/12/22/ddd-in-practice.html?spm=a2c4e.10696291.0.0.428119a4uu9Gpl
          • 極客時間.DDD實戰課:https://time.geekbang.org/column/article/152677

          作者:bryanzhao,微信支付后臺開發工程師

          本文由 @騰訊大講堂 原創發布于人人都是產品經理,未經許可,禁止轉載。

          題圖來自 Pixabay,基于CC0協議。

          們為什么需要領域驅動設計

          在說什么是領域驅動設計之前,我覺得需要先說一下我們為什么需要領域驅動,我個人認為領域驅動設計對于研發來說改進點主要有下面三個:

          1. 從大泥球風格中解脫出來,控制代碼復雜度
          2. 回歸面向對象編程本質,而不是面向過程編程
          3. 專注于業務,實現不同業務領域解偶

          什么是領域驅動設計

          領域驅動設計(DDD)是一種軟件設計思路,領域指的是業務領域,比如銀行業務領域,醫藥銷售領域;不同于傳統以數據表為中心的建模方式,它以業務領域為中心來建模,能促使我們以正確的方式使用面向對象,建立飽滿的領域對象。

          在進行領域建模和開發時我們主要需要關注以下幾點:

          1. 和領域專家一起構建一套通用語言,團隊成員使用通用業務語言進行交流;
          2. 關注領域的戰略設計,DDD的戰略設計從更高層次抽象系統,劃分出不同的系統和業務關注點,戰略設計包含:領域/子域劃分、通用語言的構建、限界上下文定義以及架構風格選擇等;
          3. 實現DDD的戰術設計,戰術設計主要包含:領域對象(實體、值對象、聚合)、模塊、領域服務、工廠等;

          下面的思維導圖是領域驅動設計需要掌握的一些點:

          Tips:

          1.領域驅動設計是2004年Eric Evans在《領域驅動設計:軟件核心復雜性應對之道》這本書中提到的,DDD的出現是為了應對復雜業務場景下軟件越來越復雜問題;也就是說通過DDD可以將軟件的復雜度控制在合理的范圍內。

          2.領域驅動設計主要解決的是業務復雜度問題(避免大泥球風格:大泥球風格就是沒有任何清楚的結構,例如隨意共享的數據,隨意全局化的數據結構。這樣風格的系統可維護性(maintainability)和可擴展性(extensibility)都很差,最終導致整個系統難以改動,維護不下去),如果業務不復雜,則不需要使用DDD方式來處理(推薦用三層架構)。

          領域驅動設計的優缺點

          領域驅動設計的優缺點很明顯,我這邊整理了幾個優缺點,供參考。

          優點:

          1. 由領域專家進行領域模型設計,通過業務驅動開發而不是數據庫設計來驅動項目開發,業務邏輯更加清晰;
          2. 再次強調了面向對象編程的重要性,減少面向過程編程(提高內聚性、降低上下文之間耦合);
          3. 對單元測試(自測)比較友好;

          缺點:

          1. 需要有對DDD比較精通的人員進行領域的建模,如果建模不當,后續會比較麻煩;
          2. 對開發人員要求比較高,開發人員需要理解DDD才能進行開發;
          3. DDD本身概念性的東西比較多,有些概念不好理解,需要長時間的歷練才能很好的掌握DDD;

          如何進行領域建模

          按照實現領域驅動設計一書中描述的DDD步驟主要有4步:

          1. 根據業務需求劃分出初步的領域和限界上下文,以及上下文之間的關系;
          2. 進一步分析每個上下文內部,識別出哪些是實體,哪些是值對象;對實體、值對象進行關聯和聚合,劃分出聚合的范疇和聚合根;
          3. 為聚合根設計倉儲,并思考實體或值對象的創建方式;
          4. 在工程中實踐領域模型,并在實踐中檢驗模型的合理性,倒推模型中不足的地方并重構。

          劃分領域和限界上下文

          提煉問題域

          軟件開發實際作用就是為客戶解決問題或者軟件升級變革,所以在領域中我們劃分了問題空間和解空間兩個緯度空間,用于描述客戶的問題(需求)和如何解決問題(解決方案)。

          問題的來源:

          1. 客戶痛點需求:比如電腦藍屏、文檔忘記保存等。
          2. 行業變革:移動支付、網購等。

          問題域劃分

          首先我們需要對問題域進行拆分,拆分的理念就是由大化小,逐個擊破。拆分完畢問題空間,我們需要做到逐一擊破,為每一個問題形成一套落地解決方案。一個問題對應一個答案,解空間與問題空間基本上應該是一一對應的。

          構建限界上下文

          我們給出的解方案是一個個限界上下文,一個限界上下文負責應對其對應的問題進行解決,承載了該問題中的業務知識及規則。限界上下文是解決某一類問題的單一功能模塊,例如訂單限界上下文,處理開單、通知訂單狀態等一切與訂單關聯的功能。

          隨著問題的劃分,將領域拆分成了不同的子域,每個子域有其獨有的業務知識,而這些知識需要靠一門統一語言來描述。而不同限界上下文間的統一語言是相互獨立的。可能在不同的限界上下文有同樣的名詞,但同樣的名詞在不同的限界上下文中可能表示的不是同一事物,即使是同一事物可能其在不同上下文中的關注點也不一致。

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

          • 合作關系(Partnership):兩個上下文緊密合作的關系,一榮俱榮,一損俱損。
          • 共享內核(Shared Kernel):兩個上下文依賴部分共享的模型。
          • 客戶方-供應方開發(Customer-Supplier Development):上下文之間有組織的上下游依賴。
          • 遵奉者(Conformist):下游上下文只能盲目依賴上游上下文。
          • 防腐層(Anticorruption Layer):一個上下文通過一些適配和轉換與另一個上下文交互。
          • 開放主機服務(Open Host Service):定義一種協議來讓其他上下文來對本上下文進行訪問。
          • 發布語言(Published Language):通常與OHS一起使用,用于定義開放主機的協議。
          • 大泥球(Big Ball of Mud):混雜在一起的上下文關系,邊界不清晰。
          • 另謀他路(SeparateWay):兩個完全沒有任何聯系的上下文。

          子域類型

          核心域

          核心域是一款軟件的所能獲得的競爭優勢的根本所在。所以在核心的建模和開發主要投入大量的時間和人力。

          通用域

          通用域是許多大型軟件系統都有的子域。通用域例如像電子郵件和短信發送、OSS、MQ等。

          支撐域

          系統中的其他域被稱為支撐域。支撐域的主要作用就是有助于支撐核心域的業務。比如:用戶的注冊等。

          分析模型(從領域建模角度分析需求)

          DDD分析建模主要有兩種方法可以使用:用例分析法、四色建模法、事件風暴、領域驅動建模。

          用例分析法

          通過對需求進行分析構建出用例圖如下所示(舉例子不一定正確):

          四色建模法

          這里列一下標準的四色建模法(https://www.infoq.cn/article/xh-four-color-modeling/),其實還是需要多聯系才行。

          時標型(Moment-Interval)對象:具有可追溯性的記錄運營或管理數據的時刻或時段對象,用紅色表示 -> 操作

          PPT(Party/Place/Thing)對象:代表參與到流程中的參與方/地點/物,用綠色表示 -> 名詞

          角色(Role)對象:在時標型對象與 PPT 對象(通常是參與方)之間參與的角色,用黃色表示 -> 操作角色

          描述(Description)對象:對 PPT 對象的一種補充描述,用藍色表示 -> 表述備注

          領域建模并不是沒有方法,而是選擇太多,有用例法、四色建模、領域驅動建模、事件風暴等,人有一個特點是喜歡找最簡單、最易用的方法,每個方法都有自己的特點,并沒有好壞優劣之分,只有適不適合。聽到一個方法就去嘗試,嘗試到一半就放棄,一種種方法嘗試,最終就會迷失在方法選擇上。

          識別模型(主要構成)


          構造模型(找到聚合根)


          細化模型(反復優化)

          對于DDD而言領域建模完成后,我們就需要對照模型進行開發,在開發之間我們需要知道領域戰略設計中的幾種架構風格。

          1. 名詞做類、動詞為方法,生成漸層次模型
          2. 將漸層次模型歸納劃分,做更抽象的

          DDD四層架構

          DDD四層架構是一個松散分層架構(任意上層可以調用下層,但是下層不能調用上層),DDD四層架構的含義如下:

          1. 用戶接口層:用戶界面層,或者表現層,負責向用戶顯示解釋用戶命令(類似于傳統三層架構中的Controller層);
          2. 應用層:定義軟件要完成的任務,并且指揮協調領域對象進行不同的操作。該層不包含業務領域知識。這層和傳統三層架構中不同點在于MVC中所有的業務邏輯都在Service層,但是DDD四層結構中將業務邏輯下層到領域層,應用層只負責定義方法,然后調用領域層進行處理。應用服務可以用于控制持久化事務和安全認證等。應用服務本身并不處理業務邏輯,但它確卻是領域模型的直接客戶。
          3. 領域層:領域層是系統的核心,負責表達業務概念,業務狀態信息以及業務規則。即包含了該領域(問題域)所有復雜的業務知識抽象和規則定義。該層主要精力要放在領域對象分析上,可以從實體,值對象,聚合(聚合根),領域服務,領域事件,倉儲,工廠等方面入手。
          4. 基礎設施層:該層主要有兩方面內容,一是為領域模型提供持久化機制,當軟件需要持久化能力時候才需要進行規劃;一是對其他層提供通用的技術支持能力,如消息通信,通用工具,配置等的實現;

          如下是DDD四層架構圖:

          依賴倒置原則(DIP)

          依賴倒置原則:我們要依賴不變或穩定的元素(類、模塊或層),抽象不應該依賴于細節,細節應該依賴于抽象。依賴倒置原則可以改進分層架構,即底層服務應該依賴于高層組件所提供的接口。

          ?采用了依賴注入方式后,其實可以發現事實上已經沒有分層概念了。無論高層還是底層,實際只依賴于抽象,整個分層好像被推平了,這就引入下一個架構六邊形架構。

          六邊形架構

          六邊形架構是Alistair Cockburn在2005年提出的,在這種架構中,不同的客戶通過“平等”的方式與系統交互。在《實現領域驅動設計》一書中,作者將六邊形架構應用到領域驅動設計的實現,六邊形的內部代表了application和domain層。外部代表應用的驅動邏輯、基礎設施或其他應用。內部通過端口和外部系統通信,端口代表了一定協議,以API呈現。個人理解其實就是變成內層、適配層&外部資源,內層是應用層和領域層;適配層是之前的接口層和基礎設施層;外部資源就是對外接口、緩存、MQ、數據庫等等。六邊形架構圖如下所示:

          ?下面是對六邊型架構的一個落地實踐示例:

          ?

          四層架構、DIP、六邊形架構可以參考:

          https://www.jianshu.com/p/c405aa19a049

          http://it.hzqiuxm.com/ddd%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E6%88%98%E7%95%A5%E7%AF%87%EF%BC%884%EF%BC%89/#DDD-2

          CQRS

          在DDD設計思路中,DDD 通過領域對象之間的交互實現業務邏輯與流程,并通過分層的方式將業務邏輯剝離出來,單獨進行維護,從而控制業務本身的復雜度。但是作為一個業務系統,查詢的相關功能也是不可或缺的。在實現各式各樣的查詢功能時,往往會發現很難用領域模型來實現。假設在用戶需要一個訂單相關信息的查詢功能,展現的是查詢結果的列表。列表中的數據來自于訂單、商品、品類、送貨地址等多個領域對象中的某幾個字段。這樣的場景如果還是通過領域對象來封裝就顯的很麻煩,其次與領域知識也沒有太緊密的關系。所以命令查詢職責分離的設計架構(CQRS)是可以很好的解決上述的問題。

          CQRS將系統分為兩類操作:命令(command)、查詢(Query)。命令則是對會引起數據發生變化操作的總稱,即我們常說的新增,更新,刪除這些操作,都是命令。而查詢則和字面意思一樣,即不會對數據產生變化的操作,只是按照某些條件查找數據。CQRS 的核心思想是將這兩類不同的操作進行分離,然后在兩個獨立的服務中實現。這種獨立服務可以是兩個不同的應用或者同一個應用中不同的包進行隔離。同時理論上命令和查詢的數據源也是不同的(實現讀寫分離)。

          當然讀寫分離模式,肯定會遇到事務的問題,事務問題主要的包含兩種情況:

          1. 當 command 端完成數據更新后,需要通過事件的形式通知 query 端系統,這就存在著一定的時間差,如果你的業務對于數據完整的實時性非常高,那么可能 CQRS 不一定適合你。
          2. 其次一個 command 觸發的事件在 query 端可能需要更新數個數據模型,而這也是有可能失敗的。一旦更新失敗那么數據就會長時間的處于不一致狀態,需要外部的介入。

          所以從事務的角度來看 CQRS,你需要面對的是問題從根本來說是個最終一致性的問題。對于團隊處理這種最終一致性問題需要有對應的方案。

          CQRS架構如下所示:

          ?領域對象

          了解了戰略設計后,我們主要做具體的實施,具體實施時我們需要了解實體、值對象和聚合這幾個領域對象。

          實體&值對象

          我們先看一下他們的定義:

          實體:許多對象不是由它們的屬性來定義,而是通過一系列的連續性(continuity)和標識(identity)來從根本上定義的。只要一個對象在生命周期中能夠保持連續性,并且獨立于它的屬性(即使這些屬性對系統用戶非常重要),那它就是一個實體。

          值對象:當你只關心某個對象的屬性時,該對象便可作為一個值對象。為其添加有意義的屬性,并賦予它相應的行為。我們需要將值對象看成不變對象,不要給它任何身份標識,還應該盡量避免像實體對象一樣的復雜性。

          對于實體Entity,實體核心是用唯一的標識符來定義,而不是通過屬性來定義。即即使屬性完全相同也可能是兩個不同的對象。同時實體本身有狀態的,實體又演進的生命周期,實體本身會體現出相關的業務行為,業務行為會實體屬性或狀態造成影響和改變。

          如果從值對象本身無狀態,不可變,并且不分配具體的標識層面來看。那么值對象可以僅僅理解為實際的Entity對象的一個屬性結合而已。該值對象附屬在一個實際的實體對象上面。值對象本身不存在一個獨立的生命周期,也一般不會產生獨立的行為。

          對于實體和值對象詳細說明可以參考:https://www.jianshu.com/p/da51d16dbdc4

          聚合&聚合根

          聚合是業務和邏輯緊密關聯的實體和值對象組合而成,聚合是數據修改和持久化的基本單元,一個聚合對應一個數據的持久化;同時將選擇一個實體作為每個聚合的根,并僅允許外部對象持有對聚合根的引用。作為一個整體來定義聚合的屬性和不變量,并把其執行責任賦予聚合根或指定的框架機制。

          https://www.cnblogs.com/laozhang-is-phi/p/9916785.html

          最小化集成

          在所有的DDD項目中,通常存在多個限界上下文,這意味著我們需要找到合適的方法對這些上下文進行集成。當模型概念從上游上下文流入下游上下文中時, 盡量使用值對象來表示這些概念。這樣的好處是可以達到最小化集成,即可以最小化下游模型中用于管理職責的屬性數目。使用不變的值對象使得我們做更少的職責假設。

          貧血模型&充血模型

          貧血模型:指使用的領域對象中只有setter和getter方法(POJO),所有的業務邏輯都不包含在領域對象中而是放在業務邏輯層。貧血模型中領域對象只有屬性沒有豐富的操作,使用時需要單獨的Dao層配合使用,風格比較面向過程。

          充血模型:將大多數業務邏輯和持久化放在領域對象中,業務邏輯只是完成對業務邏輯的封裝、事務和權限等的處理。充血模型更加傾向于面向對象的設計風格(可以參考:https://www.jianshu.com/p/fae3da337ebc)。

          模塊&領域服務&工廠

          模塊(Module)是DDD中明確提到的一種控制限界上下文的手段,在我們的工程中,一般盡量用一個模塊來表示一個領域的限界上下文。一般的工程中包的組織方式為{com.公司名.組織架構.業務.上下文.*},這樣的組織結構能夠明確的將一個上下文限定在包的內部。
          領域服務:領域中的服務表示一個無狀態的操作,它用于實現特定于某個領域的任務。
          工廠:在DDD中有可能存在復雜對象的創建,如果使用對象本身進行創建有可能會破壞單一責任原則,所以需要工廠進行對象創建。

          GML

          • 概念

          SGML稱為:標準通用標記語言。

          定義電子文檔結構和描述其內容的國際標準語言。

          • 特點

          1:通用標言為語法置標提供了異常強大的工具,同時具有極好的擴展性,因此在數據分類和索引中非常有用;

          2:是所有 電子文檔標記語言的起源,早在萬維網發明之前“通用標言”就已存在。

          只描述文檔標記應該是怎么樣的元語言。

          總結:HTML是SGML的一個實例,它的DTD作為標準被固定下來,因此,HTML不能作為定義其它置標語言的元語言。


          XML

          • 概念

          標記電子文件使其具有結構性的標記語言,可擴展標記語言。

          • 特點

          1:結合

          結合了HTML和SGML,是一種非常復雜的文檔的結構。

          2:友好

          網站設計者可以定義自己的文檔類型。

          • 用途

          1:大量高度結構化數據的防衛區

          2:其他各種工業領域,利于分類和索引。

          下面是 小二哥 寫給 小二妹 的便簽,存儲為 XML:

          <note>

          <to>小二妹</to>

          <from>小二哥</from>

          <heading>Reminder</heading>

          <body>記得給小伙伴們發福利哦!</body>

          </note>

          總結:XML 被設計用來傳輸和存儲數據,是擴展標記語言(EXtensible Markup Language),很類似 HTML。XML 的設計宗旨是傳輸數據,而非顯示數據,標簽沒有被預定義。需要自行定義標簽。具有自我描述性,是 W3C 的推薦標準。


          DHTML

          DHTML 不是 W3C 標準。指動態 HTML(Dynamic HTML)。

          DHTML 不是由萬維網聯盟(W3C)規定的標準,是一個營銷術語 - 被網景公司(Netscape)和微軟公司用來描述 4.x 代瀏覽器應當支持的新技術。

          • 用途

          DHTML 是一種用來創建動態站點的技術組合物。

          總結:對大多數人來說,DHTML 意味著 HTML 4.0、樣式表以及 JavaScript 的結合物,是動態的HTML。


          XHTML

          XHTML是更嚴格更純凈的 HTML 代碼。是指可擴展超文本標簽語言(EXtensible HyperText Markup Language)。

          XHTML是當前HTML版的繼承者。HTML語法要求比較松散,這樣對網頁編寫者來說,比較方便,但對于機器來說,語言的語法越松散,處理起來就越困難,對于傳統的計算機來說,還有能力兼容松散語法,但對于許多其他設備,比如手機,難度就比較大。因此產生了由DTD定義規則,語法要求更加嚴格的XHTML。

          實例:

          <!DOCTYPE Doctype goes here>

          <html xmlns="http://www.w3.org/1999/xhtml">

          <head>

          <title>Title goes here</title>

          </head>

          <body>

          </body>

          </html>

          總結:XHTML 的目標是取代 HTML,與 HTML 4.01 幾乎是相同的, 是更嚴格更純凈的 HTML 版本。XHTML 是作為一種 XML 應用被重新定義的 HTML。是一個 W3C 標準。



          HTML5

          HTML5是下一代的 HTML。將成為 HTML、XHTML 以及 HTML DOM 的新標準。

          HTML 的上一個版本誕生于 1999 年。自從那以后,Web 世界已經經歷了巨變。

          HTML5 仍處于完善之中。然而,大部分現代瀏覽器已經具備了某些 HTML5 支持。

          • 特點

          1:語義特性(Class:Semantic)

          2:本地存儲特性(Class: OFFLINE & STORAGE)

          3:設備兼容特性 (Class: DEVICE ACCESS)

          4:連接特性(Class: CONNECTIVITY)

          5:網頁多媒體特性(Class: MULTIMEDIA)

          6:三維、圖形及特效特性(Class: 3D, Graphics & Effects)

          一個簡單的媒體播放實例

          <!DOCTYPE HTML>

          <html>

          <body>

          <video width="320" height="240" controls="controls">

          <source src="kecheng.ogg" type="video/ogg">

          <source src="kecheng.mp4" type="video/mp4">

          你的瀏覽器不支持html5,請更換瀏覽器。

          </video>

          </body>

          </html>

          總結:至于html5和html就不用多講了吧。HTML5在2007年被萬維網聯盟(W3C)新的工作組采用。這個工作組在2008年1月發布了HTML 5的首個公開草案。眼下,HTML5處于“最火”狀態,HTML5 已成為 HTML、XHTML 以及 HTML DOM 的新標準。


          上面分別介紹了SGML、XML、DHTML、XHTML、HTML5和HTML的之間的關系。順便也看看HTML吧。

          HTML

          • 概念

          超文本標記語言,標準通用標記語言下的一個應用。

          • 特點

          1:一種規范。

          2:一種標準。

          3:簡單但是功能強大,靈活方便。

          4:具有極強的擴展性。

          5:不牽扯平臺。

          實例:

          <html>

          <body>

          <h1>這個是標題</h1>

          <p>這個是段落。</p>

          </body>

          </html>

          總結:是用來描述網頁的一種超文本標記語言 (Hyper Text Markup Language), 不是一種編程語言,而是一種標記語言 (markup language),使用標記標簽來描述網頁。


          ·歡迎留言評論哦~


          主站蜘蛛池模板: 日本一区二区三区不卡视频| 日本一区中文字幕日本一二三区视频 | 免费播放一区二区三区| 无码国产伦一区二区三区视频| 激情内射亚洲一区二区三区爱妻| 国产一区在线电影| 丝袜无码一区二区三区| 天堂va视频一区二区| 亚洲一区二区三区高清| 精品一区二区三区在线视频观看| 久久精品岛国av一区二区无码| 老鸭窝毛片一区二区三区| 国产精品一区二区不卡| 中文字幕在线无码一区| 天堂成人一区二区三区| 国产AV午夜精品一区二区入口 | 久久精品国产亚洲一区二区| 影院成人区精品一区二区婷婷丽春院影视 | 国产视频一区二区在线观看| 无码国产精成人午夜视频一区二区| 国产中的精品一区的| 波多野结衣一区视频在线| 丰满爆乳一区二区三区| 国产伦精品一区二区三区四区 | 国产成人精品亚洲一区| 亚洲一区欧洲一区| 久久国产精品最新一区| 中文字幕不卡一区| 一区二区三区视频在线播放| 日本精品啪啪一区二区三区| 国产成人精品久久一区二区三区| 国产综合无码一区二区辣椒| 一区二区三区免费电影| 国产一区二区影院| 欧美日韩综合一区二区三区| 国产福利91精品一区二区| 无码国产精品一区二区免费模式| 果冻传媒董小宛一区二区| 国产精品无码不卡一区二区三区| 日韩AV无码一区二区三区不卡| 亚洲AV无码一区二区三区网址 |