天天看點

從壹開始微服務 [ DDD ] 之三 ║ 簡單說說:領域、子域、限界上下文前言零、今天要完成綠色的部分一、領域 —— 就是一個獨立項目二、子領域 —— 具體的項目實作三、限界上下文 —— 領域模型的邊界四、結語

前言

哈喽大家好,DDD領域驅動設計系列又開始了,前天周二的那篇入門文章中,也收到了一定的效果(寫小說的除外),同時我也是倍感鴨梨,怎麼說呢,DDD領域驅動設計已經有十年曆史了,甚至更久,但是包括我在内的一批技術人員還是對其不是很明白,這幾天我也是日思夜想,怎樣才能說的明白,怎樣才能把這個高高在上的思想落在實踐上,可惜的是國内栗子比較少,國外文章比較少,隻能硬啃了,是以更需要大家一起來讨論,這裡要說一下,是一起讨論推動,而不是内心去拒絕,而一直和多層架構做對比,這樣不僅不利于學習,也無法帶動我的積極性,是以,這裡懇請大家,多多評論,多多交流,比較我一個人很難扛得動這個DDD的大旗。

好啦,言歸正傳,上次咱們說到了《[ DDD ] 之二 ║ DDD入門 & 項目結構粗搭建》,其中主要說明了為什麼使用DDD,以及如何簡單的搭建一個基于領域的粗略層,顆粒度還是項目級别,還沒有繼續往下深究,今天呢,咱們就往下慢慢走,說一說整個項目下,是如何實作領域設計的。

這裡先給大家提一個問題,如果一個新的項目,比如一個小的問答系統交給你的手裡,PM 剛剛和你簡單的讨論了下需求,下一步你打算做些什麼?

1、根據需求,立刻準備設計資料庫,建表,腦中模拟場景;

2、根據需求,立刻建立實體類(也就是model層),然後CodeFirst 生成資料庫;

3、找尋該領域專家(做過或者懂得類似産品的人),設計該問答領域下,有哪些子領域,制作限界上下文;

4、啥都沒有,直接網上找開源項目,下載下傳下來看看;

老張說:這裡沒有正确與否的比較,隻是一個習慣和優劣的分析,不用太在意,如果你比較好奇,那就往下看吧。

零、今天要完成綠色的部分

從壹開始微服務 [ DDD ] 之三 ║ 簡單說說:領域、子域、限界上下文前言零、今天要完成綠色的部分一、領域 —— 就是一個獨立項目二、子領域 —— 具體的項目實作三、限界上下文 —— 領域模型的邊界四、結語

一、領域 —— 就是一個獨立項目

1、領域的概念

 這個概念相信很多人已經很明白了,而且也聽到了無數遍,這裡就再簡單的說兩句:

領域(Domain)其實就是一個組織所要做的整個事情,已經這個事情下所包含的一切内容。這是一個範圍概念,而且是面向業務的(注意這裡不是面向技術的,更不是面向資料庫的持久化的),每個組織都有自己的人員、自己的工作業務範圍和做事方式,當你為該組織開發軟體的時候,你面對的就是這個組織的領域。

就比如之前我在一家旅遊公司進行開發工作,那我所進行的開發工作就是一個旅遊行業,我必須要很清晰旅遊行業的其中的領域知識,而且必須能和領域專家通過通用性語言進行溝通,這樣能保證我開發出來的是他們想要的,而不是我單純的從技術上實作,在領域設計上一塌糊塗。當然我們每天也都在做這樣的事情,也許你感覺很正常,那我再舉個例子:

我在開發其中一個目的地(旅遊景點)項目的時候,這是一個領域,後來在電商系統項目中,又是一個領域,但是在電商領域中,涉及到了景點領域的一些資料,那我如果不和領域專家溝通,有時候為了貪圖技術上的友善,甚至把兩個領域合并成一個,雖然都不大,合并以後大小也還可以,但是這樣卻完全打破了領域的這個概念,這個就是完全面向技術開發的,因為領域專家看不懂我這麼寫到底屬于什麼。

當然上邊的栗子有點兒牽強,咱們再說下以後我想做的一個基于DDD的問答項目,咱們先畫一個框。

從壹開始微服務 [ DDD ] 之三 ║ 簡單說說:領域、子域、限界上下文前言零、今天要完成綠色的部分一、領域 —— 就是一個獨立項目二、子領域 —— 具體的項目實作三、限界上下文 —— 領域模型的邊界四、結語

就如圖所示,咱們首先定義一個邊界,至于裡邊有什麼東西,咱們接着往下看,這個很簡單。

2、如何定義一個領域

這個是更簡單的一個問題,在領域設計中,有兩個方法:戰略設計和戰術設計,其實我個人感覺可以定義兩步走,這兩個是有先後之分的,

戰略設計中定義了,一個領域就是一個問題空間,我們在業務中所遇到的所有的問題與挑戰;

在戰術設計中,一個領域就算一個解決問題空間,用來解決在問題空間的所有問題;

是以,其實一個領域就是一個我們建立的一個解決方案,一個項目,在我們的問答項目中,整個解決方案就是一個問答領域。

