成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

DDD實戰之看看代碼結構長啥樣

開發 架構
DDD 戰術設計,核心就是完成“領域”層內的“聚合”、“領域服務”的設計,也就是“核心業務邏輯”的設計。

真正開始 DDD 旅程前,我想讓您看到經過 DDD 設計之后的代碼長啥樣。我想,這是所有本著“talking is easy, show me your code”理念的程序員都比較在乎的觀念。

為此,我特別將“群買菜”生鮮電商系統服務端代碼新舊代碼結構都顯示出來,讓您看看原來的舊代碼——也就是“事務腳本式”代碼長啥樣(應該是目前大部分 java 程序員寫代碼的樣子),再讓您看看 DDD 改造設計后的新代碼長什么樣子。然后再通過分析,說清楚為什么傳統的“事務腳本”代碼不是對真實世界的“同構映射”,而 DDD 代碼的“同構映射”在哪。

需要提醒您的是:從今天這個專題開始,可能需要你多花點時間、深入地閱讀我寫的代碼、和文字的每一句話,反復對照著看,甚至來回反復多看幾遍,才能真的去理解這些文字了。

1.舊代碼:事務腳本式(貧血模型)代碼

我們先來看舊代碼的目錄結構截圖。注意看下面的 1、2、3、4 標注位置(解釋下,我這里用的是 spring-boot 開發框架,MyBatisPlus 數據持久框架、MySql5.6 數據庫):

您注意到這里標注的 1、2、3、4 代碼位置了嗎?是不是代碼結構很像大部分 spring-boot 應用框架下代碼結構?為了避免您可能不太了解這種代碼結構,我還是簡單解釋下。

標號 1 位置:這里放的是 Controller(控制器)層代碼,也就是所有前端訪問的接口都在這里實現。按照 MVC 的分層原則,一般來說,這里只會放一些客戶端輸入參數的解析、以及對 service 層(見下文)的業務方法調用。一般來說,這里的代碼都長成下面這樣:

標號 2 位置:這里放的是 entity(數據 bean)層代碼,其實都是 POJO 代碼,所有類都一一對應到數據庫表。一般來說,這里的代碼都長成這樣:

標號 3 位置:mapper 層,對于 mybatis 持久層框架來說,mapper 和 entity 共同實現了 ORM(對象模型到關系模型的映射)。一般來說,這里的代碼長成這樣(這里 CustomerMapper 類只是定義了 entity 類 Customer 的映射關系,以及自定義的數據操作方法):

以及這樣(在 MP 中,只有需要實現自定義的 SQL 操作方法,才需要這個 CustomerMapper.xml 文件):

標號 4 位置:Service(服務)層,這里是所有業務邏輯實現的核心代碼處,幾乎所有的業務邏輯都是在這里實現的。一般來說,這里會有 interface+implementation 組合的實現方式。比如:OrderService 和 OrderServiceImpl,分別長下面這樣:

OrderService 接口類:

OrderServiceImpl 實現類;

從上面的代碼中 ,我們可以很明顯地看出如下幾點:

  • Controller/entity/mapper 基本上都是利用框架的 annonation(注解)和公共工具類代碼(如 json 解析等)實現的很少的代碼;
  • 顯然,大部分業務邏輯都是在 Service 層的實現類里面實現的;
  • Service 層實現類代碼的邏輯寫的很長,且完全是“平鋪直述”的。我這里展示的 OrderSeriveImple 的 create 方法——創建訂單,就寫了 135 行。從我的代碼截圖中的注釋可以看出來,我是想好了一步一步要怎么對數據庫進行 CRUD,先填寫好注釋,然后寫代碼的。這種代碼,說白了就是“CRUD+計算邏輯”組合的代碼;
  • 事實上,這種“平鋪直述”式的代碼,是很容易被程序理解的,寫起來也很容易,基本上不用“殺死”太多腦細胞,所以團隊很容易就開始實施項目工程,隨便找一個具有基本 java 編程經驗(一般一年以上經驗即可)就能夠開始著手業務代碼的開發;
  • 這種代碼,我們就叫做”事務腳本式”代碼,或者說叫“貧血模型”代碼。

之所以叫“事務腳本”,我個人的理解:本質上跟 20 年前寫數據庫存儲過程代碼沒有本質區別(只是換了個語言書寫、運行代碼的位置從數據庫服務器內部提到了應用服務器);

