實現領域驅動設計

193值對象的特徵.......................... 271訊息設施的一致性........................... 357領域服務中的工廠..........................

圖書信息

書名:實現領域驅動設計
宣傳語:DDD之父作序力薦 讓DDD思想真正落地的首創巨著
作者:Vaughn Vernon(沃恩.弗農)著
譯者:滕雲 譯
ISBN:978-7-121-22448-5
出版時間:2014年3月出版
定價:99.00元
頁數:584頁
開本:16開

編輯推薦

著譯俱佳 ThoughtWorks資深諮詢師傾力譯、校,完整涵蓋DDD各方面知識提供大量示例代碼,案例貫穿全書 理論與實踐緊密銜接之典範,架構師、程式設計師境界提升不可或缺之必選書目。

目錄

序............... xix
前言............. xxi
致謝............ xxxi
關於作者................... xxxv
如何使用本書.........xxxvii
第1章 DDD入門...............1
我能DDD嗎?..................2
為什麼我們需要DDD.............5
如何DDD...................... 17
使用DDD的業務價值..............22
1.你獲得了一個非常有用的領域模型................22
2.你的業務得到了更準確的定義和理解............23
3.領域專家可以為軟體設計做出貢獻...........23
4.更好的用戶體驗....................23
5.清晰的模型邊界.....................24
6.更好的企業架構..............24
7.敏捷、疊代式和持續建模....................24
8.使用戰略和戰術新工具........................24
實施DDD所面臨的挑戰.....................25
虛構的案例,真實的實踐................... 33
本章小結.........................36
第2章 領域、子域和限界上下文.....................37
總覽....................... 37
工作中的子域和限界上下文............................. 38
將關注點放在核心域上............................. 42
戰略設計為什麼重要.................... 45
現實世界中領域和子域...................48
理解限界上下文..................... 53
限界上下文不僅僅只包含模型..................... 57
限界上下文的大小...................... 59
與技術組件保持一致................... 61
示例上下文........................ 62
協作上下文..................63
身份與訪問上下文..................69
敏捷項目管理上下文................. 71
本章小結....................................73
第3章 上下文映射圖............................75
上下文映射圖為什麼重要........................ 75
繪製上下文映射圖......................77
產品和組織關係........................79
映射3個示例限界上下文........................82
本章小結............................97
第4章 架構.......................99
採訪一個成功的CIO.................... 100
分層................................. 104
依賴倒置原則.................... 107
六邊形架構(連線埠與適配器)..................... 110
面向服務架構.......................114
REST................................117
REST作為一種架構風格...........................117
RESTful HTTP伺服器的關鍵方面 ........................................ 118
RESTful HTTP客戶端的關鍵方面 ........................................ 119
REST和DDD..................... 120
為什麼是REST?......................... 121
命令和查詢職責分離——CQRS................. 121
CQRS的各個方面........................ 123
處理具有最終一致性的查詢模型.................. 128
事件驅動架構................... 129
管道和過濾器..................... 131
長時處理過程(也叫Saga)................... 134
事件源...................... 140
數據網織和基於格線的分散式計算....................... 143
數據複製..................... 144
事件驅動網織和領域事件.................. 145
持續查詢................... 145
分散式處理...................... 146
本章小結............................ 148
第5章 實體......................... 149
為什麼使用實體......................... 149
唯一標識............................ 151
用戶提供唯一標識......................... 152
應用程式生成唯一標識........................... 153
持久化機制生成唯一標識............................ 156
另一個限界上下文提供唯一標識..................... 160
標識生成時間..................... 161
委派標識......................... 163
標識穩定性.......................... 165
發現實體及其本質特徵............................. 167
揭開實體及其本質特徵的神秘面紗................. 168
挖掘實體的關鍵行為.......................... 172
角色和職責......................... 176
創建實體......................... 181
驗證................................... 183
跟蹤變化............................ 192
本章小結................................ 192
第6章 值對象..................... 193
值對象的特徵.......................... 194
度量或描述.......................... 195
不變性........................... 195
概念整體................................ 196
可替換性.......................... 199
值對象相等性..........................200
無副作用行為............................. 201
最小化集成..................204
用值對象表示標準類型........................206
測試值對象........................ 210
實現.............................. 214
持久化值對象................. 219
拒絕由數據建模泄漏帶來的不利影響..................220
ORM與單個值對象................................ 221
多個值對象序列化到單個列中.....................224
使用資料庫實體保存多個值對象....................225
使用聯合表保存多個值對象..........................229
ORM與枚舉狀態對象........................................230
本章小結....................... 233
第7章 領域服務.................................235
什麼是領域服務(首先,什麼不是領域服務).................. 237
請確定你是否需要一個領域服務................................ 238
建模領域服務.................. 241
獨立接口有必要嗎.............................244
一個計算過程..........................246
轉換服務........................249
為領域服務創建一個迷你層.........................250
測試領域服務............................250
本章小結.................. 253
第8章 領域事件...............................255
何時/為什麼使用領域事件.......................... 255
建模領域事件.................... 258
創建具有聚合特徵的領域事件................... 263
身份標識............................264
從領域模型中發布領域事件.............................. 265
傳送方................... 265
訂閱方.....................269
向遠程限界上下文發布領域事件............................. 271
訊息設施的一致性........................... 271
自治服務和系統............................. 272
容許時延.................. 273
事件存儲.................. 274
轉發存儲事件的架構風格........................... 279
以REST資源的方式發布事件通知....................... 279
通過訊息中間件發布事件通知.................. 283
實現............................284
發布NotificationLog............... 285
發布基於訊息的事件通知..............................290
本章小結........................297
第9章 模組................................299
通過模組完成設計..................................299
模組的基本命名規範..........................302
領域模型的命名規範...........................302
敏捷項目管理上下文中的模組..............................305
其他層中的模組..................308
先考慮模組,再是限界上下文...............................309
本章小結......................... 310
第10章 聚合...................... 311
在Scrum核心領域中使用聚合........................ 312
第一次嘗試:臃腫的聚合....................... 313
第二次嘗試:多個聚合........................... 314
原則:在一致性邊界之內建模真正的不變條件................317
原則:設計小聚合............................. 319
不要相信每一個用例............................ 321
原則:通過唯一標識引用其他聚合......................... 322
通過標識引用使多個聚合協同工作 ...................................... 324
建模對象導航性............................ 325
可伸縮性和分散式............................. 326
原則:在邊界之外使用最終一致性............................. 327
誰的任務?............................ 328
打破原則的理由......................... 329
理由之一:方便用戶界面................................. 329
理由之二:缺乏技術機制............................. 330
理由之三:全局事務.......................................... 331
理由之四:查詢性能.................................. 331
遵循原則.................... 332
通過發現,深入理解............................... 332
重新思考設計............................... 332
估算聚合成本............................. 334
常見用例場景........................ 335
記憶體消耗............................ 336
探索另外的設計................................... 337
實現最終一致性.............................. 338
這是Scrum團隊成員的任務嗎?......................... 339
決定的時候到了.............................. 341
實現........................................ 341
創建具有唯一標識的根實體........................ 342
優先使用值對象...................... 343
使用迪米特法則和“告訴而非詢問”原則 ...............344
樂觀並發...............346
避免依賴注入................348
本章小結................................ 349
第11章 工廠................. 351
領域模型中的工廠................. 351
聚合根中的工廠方法............................. 352
創建CalendarEntry實例................... 353
創建Discussion實例............................ 357
領域服務中的工廠.......................... 358
本章小結.......................... 361
第12章 資源庫...........................363
面向集合資源庫...........................364
Hibernate實現...................... 369
TopLink實現.................... 377
面向持久化資源庫........................ 379
Coherence實現............................ 381
MongoDB實現......................... 386
額外的行為...................................... 391
管理事務................................. 393
警告................................. 397
類型層級............................... 397
資源庫 vs 數據訪問對象(DAO)..............................400
測試資源庫.......................................... 401
以記憶體實現進行測試...................404
本章小結................................407
第13章 集成限界上下文...............................409
集成基礎知識....................................409
分散式系統之間存在根本性區別.......................411
跨系統邊界交換信息...............................411
通過REST資源集成限界上下文......................... 417
實現REST資源.......................... 418
使用防腐層實現REST客戶端........... 421
通過訊息集成限界上下文................ 428
從Scrum的產品負責人和團隊成員處得到持續通知 .................... 428
你能處理這樣的職責嗎?..................... 434
長時處理過程,以及避免職責............. 439
長時處理過程的狀態機和逾時跟蹤器 .................................. 450
設計一個更複雜的長時處理過程 ..........................................460
當訊息機制或你的系統不可用時 ...........................................464
本章小結.................................465
第14章 應用程式..................467
用戶界面...................................469
渲染領域對象............. 470
渲染數據傳輸對象................... 471
使用調停者發布聚合的內部狀態 .......................................... 471
通過領域負載對象渲染聚合實例 .......................................... 472
聚合實例的狀態展現............................. 473
用例最佳化資源庫查詢...................... 474
處理不同類型的客戶端................... 474
渲染適配器以及處理用戶編輯............. 475
套用服務 ............................................ 478
示例套用服務 ................................ 478
解耦服務輸出 .....................485
組合多個限界上下文 .....................487
基礎設施 ...............................489
企業組件容器 ....................490
本章小結 ....................494
附錄A 聚合與事件源:A+ES ..........................495
套用服務內部 ....................... 496
命令處理器 .....................505
Lambda語法...................508
並發控制 ....................... 510
A+ES所帶來的結構自由性 .............. 513
性能 ............................ 513
實現事件存儲 ..................... 516
關係型持久化 .................. 520
BLOB持久化 ...................... 522
專注的聚合 ............................ 523
讀模型投射 ........................... 524
與聚合設計一道使用 ................ 527
增強事件 ........................... 527
工具和模式 ................... 529
事件序列器 .......... 530
事件不變性 ................ 531
值對象 ..................... 531
協定生成 .................... 534
單元測試和需求規範 .............. 535
事件源和函式式語言 .......... 536
參考文獻 ..................539