二、子領域 —— 具體的項目實作

1、子域 / 核心子領域 / 通用子領域

什麼是子域(SubDomain)呢?這個很好了解,就是在整個領域中,我們如何對其進行拆分,然後滿足我們的業務邏輯。一個子域可能是一個 dll ,一個命名空間的形式存在。

我們定義好領域,并且劃分好限界後,就開始考慮如何進行實作,這裡大家想一想如何設計與劃分,這裡就說說我自己的之前的想法:

在我們的問答領域設計中,我們的思路一定是有客戶來 =》驗證是否有發問題的權限 =》 然後釋出一個問題 =》

從壹開始微服務 [ DDD ] 之三 ║ 簡單說說:領域、子域、限界上下文前言零、今天要完成綠色的部分一、領域 —— 就是一個獨立項目二、子領域 —— 具體的項目實作三、限界上下文 —— 領域模型的邊界四、結語

這僅僅是一個釋出問題的流程,也僅僅是一個顧客認證的過程,很簡單,我們一般會怎麼分子領域呢,可能會這麼分,這個就是 消息釋出子領域,裡邊有我們的釋出模型,使用者模型,讨論模型,月曆模型等等,大概就是這個樣子

從壹開始微服務 [ DDD ] 之三 ║ 簡單說說:領域、子域、限界上下文前言零、今天要完成綠色的部分一、領域 —— 就是一個獨立項目二、子領域 —— 具體的項目實作三、限界上下文 —— 領域模型的邊界四、結語

因為我們會這麼想:“使用者和權限這兩個模型,和我們的消息子領域有何緊密的關系,你看,釋出+回複+讨論+月曆(指自己建立一個月曆功能,具體待定),這些模型肯定都需要使用者登陸認證吧,甚至有些是需要授權的,分在一個子領域有什麼不對麼?”,這樣的代碼邏輯應該是這樣的

從壹開始微服務 [ DDD ] 之三 ║ 簡單說說:領域、子域、限界上下文前言零、今天要完成綠色的部分一、領域 —— 就是一個獨立項目二、子領域 —— 具體的項目實作三、限界上下文 —— 領域模型的邊界四、結語

如果是你看到這裡,首先明白了什麼是子領域了吧,也知道如何劃分了,但是你感覺這個劃分對麼? 如果你感覺很正常,那就請往下看吧。

2、核心子領域 / 通用子領域 / 支撐子領域

我們再來分析一下,我們的問答領域中的有哪些内容,首先:肯定有消息釋出子領域,這個也是上邊說到的,這個毋庸置疑,一個問答系統,消息釋出是肯定的(這裡說明下:釋出問題,回答問題,讨論問題等都屬于一個消息的釋出,這個應該了解),而且這個子領域是缺少它不可的,這個就是我們的核心子領域。

再來看看,還有一些其他的,比如日志記錄,資料操作痕迹記錄(哪個管理者修改了哪些資料),這些子領域貫穿着我們整個領域系統,被其他領域共用,我們稱之為 通用子領域,

當然,我們還有一些站内的即時消息,wiki百科,通知提醒,活動跟蹤,等等,這些都不是我們的核心子域,因為沒有這些,我們依然可以進行問答,但是這些确是支撐着我們核心子域的相關功能,我們就把這些命名為 支撐子領域,這個時候你會問,這些支援子領域要不要再拆開,我個人表示沒有很大的必要。

最後我們再來看看我們上邊的使用者認證授權問題,在上邊我們把他們柔和到了消息核心子域裡,但是這裡要說明,這兩者是沒有關系的:

為什麼沒有關系呢?誠然,我們的軟體是必須有使用者參與的,但是我們應該将不同的使用者種類差別對待,因為在不同的上下文(下邊會說到)中,他們的作用和任務是不一樣的,在消息核心子域中,我們關注的是角色,不管他是誰或者有什麼權限,如果我們有一天把權限模型修改了,那我們的問答模型也一定要修改,你想想是不是,因為兩者業務邏輯已經耦合了!

這個時候我們應該明白,釋出資訊和“誰可以發,在什麼條件下發”其實沒有太大的關系,我的問答,隻關心的是“有一個顧客釋出了一個問題”這樣就可以了,我們關心的是釋出消息這個過程,而不能把使用者權限涉及進來,這個時候我們應該把使用者權限單拿出來一個子領域,就叫安全子領域。

從壹開始微服務 [ DDD ] 之三 ║ 簡單說說:領域、子域、限界上下文前言零、今天要完成綠色的部分一、領域 —— 就是一個獨立項目二、子領域 —— 具體的項目實作三、限界上下文 —— 領域模型的邊界四、結語

3、隔離核心

其實上邊說的可能有點兒朦胧,但是我們應該都已經用到了,如果你看了我的上一個系列教程,你應該知道有一個JWT權限驗證那一章節,很多人就是不很了解,是如何進行授權驗證的,其實采用的就是隔離内容,以前我們寫邏輯,就算直接在控制器裡,判斷目前使用者權限,但是現在我們是通過一個中間件,判斷 Token 所包含的使用者Role 是否有這個權限,再進行下一步,隻不過在DDD中,把這一塊單拿出來形成了一個安全子領域了,這個時候你應該明白了吧。