又之所以叫“貧血模型”代碼,是因為 entity 層的那些 POJO 對象如 Order 等,沒有任何業務行為的封裝(比如:Order 類應該自己生成自己的訂單號、提貨號等),只有屬性而沒有行為的對象,就是“貧血”對象,基于“貧血”對象實現的業務邏輯代碼,就叫“貧血模型”代碼。

根據這里的代碼分析,我們是不是能夠發現一個關鍵問題:這里的 Controller/entity/mapper/service,事實上和真實世界的業務之間關系,是沒有任何映射的——也就是說:“代碼世界”和“真實世界”是異構的。具體來說,我們可以分以下幾點來看。

首先,從業務模塊劃分這個“最粗”的粒度來說,我們其實是可以簡單的、憑直覺進行模塊劃分的,不用全部業務模塊放在一個工程項目中,是可以按照業務模塊(比如:店鋪管理、訂單管理、商品管理等)進行項目目錄劃分、也就是項目團隊分組的。

事實上,目前市面上的大多數軟件公司,就是根據業務經驗或直覺簡單粗暴的將項目劃分了多個團隊在進行開發。但這種劃分方式,雖然也可以七七八八準確——但我們需要意識到的是,這樣簡單粗暴的憑經驗直覺的劃分,跟 DDD 方法論做的設計劃分相比(劃分到限界上下文這個粒度的設計,在 DDD 中叫做“戰略設計”),至少有 3 個不足:

  • 軟件代碼如何劃分是嚴格的“工程性問題”,而所有工程性問題,往往會“差之毫厘謬以千里”!這種經驗直覺的劃分,很可能會遺漏掉一些很重要的“限界上下文”識別。而正因為這些重要的“限界上下文”的遺漏,導致了一些模糊地帶,發現要么是沒必要的模塊間耦合、要么是沒必要的重復。
  • DDD“限界上下文”的識別,不但要區分出到底要劃分為幾個模塊(其實“模塊”是個很模糊的詞,可以用來劃分微服務、也可以用來劃分代碼目錄結構,視需要而定),還需要識別這些“限界上下文”之間的協作關系和邊界。而這些協作關系,才真正“清晰準確、代碼行級”定義了哪些代碼歸屬模塊 A、哪些代碼歸屬模塊 B——也就是邊界,以及這些模塊是通過 RPC 或本地調用關系在協作、還是異步消息事件在協作、甚至直接就沒有協作。
  • 一般來說,DDD 的“限界上下文”需要對應到業務子領域,而業務子領域的重要程度將決定限界上下文的重要程度。業務子領域針對某個具體的軟件系統來說,是可以從業務角度判斷出哪些必須建設為軟件的核心競爭力、哪些則可以作為次要模塊甚至通過外包來實現。這些對“限界上下文”模塊的不同“重要程度”定義,將會促使項目管理層從效率的角度采用不同的技術棧。比如:目前市面上不同的程序員薪資水平是不同的、招聘難度是不同的;不同技術棧的成熟程度、可適用的編程特性是不同的(比如:java 比較成熟適合企業級應用開發,而 python 適合數據處理類開發,node.js 適合跟第三方互聯網系統連接等)。

其次,到模塊內部,其代碼的層次結構劃分,如果按照 mvc 思想,最后還是又回到了類似 controller/entity/mapper/service 這樣的劃分方式。而這種劃分方式,又和“真實世界”有什么同構映射關系呢?可以說,沒有!

所以,最終我們還是可以得出結論:這種傳統的代碼架構,是沒有考慮和真實世界的“同構映射”的。而這種對“同構映射”的缺失,才是導致我們出現“真實業務其實沒多大變化、但某個需求卻為什么引起軟件代碼翻天覆地的變化呢?”這樣疑惑的根本原因——DDD 方法論,就是用來解決這個問題的!

2.新代碼:DDD 設計代碼(充血模型)

我們再來看看使用 DDD 設計后,新的代碼結構長什么樣。下面是新代碼的結構截圖(同樣注意下面的 1~8 標號):

對上面的代碼標號位置,我來逐個解釋如下(需要說明的是:這里目錄排序是 IDEA 開發工具自動按字母順序排序,不是代碼設計先后順序):