作者簡介

Vaughn Vernon是一個經驗豐富的軟體工匠,在軟體設計、開發和架構方面擁有超過25年的從業經驗。他提倡通過創新來簡化軟體的設計和實現。從20世紀80年代開始,他便開始使用面向對象語言進行編程;在 20世紀 90年代早期,他便在領域建模中套用了領域驅動設計,那時他使用的是Smalltalk語言。他在很多業務領域都有從業經驗,包括航空、環境、地理、保險、醫學和電信等領域。同時,Vaughn在技術上也取得了很大的成功,包括開發可重用的框架和類庫等。他在全球範圍之內提供軟體諮詢和演講,此外,他還在許多國家教授《實現領域驅動設計》的課程。你可以通過個人網站訪問到他的最新研究成果。他的Twitter:@VaughnVernon。

媒體評論

“在《實現領域驅動設計》中,Vaughn不僅為DDD領域做出了卓越的貢獻,還為更寬闊的企業套用架構領域寫上了厚重的一筆。例如,在架構和資源庫等核心章節中,Vaughn向我們展示了如何將DDD與各種架構風格和持久化技術融合在一起——包括SOA、REST、NoSQL和數據格線等——其中很多都是在Eric Evans那本DDD開山之作出版之後才出現的。另外,書中還講到了對實體、值對象、聚合、領域服務、事件、工廠和資源庫的實現,其中包括大量的例子。一言以蔽之,我認為這本書非常全面。對於那些希望提升自己技能的軟體開發者來說,《實現領域驅動設計》將是一本絕佳的好書。”
——Randy Stafford,自由架構師,Oracle Coherence產品部
“領域驅動設計是一套非常強大的思想工具,它深遠地影響著軟體開發團隊的效率。問題在於,許多開發者在套用這套思想工具時會不時地迷失方向,他們需要更實際的指導建議。在本書中,Vaughn將理論與實踐聯繫在了一起。除了為我們講解那些易被誤解的DDD概念之外,Vaughn還講到了一些新的概念,比如命令/查詢職責分離(CQRS)和事件源等。對於那些希望實際套用DDD的人來說,這是一本必讀之作。”
——Udi Dahan,NServiceBus創始人
“多年以來, DDD的開發者們都希望獲得一些更實際的幫助。 Vaughn縫合了理論和實踐之間的間隙,向大家提供了一套完整的 DDD實現參考。他向我們展示了如何在當前軟體項目中使用DDD,並且向我們提出了大量的實際建議。 ”
——Alberto Brandolini,DDD導師(由 Eric Evans和Domain Language, Inc頒發證書)
“《實現領域驅動設計》清晰地向我們展示了 DDD的核心話題。本書的寫作風格非常友好,就像一個值得信賴的導師在給你講課一樣。讀完本書,你將能夠套用 DDD的各個重要概念。我在閱讀本書的時候,在很多章節中都做上了著重標記……我會經常地參考並推薦本書。”
——Paul Rayner,首席諮詢師, DDD導師(由 Eric Evans和Domain Language, Inc頒發證書), DDD Denver創始人。
“在我所教的 DDD課程中,很重要的一點便是如何將所有的 DDD理論付諸實踐。有了本書, DDD社區便有了可供參考的資料。《實現領域驅動設計》包含了創建 DDD系統的方方面面,從具體的實現細節到高層的設計思想。這是一本了不起的 DDD參考書,同時也是 Eric Evans那本 DDD開山之作的極佳伴侶。 ”
——Patrik Fredriksson,DDD導師(由 Eric Evans和Domain Language, Inc頒發證書)
“如果你關心軟體工藝——你也應該這么做——那么領域驅動設計便是非常重要的一項技能,而《實現領域驅動設計》則向我們提供了一條邁向成功的捷徑。本書詳盡地討論了 DDD的戰略模式和戰術模式,使開發者能夠立即將理論付諸實踐。今後的業務軟體系統將從本書中受益匪淺。”
——Dave Muirhead,首席諮詢師, Blue River Systems 集團
“DDD既有理論,也有實踐,這些都是每個開發者應該了解的,而本書則很好地彌補了理論與實踐之間的差距。強烈推薦本書! ”
——Rickard Oberg,Java開發者, Neo Technology公司
“在《實現領域驅動設計》中, Vaughn採用了自頂向下的方法,首先講到了 DDD的戰略模式,比如限界上下文和上下文映射圖,然後講到了戰術模式,比如實體、值對象和領域服務等。案例研究貫穿全書,要從中有所學,你需要在該案例研究上下足功夫。如果你這么做了,你便能看到將 DDD套用於複雜領域的意義所在。書中包含了大量的旁註、圖示和示例代碼。如果你希望使用當下最常見的架構風格來創建一個 DDD系統,那么 Vaughn的這本《實現領域驅動設計》便是我所推薦的。”
——Dan Haywood,《Domain-Driven Design with Naked Objects》作者
“本書採用了一種自頂向下的方式來講解 DDD,這種方式將 DDD的戰略模式和戰術模式自然地銜接起來。在本書中, Vaughn強調了業務領域的價值,同時也給出了技術上的討論。因此, DDD在軟體開發中的角色也變得非常清晰。很多時候,我的團隊,包括我本人,在套用 DDD時都會遇到這樣那樣的麻煩。有了《實現領域驅動設計》的指導,我們得以克服種種挑戰,進而將付出立即轉化為業務價值。 ”
——Lev Gorodinski,首席架構師, DrillSpot