/// <summary>
        /// 删除一個顧客資訊
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost, ActionName("Delete")]
        [Authorize(Policy = "CanRemoveCustomerData")]
        [Route("customer-management/remove-customer/{id:guid}")]
        [ValidateAntiForgeryToken]
        public IActionResult DeleteConfirmed(Guid id)
        {
            _customerAppService.Remove(id);

            if (!IsValidOperation()) return View(_customerAppService.GetById(id));

            ViewBag.Sucesso = "Customer Removed!";
            return RedirectToAction("Index");
        }      

這個時候,可能還不是很明白,為什麼好好的程式要拆分,這麼做的目的又是為了什麼,直接在需要用到的權限的地方寫業務邏輯不就行了麼,這個往下看,咱們說說限界上下文。

三、限界上下文 —— 領域模型的邊界

1、限界上下文是顯示的,有語義的

限界上下文(Bounded Context)定義了每個模型的應用範圍,在每個Bounded Context中確定領域模型的一緻性。不同的限界上下文中,領域模型可以不用保證一緻性。通常我們根據團隊的組織、軟體系統的每個部分的用法及實體表現(如元件劃分,資料庫模式)來設定模型的邊界。

概念還是有點兒朦胧,那就舉例來說:

在電商系統中,銷售子域是核心域,商品子域和物流子域為支撐子域。在這三個子域中,都要和商品打交道。如果把商品抽象為Product對象的話,按我們一般的正常思路(抛開子域的劃分)來說,不管是商品銷售還是發貨,我們都可以共用同一個Product對象。

但在DDD中,在商品子域和銷售子域中,可以共享這個Product對象,但在物流子域,就有點大材小用。為什麼呢?因為畢竟物流子域關注的是商品的發貨處理和物流跟蹤。針對發貨流程而言,我隻關心商品的數量、大小、重量等規格,而不必了解商品的價格等其他資訊。是以說物流子域應該關注的是貨物的發貨處理而不是商品。

那為什麼我們之前的開發思路會共用同一個Product對象呢?

答案很簡單,沒有進行領域的劃分。把整個項目一概而論,統一模組化導緻的結果。

在DDD的思想下,當劃分子域之後,每個子域都對應有各自的上下文。在銷售子域和商品子域所在的上下文語境中,商品就是商品,無二義性。在物流子域的上下文語境中,我們也可以說商品的發貨處理,但這時的商品就特指貨物了。确定了真實面目之後,我想我們也會不由自主的抽象一個新的Cargo對象來處理物流相關的業務。這也是DDD帶來的好處,讓我們更清晰的模組化。

2、定義限界上下文

 在我們上邊的子域定義中,我們出現了三個子域,我這裡同時也定義了三個限界上下文(這裡說下,兩者不是一對一的關系),總體來說,我們不應該按技術架構或者開發任務來建立限界上下文,應該按照語義的邊界來考慮。

我們的實踐是,考慮産品所講的通用語言,從中提取一些術語稱之為概念對象,尋找對象之間的聯系;或者從需求裡提取一些動詞,觀察動詞和對象之間的關系;我們将緊耦合的各自圈在一起,觀察他們内在的聯系,進而形成對應的界限上下文。形成之後,我們可以嘗試用語言來描述下界限上下文的職責,看它是否清晰、準确、簡潔和完整。簡言之,限界上下文應該從需求出發,按領域劃分。

從壹開始微服務 [ DDD ] 之三 ║ 簡單說說:領域、子域、限界上下文前言零、今天要完成綠色的部分一、領域 —— 就是一個獨立項目二、子領域 —— 具體的項目實作三、限界上下文 —— 領域模型的邊界四、結語

3、上下文都包含哪些内容

一個限界上下文不是隻有領域模型,當然這個是必不可少的,它總體來說是一個系統,一個應用程式,或者一個業務服務,它裡邊會有實體,值對象,領域事件(一個個方法事件組成,比如使用者注冊,修改密碼,驗證資訊等等都是該上下文中的領域事件),在我們的身份和通路上下文中,是這樣定義的

從壹開始微服務 [ DDD ] 之三 ║ 簡單說說:領域、子域、限界上下文前言零、今天要完成綠色的部分一、領域 —— 就是一個獨立項目二、子領域 —— 具體的項目實作三、限界上下文 —— 領域模型的邊界四、結語

感覺寫到這裡還是沒有寫的很透徹,因為我們還沒有涉及到代碼,可能通過代碼的設計會比較好。

四、結語

 本文主要是通過DDD領域設計的思想,來說明如何對一個項目進行細分的過程,這個再想想文章開頭提出的問題,是不是稍微有些感觸,隻不過在沒有代碼的講解下,一起總是很空洞,下次咱們直接通過基礎設施層中的上下文定義,來進一步了解領域設計的思想吧。 

轉載于:https://www.cnblogs.com/laozhang-is-phi/p/9845573.html