標號 1 位置:這里放的是邊緣層(edge)代碼。由于“群買菜”小程序前端界面已經開發完成,并且這是一個前后端分離項目,前端代碼我并沒有打算修改,所以這里就多了個“界面適配”的代碼工作。一般來說,這種代碼就叫“邊緣層”。邊緣層放的代碼,都是類似這種為了前端界面適配、第三方系統接口適配之類的代碼。這種代碼,也可以叫做“為前端提供的后端”(Backend for Frontend, BFF)。理論上,這種 BFF 層的代碼,可以由前端團隊開發的,我可以選擇技術棧是 Node.js,使用 js 或 ts 語言進行開發。

標號 2 位置:這里顯示的是“基礎層”(foudation)。在 DDD 的系統架構中,限界上下文(具體概念介紹見后面,這里你只需要理解為它類似于子系統或業務模塊劃分就好)是可以根據“業務子域”不是核心層,而分為“基礎層”和“業務價值層”。一般來說,“業務價值層”對應到最核心的業務模塊,是一個軟件系統的核心競爭力所在,是需要嚴格按照 DDD 的理念進行戰術設計、并采用測試驅動開發模式、投入最懂業務的程序員去工作的;而“基礎層”一般都是非核心業務模塊,比如:業務相關基礎類、工具類、伴生系統的對接等——需要注意的是:“基礎層”不是“基礎資源層”,基礎層指的是業務模塊處于非核心地位、而基礎資源指的是數據庫、中間件這些技術組件。

標號 3 位置:這里顯示了多個限界上下文,都是以 xxxcontext 這樣的目錄取名。在“基礎層”和“業務價值層”中,都會出現多個“限界上下文”。每個限界上下文可以分離到不同的項目團隊去負責、甚至分離到不同的微服務中心中。還是那句話,現在你還不用太深入的理解“限界上下文”,暫時只需要理解它是一種模塊劃分的說法就好(后面會逐步深入解釋)。

標號 4 位置:這里顯示出來了“業務價值層”的代碼——也就是該軟件系統中需要作為最核心競爭力的那些模塊,同樣下面也會有多個“限界上下文”。

標號 5 位置:DDD 戰術設計軟件分層的“菱形架構”下,“領域”(domain)層的代碼放這里,也是業務邏輯最核心的代碼——所有的“充血”模型代碼。從這里開始,我們解釋某個“限界上下文”內的代碼結構。具體這些代碼怎么設計的細節,我們后面會講,現在你只需要知道這里放的是“業務邏輯核心”即可。

標號 6、8 位置:在 DDD 戰術設計軟件分層的“菱形架構”下,為了讓“限界上下文”在滿足外部的各種調用需求、以及需要調用或與別的“限界上下文”通訊時,不至于因為與本模塊業務邏輯無關的、各種外在因素變化而引起本模塊內代碼邏輯的“動蕩不安”,而引入了“北向網關”、“南向網關”概念。分別說明如下:

標號 6 就里面就是“北向網關”的代碼,里面又分為 local 和 remote 兩個典型的目錄。“北向網關”的作用,就是讓限界上下文可以向外輸出各類應用服務。local 目錄下方的是本限界上下文向外提供的“應用服務”,是將 domain 內各種“充血模型”代碼進行封裝后的、完整的業務邏輯;而 remote 目錄下,放的是對 local 目錄為了滿足“遠程調用”而進行的代碼封裝——如 RPC 調用、跨服務器消息事件訂閱等,并不存在任何業務邏輯。

標號 8 里面就是“南向網關”的代碼,里面又分為“端口(port)”和“適配器(adaper)”兩個典型的目錄?!澳舷蚓W關”的作用,就是是讓本限界上下文通過其請求外部資源。典型的 3 類外部資源請求有:訪問數據持久層(關系或非關系數據庫)、調用別的限界上下文服務(在微服務架構中,往往是 RPC 遠程調用)、向別的限界上下文發布消息。我們都知道,這些對外部資源的請求,可能會因為外部資源的技術底層不同,而存在不同的實現方式。為了能夠隔離“領域層”對具體技術底層的依賴,就分離出來 port 層和 adapter 層。在 java 語言實現中,port 層就是 interface,沒有任何實現代碼,只有方法定義;而 adaper 層就是 implemetaion,具體實現到不同持久層(如不同關系數據庫 oracle/mysql 等、不同 nosql 數據庫 redis/mongodb 等)。然后,根據 IoC(依賴倒置)原則在 java 中通過“依賴注入”來將 adaper 目錄下的具體實現與 domain 層的代碼連接起來。