前言

所有的計算都表明它不工作,唯一的做法是:使其工作。 ——Pierre-Georges Latécoère早期法國航空企業家
是的,我們將使其工作。然而,在軟體開發過程中採用領域驅動設計卻是困難的。即便是有能力的開發者,也很難找到實現領域驅動設計的正確方法。
起飛,著陸
在我小的時候,我的父親學習過駕駛小型飛機。我們經常會全家出去飛行,有時會飛到另一個機場,在那裡吃過午飯後再返回。當父親時間有限而他依然想飛時,父親便帶上我一起在機場上空盤鏇,起飛,著陸,再起飛,再著陸。
也會有些長途飛行,這時我們會帶上一張由父親先前繪製好的路線圖。我們幾個小孩便當起了領航員:將圖上的標誌對應著陸地上的地標,以確保我們沒有跑偏航線。這是一件很有趣的事情,因為要識別遠在地面上的物體是很有挑戰性的。事實上,我敢肯定父親根本不用我們領航便知道我們處於什麼方位——他能看到儀錶盤上的所有信息,並且他擁有儀表飛行執照。
空中的景觀的確改變了我的視野。不時地,父親和我會飛過我們鄉下的房子。在幾百英尺的高空中,我體會到了另一種“家”的概念,而這在之前是沒有過的。當我們飛過自家的房子時,母親和我的姐妹們便會跑到院子裡向我們揮手。我知道那是她們,即便我看不清楚她們是誰。談話肯定是不行的,連大聲喊都不行,她們是聽不見的。我還可以看到將我家和外面公路分開的護欄,平時我們會像走平衡木一樣在護欄上面走來走去。從空中看,它們就像被細心編排過的小樹枝一樣。我們
家的院子很大,每每到了夏天,我都會開著割草機一排一排地修理院子裡的草坪。而在空中時,我只能看到一片綠色,小草的葉子肯定是看不清楚的。
我喜歡在空中的時刻,直到現在我還不時回想起這些時刻,好像那個降落飛
機的黃昏就發生在不久以前一樣。雖然如此,在地面上的感覺依然是無法取代的,
因為它給我一種腳踏實地的感覺。
著陸於領域驅動設計
一開始接觸領域驅動設計( DDD)就像一個小孩之于飛行一樣。天空中的景色是令人驚嘆的,但有時我們卻因為過於陌生而搞不明白它們到底是什麼。要從甲地到乙地顯得如此的遙遠。然而, DDD的“成年人 ”們卻總知道他們所處的方位,因為他們在很早之前便繪製好了路線圖,並且能夠完全按照儀表進行相應的操作。而還有很多人找不到“在地面上”的感覺,此時我們需要的是“穩定著陸”的能力,然後找到一張地圖給我們指引方向。
Eric Evans的《領域驅動設計:軟體核心複雜性應對之道》是一本經得住時間考驗的經典之作。我堅定地相信,在接下來的幾十年里,本書依然會是開發者的實用指導。和其他模式一樣,該書為我們建立起了一種高屋建瓴式的寬闊視野。然而,對於如何實現 DDD,我們可能將面對更多的挑戰。通常來說,我們更渴望看到一些具體的例子。
我的目標之一便是幫助你來一個“軟著陸”,保全飛機,然後沿著一條周知的線路帶你回家。這將幫助你如何更好地去實現 DDD,並且通過你所熟悉的工具和技術給出示例演示。當然,任何一個人都不可能一直呆在家裡,所以我還會帶領你到新的地帶去冒險,這些地帶你可能從來沒有去過。冒險之路是險峻的,但是在正確的戰術應對下,征服這些困難是可能的。在這條冒險之路上,你將學到另外的架構和模式來集成多個領域模型。你將接觸到先前沒有被研究過的集成方法,並且學到如何開發自治性服務。
我將向你提供一張對短途旅行和長途旅行均適用的地圖,它可以幫助你更好地享受沿途風景,同時又不至於迷失途中。
對照地形,繪製飛行圖
在軟體開發的過程中,我們經常做的一件事便是將一種東西映射到另一種東西。我們將對象映射到資料庫,映射到用戶界面,或者映射到不同的套用層展現(包括作為消費方的其他系統或應用程式)。在所有這些映射中,我們很自然地希望在Evans提出的高層模式和具體實現之間存在一種映射。
即便你已經接觸過 DDD,你依然有很多可以獲益的地方。有時, DDD首先被看作是一套技術工具集,有人將此稱為 DDD-Lite。我們可能已經對實體、服務等 DDD概念非常熟悉了,並且大膽地嘗試著設計聚合,還通過資源庫來管理持久化。這些模式是大家相對熟知的,使用起來很容易,我們甚至還使用了值對象。以上這些都屬於戰術設計模式範疇,也即更加偏向技術層面。這些模式可以很好地幫我們解決軟體問題。而同時,對於戰術性模式,我們依然有許多需要學習的。我將戰術模式映射到實現層面。
你曾了解過戰術建模之外的東西嗎?你曾了解過被稱為 DDD“另一半”的戰略設計模式嗎?如果你還沒有使用過限界上下文和上下文映射圖,那么你很有可能也沒有使用過通用語言。
如果說 Evans在軟體開發社區有一項發明,那便是通用語言。通用語言是一種團隊協作模式,用於捕捉特定業務領域中的概念和術語。一個特定領域的軟體模型通過不同的名詞、形容詞和動詞來表達,這些辭彙是開發團隊正式使用的,而團隊中應該包含一個或多個領域專家。然而,將通用語言僅限定於一些辭彙則是錯誤的。就像自然語言反映人們的思想一樣, DDD的通用語言反映了領域專家對於軟體系統的思維模型。通用語言和那些戰略和戰術性的建模模式同等重要,在有些情況下甚至更具有持久性。
簡單地講, DDD-Lite將導致劣質的領域對象,因為通用語言、限界上下文和上下文映射圖的作用太大了,你從其中獲得的並不只是一套團隊共用的語言。在限界上下文中用通用語言來表述一個領域模型可以增加業務價值,並且使我們確信所開發軟體的正確性。即使從技術的角度,它也可以幫助我們創建更好的領域模型,這樣的模型行為豐滿,業務純淨,並且可以減少犯錯誤的可能性。因此,我將戰略設計模式映射到了可理解的實際例子中。
本書對於 DDD的映射可以幫助你同時體會到戰略設計和戰術設計的好處。通過一些具體的例子,你將感受到這些 DDD映射的業務價值和技術展現力。
如果我們對於 DDD的所有實踐都只是停留在“地面上”,那將是令人失望的。過度地拘泥於細節將使我們喪失在空中俯瞰的機會。所以,不要將自己局限在地面的細節上,要勇敢地飛翔在空中,居高臨下。搭上戰略設計的航班,去了解限界上下文和上下文映射圖,你將獲得更廣闊的視野。當你從 DDD的航班中獲益時,我的目的也就達到了。
各章概要
以下是各章的主要內容以及你將如何從中獲益。
第1章:DDD入門
本章向你介紹 DDD的好處,並且教你如何儘可能多地去實現 DDD。你將學到當你在應對複雜的軟體系統時, DDD可以為你的項目和團隊帶來什麼。同時,你將了解到通常的 DDD替代方案以及這些方案為什麼會導致問題。作為對 DDD的基礎講解,本章將教你如何在項目中開始採用 DDD,還有如何向你的領域專家和技術團隊推銷 DDD。在DDD的武裝下,你將學會如何迎接挑戰,勇往直前。
本章將介紹關於一個公司及其團隊的案例研究,雖然該公司是虛構的,但是他們所面臨的 DDD挑戰卻是真實存在的。該公司旨在開發一個新的多租戶 SaaS(Software as a Service,軟體即服務)軟體產品。不出所料,在使用 DDD時,他們犯了一些常見的錯誤。不過還好,他們發現了這些錯誤,並解決了一些問題,因此項目還算沒有偏離正軌。該團隊需要開發一套基於 Scrum的項目管理軟體。該案例還會在本書的後續章節中連續講到。每一種戰略和戰術模式都將教給這個團隊。在這個過程中,團隊有誤入歧途的時候,但最終他們將向著成功的 DDD實踐昂首闊步。
第2章:領域、子域和限界上下文
領域、子域和核心域分別是什麼?限界上下文是什麼,我們為什麼要使用它,並且如何使用?這些問題將在這個 SaaS項目團隊犯錯誤的時候給予解答。在他們的第一個 DDD項目中,他們並不了解子域、限界上下文和通用語言這些概念。事實上,他們根本不知道什麼是戰略設計,只是採用了戰術設計來解決一些技術問題。這樣他們在開始設計領域模型的時候便遇到了不少問題。幸運的是,他們及時地意識到了這些問題,項目還有挽回的餘地。
本章還講到了如何使用限界上下文對模型進行分離,這是非常重要的;同時還講到了一些模型分離不當的反例,並且給出了有效的實現建議。在採用了這些建議之後,該團隊的成員們重新創建了兩個不同的限界上下文。這種合理的模型分離帶來的好處是引出了第三個限界上下文——核心域,這將是本書使用的主要例子。
對於那些苦於單單從技術層面套用 DDD的人來說,本章應該能引起你的共鳴。如果你還是 DDD戰略設計的外行,那么本章將為你指明方向。
第 3章:上下文映射圖
上下文映射圖幫助我們理解業務領域、模型間的邊界,以及這些模型之間的集成方式。
上下文映射圖絕對不只是繪製系統架構圖這么簡單,它處理的是不同限界上下文之間的關係,以及如何在不同的模型之間映射對象。對於在複雜的業務系統中使用好限界上下文,這是至關重要的。在第 2章中,團隊成員們在首次嘗試限界上下文時碰到了問題。本章中,他們將學著如何利用上下文映射圖來解決這些問題。這樣的結果是產生了兩個體面的限界上下文,這兩個上下文將被另外一個負責核心域的團隊所使用。
第 4章:架構
我們都知道分層架構,但它是開發 DDD軟體的唯一方式嗎,也或許還存在另外的方式?在本章中,我們將講到:六邊形架構(連線埠和適配器)、面向服務架構、REST、CQRS、事件驅動(管道和過濾器,長時處理過程,事件源)和數據格線,其中好幾種架構都將被該團隊成員所採用。
第 5章:實體
在DDD的戰術模式中,我們將首先講到實體。團隊成員們一開始過於強調實體的作用而忽視了值對象。受到資料庫和持久化框架的影響,實體被該團隊濫用了,此時他們開始討論如何避免大範圍地使用實體。
在本章中,你將看到很多優秀的實體設計例子。同時,本章還將講到如何使用實體來表達通用語言,以及如何對實體進行測試、實現和持久化。
第 6章:值對象
早些時候,團隊成員們錯過了採用值對象的好機會。他們過於注重為實體創建一些單一的屬性,這種方式是欠妥的,更好的方式是將這些單一的屬性聚合成一個不變的整體。本章將從不同的角度講解如何設計值對象,以及在什麼時候採用值對象會優於實體。同時,本章還包含了一些其他話題,比如值對象在集成中的角色和對標準類型的建模等。然後,本章講到了如何設計以領域為中心的測試,如何實現值對象。此外,本章還講到了在聚合中存儲值對象時,如何避免持久化機制所帶來的不利影響。
第 7章:領域服務
本章將講到,在領域模型中,什麼時候應該將一個概念建模成粒度適中,並且無狀態的領域服務。你將學到何時應該使用領域服務而不是實體或值對象,以及如何使用領域服務來處理業務邏輯和技術上的集成。團隊成員們向我們展示了何時應該使用領域服務,以及如何設計領域服務。
第 8章:領域事件
Eric Evans並沒有在他的書中正式介紹領域事件,領域事件是在他那本書出版之後才進入人們視野的。在本章中,你將學到為什麼領域事件如此有用,以及使用領域事件的不同方法。領域事件甚至被用來輔助集成和自治性服務。在軟體系統中,我們經常使用一些技術層面的事件機制,但本章將著重講解領域事件與這些事件機制的區別。本章還將指導你如何設計並實現領域事件,包括一些可行的方案和對這些方案的權衡選擇。然後,本章將講到如何創建一個發布 -訂閱機制;如何利用事件來集成整個企業軟體中的各個訂閱方;如何創建和管理事件存儲;如何處理訊息機制所面臨的常見挑戰等。
第 9章:模組
對於模型中的對象,我們應該如何將他們組織在大小適中的容器中呢?我們又如何保證不同容器中的對象之間只存在有限的耦合?另外,我們如何對這些容器進行命名以體現通用語言?除了包和命名空間之外,我們如何使用由語言和框架提供的現代模組化機制,比如 OSGi和Jigsaw?在本章中,你將看到 SaaS團隊成員是如何在不同的項目中使用模組的。
第 10章:聚合
在DDD的戰術模式中,聚合可能是最不容易理解的了。然而,在遵循一定的經驗法則的情況下,我們是能夠更簡單、更快地實現聚合的。在本章中你將學到:如何利用聚合在不同的小規模對象集群間創建一致性邊界,從而降低模型的複雜性。由於在細枝末節上花了太多精力, SaaS團隊成員們在設計聚合時總是磕磕絆絆。我們將仔細研究該團隊所面臨的挑戰,並且分析錯誤的原因以及他們的應對策略。結果,團隊成員們對他們的核心域有了更深層次的理解。我們將看到,在合理的事務處理和保證最終一致性(Eventual Consistency)的前提下,該團隊更正了他們所犯的錯誤,並且在一個分散式環境中設計出了更具有伸縮性和更高效的模型。
第 11章:工廠
工廠已經在 [Gamma et al.]中被大量地談及了,為什麼還要講呢?本章並不打算重蹈覆轍,而是將重點放在“工廠應該存在於何處”這個問題上。在本章中,我們將講到在 DDD中實現工廠的技巧。團隊成員在他們的核心域中創建的工廠可以簡化客戶端接口,並且對模型的消費方起到保護作用,從而避免了在多租戶環境中引入災難性的 bug。
第 12章:資源庫
資源庫只是一個數據訪問對象( Data Access Object, DAO)嗎?如果不是,它們之間有什麼區別呢?我們為什麼應該將資源庫看成是對集合的模擬而非資料庫呢?在本章中,我們將講到如何利用 ORM來實現資源庫,其中有兩種 ORM方案,一種採用基於格線的分散式快取,另一種則採用 NoSQL的鍵值對存儲。團隊成員們可以採用任何一種作為他們的持久化機制。
第 13章:集成限界上下文
到現在為止,你已經了解了戰略層次的上下文映射圖和多種戰術層次的模式。本章將講到,在 DDD中,我們如何通過上下文映射圖來集成不同的模型。在團隊對核心域和其他輔助性的限界上下文進行集成時,我們將給出相應的建議和指導。
第14章:應用程式
對於每一個核心域的通用語言,我們都設計了相應的模型,並且進行了足夠的測試,模型工作正常。然而,客戶應該如何使用我們的模型呢?他們應該使用 DTO將數據在模型和用戶界面之間傳輸嗎?或者存在其他方案可以實現模型和展現組件間的數據傳遞? DDD中的套用服務和基礎設施是如何工作的?對於這些問題,本章都將做出解答。
附錄A:聚合與事件源: A+ES
事件源是一種持久化聚合的重要技術,同時也是事件驅動架構的基礎。事件源通過一系列的事件來表示聚合的所有狀態。通過有序的事件重放,我們可以重新構建聚合的狀態。當然,使用事件源的前提是:它能夠簡化對數據的持久化,並且能夠捕捉到那些具有複雜行為屬性的概念。
Java和開發工具
本書中的絕大多數例子都是使用 Java語言編寫的。我本來可以用 C#的,但是我有意識地使用了 Java。
首先,我認為 Java社區正在拋棄好的軟體設計和開發實踐。現在,對於多數 Java項目而言,要在其中找到一個好的領域對象恐怕是困難的。在我看來, Scrum和敏捷被人們看成了優良設計的替代品,而其中的產品待定項(Product Backlog)被看成了設計本身。多數敏捷人士並不會過多地去思考這些待定項是否會影響到業務模型。我得說明, Scrum的本意絕對不是要取代設計。不管有多少項目經理想將你捆綁在持續交付這條路上,我得說 Scrum並不僅僅是要取悅於那些甘特圖( Gantt chart)的追隨者們。然而,太多的時候,情況的確是這樣的。
我認為這是個很大的問題,所以我想鼓勵 Java社區重新回到領域建模中來,同時我會通過本書向大家說明,設計是可以使我們獲益的。
此外,在 .NET社區中已經有很好的DDD資源了,比如Jimmy Nilsson的《領域驅動設計與模式實戰》[Nilsson]。由於Jimmy的出色工作和其他人對Alt.NET的倡導,.NET社區中正掀起一陣優秀設計的開發浪潮,這是Java社區需要注意的。
其次,我意識到 C#.NET人員在理解 Java代碼上並不存在什麼困難。由於很多 DDD社區的人都在使用 C#.NET,而本書的早期校對人員也都是 C#程式設計師,但是我從來就沒有收到他們的抱怨。因此,我便不用顧慮這些了。
在我寫這本書時,業內正將目光從關係型資料庫轉向基於文檔和鍵值對的存儲方案。這是有原因的, Martin Fowler將這些存儲方案稱為“面向聚合存儲”。這種命名是恰當的,它很好地描述了在 DDD中使用 NoSQL的好處。
但是,就我從事諮詢的經驗來看,很多開發者還是認定了關係型資料庫和對象-關係映射。因此我想, NoSQL追隨者們應該能夠理解我在書中包含對象 -關係映射的章節。然而,我的確得承認,這可能會招致那些認為存在對象 -關係阻抗失配(Object-Relational Impedance)的人的鄙視。這無所謂,對此我表示接受,因為絕大多數人在他們的日常工作中都還得面對這種對象 -關係阻抗失配。
當然,在第 12章“資源庫”中,我同樣提供了基於文檔的、鍵值對的和數據格線的存儲方案。在多處地方,我都討論到了 NoSQL對聚合設計的影響。 NoSQL趨勢很有可能持續下去,那些對象 -關係型的開發者們應該注意了。在本書中你將看到,我能夠同時理解兩個陣營的觀點,並且對於雙方的觀點我都同意。這些都是技術趨勢所導致的摩擦,而這對於積極的變革是有必要的。

相關詞條

熱門詞條

聯絡我們