標號 7 位置:這里是“發布語言”(published language, pl)層。說白了,“發布語言”就是讓“北向網關”向外輸出服務時,能與服務調用者之間有個“統一語言”,比如:輸入輸出參數的結構性定義、事件消息的格式定義等等。因為,我們是不用將限界上下文內部的“領域”層的內部對象結構“泄露”到外部的,所以我們必須要有這個“發布語言”層。

3.結論

好了,解釋完了按照 DDD 進行的代碼結構設計,我們還是要回答一個問題:DDD 對真實世界進行“同構映射”后的代碼邏輯到底在哪里呢?

答案是:在“領域”(Domain)層里面!所謂的“北向網關”、“發布語言”、“南向網關”層的作用,都只是為了讓外部的請求、被請求資源的底層技術,不要去“打擾”我們“業務邏輯”的“同構化”映射!

這就相當于是說:領域層才是 DDD 對“業務邏輯”映射后的核心,其它都只是對這些“核心業務邏輯”的層次“包裝”而已!

那么,顯然,從技術角度來說,懂得領域層如何設計才是 DDD 戰術設計層面最重要的技能!因為,“北向網關”、“發布語言”、“南向網關”這 3 層的代碼開發,都是常規套路,沒啥“業務知識”含量,甚至可以用機器人來實現(也就是通過代碼自動生產工具)。

最后,解釋下反復提到的 DDD 戰略設計和戰術設計的區別:

大體上來說,DDD 戰略設計,就是識別出有哪些限界上下文、以及清晰的定義限界上下文的關系和邊界,就基本完成了(雖然還有些修修補補的工作,比如要不要邊緣層、本軟件系統跟哪些第三方外部系統接口等,但這些其實已經不能叫“設計”了,因為不需要花多少腦子了);

DDD 戰術設計,核心就是完成“領域”層內的“聚合”、“領域服務”的設計,也就是“核心業務邏輯”的設計。具體怎么玩,我后面會一點點演示。

責任編輯:武曉燕 來源: 逸言
相關推薦

2021-12-07 07:01:21

Python病毒 文件

2017-11-08 13:31:34

分層架構代碼DDD

2014-11-05 10:08:50

2022-10-10 11:32:01

數據分析技術

2020-01-09 10:03:41

AI 數據人工智能

2015-09-11 09:59:04

阿里云數據中心

2020-04-29 09:30:48

Google面試題工程師

2021-02-06 14:36:39

數字人民幣數字貨幣區塊鏈

2011-09-29 10:13:54

IBM私有云云計算

2013-10-29 09:35:54

Windows 9概念圖

2020-04-16 12:04:09

5G基站4G

2021-06-24 05:39:16

Windows 1操作系統微軟

2020-11-02 07:59:40

高并發系統業務

2025-02-24 09:56:13

交換機網絡通信

2020-01-07 08:44:33

5G網絡4G

2013-12-03 10:33:51

微軟Windows 9

2023-04-27 11:30:44

2020-06-28 08:22:48

淘寶數據粽子

2009-11-20 09:19:43

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91网站视频在线观看 | 99视频免费播放 | 精品视频一区二区三区在线观看 | 成人日韩 | 亚洲午夜在线 | 午夜成人免费视频 | 日韩一级免费观看 | 中文字幕一级毛片 | 国产精品亚洲欧美日韩一区在线 | 天堂一区二区三区 | 欧美一级特黄aaa大片在线观看 | 成人激情视频在线播放 | 亚洲性网| 蜜桃视频在线观看免费视频网站www | 国产精品久久久久久久午夜片 | 国产精品精品视频一区二区三区 | 国产精品久久久久久久久久久久冷 | 亚洲成av人影片在线观看 | 91麻豆精品一区二区三区 | 一级看片免费视频囗交动图 | 欧美视频三区 | 国产在线播 | 欧美日本在线观看 | 91人人澡人人爽 | 久久国产精品偷 | 免费精品视频一区 | 久久国产一区二区三区 | www狠狠爱com | 九九色综合 | 久久99国产精品 | 伊人久久伊人 | 日日干日日操 | 日韩欧美大片在线观看 | 午夜影晥| 国产激情91久久精品导航 | 欧美日韩一 | 成人午夜网站 | 91国自视频 | 在线播放中文字幕 | 久草精品视频 | 激情在线视频 |