第Ⅰ部分領域驅動設計的原則與實踐第1章什么是領域驅動設計 3
1.1為復雜問題域創建軟件的挑戰 4
1.1.1未使用通用語言創建的代碼 4
1.1.2組織結構的缺乏 5
1.1.3泥球模式將扼殺開發 5
1.1.4缺乏對問題域的關注 5
1.2領域驅動設計模式如何管理復雜性 6
1.2.1DDD的戰略模式 6
1.2.2DDD的戰術模式 8
1.2.3問題空間與解空間 9
1.3領域驅動設計的實踐與原則 10
1.3.1專注于核心領域 10
1.3.2通過協作進行學習 10
1.3.3通過探索和實驗來創建模型 10
1.3.4通信 11
1.3.5理解模型的適用性 11
1.3.6讓模型持續發展 11
1.4領域驅動設計的常見誤區 12
1.4.1戰術模式是DDD的關鍵 12
1.4.2DDD是一套框架 12
1.4.3DDD是一顆靈丹妙藥 12
1.5要點 13
第2章提煉問題域 15
2.1知識提煉與協作 15
2.1.1通過通用語言達成共識 16
2.1.2領域知識的重要性 17
2.1.3業務分析員的角色 17
2.1.4一個持續過程 17
2.2與領域專家一起獲得領域見解 18
2.2.1領域專家與業務相關人員的對比 18
2.2.2對于業務的更深刻理解 18
2.2.3與你的領域專家互動 19
2.3有效提煉知識的模式 19
2.3.1專注在最有意思的對話上 19
2.3.2從用例開始 19
2.3.3提出有力的問題 20
2.3.4草圖 20
2.3.5CRC卡 21
2.3.6延遲對模型中概念的命名 21
2.3.7行為驅動開發 21
2.3.8快速成型 23
2.3.9查看基于紙面的系統 23
2.4查看現有模型 23
2.4.1理解意圖 24
2.4.2事件風暴 24
2.4.3影響地圖 25
2.4.4理解業務模型 26
2.4.5刻意發現 27
2.4.6模型探討漩渦 27
2.5要點 28
第3章專注于核心領域 31
3.1為何要分解一個問題域 31
3.2如何捕獲問題的實質 32
3.2.1超越需求 32
3.2.2為達成什么是核心內容的共識而捕獲領域愿景 32
3.3如何專注于核心問題 33
3.3.1提煉問題域 34
3.3.2核心領域 35
3.3.3將你的核心領域當作一款產品而非一個項目 36
3.3.4通用域 36
3.3.5支撐域 37
3.4子域如何決定解決方案的形成 37
3.5并非一個系統的所有部分都會經過良好設計 38
3.5.1專注于清晰邊界而非完美模型 38
3.5.2一開始核心領域不必總是需要是完美的 39
3.5.3構建用于替代而非重用的子域 39
3.6如果沒有核心領域怎么辦 39
3.7要點 39
第4章模型驅動設計 41
4.1什么是領域模型 41
4.1.1領域與領域模型的對比 42
4.1.2分析模型 43
4.1.3代碼模型 43
4.1.4代碼模型是領域模型的主要表現 44
4.2模型驅動設計 44
4.2.1預先設計的挑戰 44
4.2.2團隊建模 46
4.3使用通用語言將分析和代碼模型綁定在一起 47
4.3.1語言的生存周期將大于軟件 48
4.3.2業務語言 48
4.3.3開發人員和業務之間的轉譯 48
4.4基于通用語言進行協作 49
4.4.1通過使用具體示例來定制出語言 50
4.4.2教導你的領域專家專注在問題上而不要跳到解決方案 50
4.4.3塑造語言的最佳實踐 51
4.5如何創建有效的領域模型 52
4.5.1不要讓實情妨礙一個好模型 52
4.5.2僅對相關內容建模 53
4.5.3領域模型都是暫時有用的 53
4.5.4要十分清楚專業術語 54
4.5.5限制你的抽象 54
4.6何時應用模型驅動設計 55
4.6.1如果它不值得花費精力,則不要嘗試對其建模 56
4.6.2專注于核心領域 56
4.7要點 56
第5章領域模型實現模式 59
5.1領域層 59
5.2領域模型實現模式 60
5.2.1領域模型 61
5.2.2事務腳本 64
5.2.3表模塊 67
5.2.4活動記錄 67
5.2.5貧血領域模型 67
5.2.6貧血領域模型和函數編程 68
5.3要點 71
第6章使用有界上下文維護領域模型的完整性 73
6.1單個模型的挑戰 74
6.1.1模型的復雜性可能會增加 74
6.1.2多個團隊處理單個模型 74
6.1.3模型語言中的歧義 75
6.1.4領域概念的適用范圍 76
6.1.5集成遺留代碼或第三方代碼 78
6.1.6領域模型并非企業模型 78
6.2使用有界上下文劃分和破除大模型 79
6.2.1定義模型的邊界 81
6.2.2子域和有界上下文之間的差異 84
6.3實現有界上下文 85
6.4要點 88
第7章上下文映射 91
7.1一個現實情況的映射 92
7.1.1技術的現實 92
7.1.2組織的現實 93
7.1.3映射一個相關現實情況 94
7.1.4用X標記核心領域的位置 94
7.2認識有界上下文之間的關系 94
7.2.1防止損壞層 95
7.2.2共享內核 96
7.2.3開放宿主服務 96
7.2.4分道揚鑣 97
7.2.5合作關系 98
7.2.6一種上游/下游關系 98
7.3傳遞上下文映射 99
7.4上下文映射的戰略重要性 100
7.4.1保持完整性 100
7.4.2解決計劃的基礎 101
7.4.3理解所有權和職責 101
7.4.4揭示業務工作流中的混亂區域 101
7.4.5識別非技術障礙 101
7.4.6鼓勵良好的溝通 101
7.4.7幫助加入的新員工 102
7.5要點 102
第8章應用程序架構 103
8.1應用程序架構 103
8.1.1分離應用程序的問題 103
8.1.2從領域的復雜性中進行抽象 104
8.1.3分層架構 104
8.1.4依賴倒置 105
8.1.5領域層 105
8.1.6應用程序服務層 105
8.1.7基礎架構層 106
8.1.8跨層通信 106
8.1.9隔離測試 107
8.1.10不要在有界上下文之間共享數據結構 108
8.1.11應用程序架構與用于有界上下文的架構的對比 109
8.2應用程序服務 110
8.2.1應用程序邏輯與領域邏輯的對比 111
8.2.2定義和公開能力 112
8.2.3業務用例協作 112
8.2.4應用程序服務表示的是用例,而不是創建、讀取、更新和刪除 112
8.2.5作為實現詳情的領域層 113
8.2.6領域報告 113
8.2.7讀取模型與事務模型的對比 113
8.3應用程序客戶端 115
8.4要點 117
第9章團隊開始應用領域驅動設計通常會遇到的問題 119
9.1過分強調戰術模式的重要性 120
9.1.1將相同架構用于所有的有界上下文 120
9.1.2力求戰術模式盡善盡美 120
9.1.3錯誤估計構造塊對于DDD的價值 120
9.1.4專注于代碼而非DDD的原則 121
9.2缺失了DDD的真實價值:協作、通信和上下文 121
9.2.1由于低估上下文的重要性而產生大泥球 122
9.2.2未能成功創建UL將造成歧義和誤解 122
9.2.3由于缺乏協作將只能設計專注于技術的解決方案 123
9.3在不重要的部分花費太多時間 123
9.4簡單問題復雜化 123
9.4.1將DDD原則應用到具有少量業務預期的瑣碎領域 124
9.4.2別將CRUD作為反模式 124
9.4.3將領域模型模式用于每一個有界上下文 124
9.4.4問一問自己:額外的復雜性是否值得 124
9.5低估應用DDD的成本 125
9.5.1嘗試在沒有積極專注的團隊的情況下取得成功 125
9.5.2項目背后沒有領域專家時的協作嘗試 125
9.5.3在非迭代式開發方法中進行學習 125
9.5.4將DDD應用到每一個問題 126
9.5.5為不必要的純粹性而犧牲實用主義 126
9.5.6尋求驗證會浪費精力 126
9.5.7永遠力求代碼之美 127
9.5.8DDD關乎的是提供價值 127
9.6要點 127
第10章應用DDD的原則、實踐與模式 129
10.1推廣使用DDD 129
10.1.1培訓團隊 130
10.1.2與業務人員進行交流 130
10.2應用DDD的原則 131
10.2.1理解愿景 131
10.2.2捕獲所需的行為 131
10.2.3理解環境的現實情況 132
10.2.4對解決方案建模 133
10.3探究和實驗 139
10.3.1質疑假設 139
10.3.2建模是一項持續性活動 139
10.3.3不存在錯誤的模型 140
10.3.4靈活的代碼有助于探索發現 140
10.4讓隱式內容變得顯式 140
10.4.1處理歧義 141
10.4.2為事物命名 143
10.5問題解決人先行,技術專家后行 143
10.6如何才能知道我在正確地工作 143
10.6.1好用就足夠了 144
10.6.2實踐、實踐、實踐 144
10.7要點 144
第Ⅱ部分戰略模式:在有界上下文之間通信
第11章有界上下文集成介紹 149
11.1如何集成有界上下文 150
11.1.1有界上下文是獨立自主的 150
11.1.2在代碼層面集成有界上下文的挑戰 151
11.1.3使用物理邊界來強制實現整潔的模型 154
11.1.4集成遺留系統 155
11.2集成分布式有界上下文 158
11.2.1集成用于分布式有界上下文的策略 159
11.2.2數據庫集成 159
11.2.3平面文件集成 160
11.2.4RPC 161
11.2.5消息傳遞 162
11.2.6REST 162
11.3DDD使用分布式系統的挑戰 162
11.4分布式事務將損害可擴展性和可靠性 165
11.4.1有界上下文不必彼此保持一致 166
11.4.2最終一致性 166
11.5事件驅動響應式DDD 167
11.5.1展示響應式解決方案的彈性和可擴展性 168
11.5.2異步消息傳遞的挑戰和取舍 169
11.5.3RPC還有價值嗎 169
11.6SOA和響應式DDD 170
11.6.1將你的有界上下文視作SOA服務 171
11.6.2進一步處理微服務架構 174
11.7要點 175
第12章通過消息傳遞集成 177
12.1消息傳遞基礎 178
12.1.1消息總線 178
12.1.2可靠的消息傳遞 180
12.1.3存儲轉發 180
12.1.4命令和事件 180
12.1.5最終一致性 181
12.2使用NServiceBus構建一個電子商務應用程序 182
12.2.1系統設計 183
12.2.2從Web應用程序發送命令 187
12.2.3處理命令和發布事件 196
12.2.4使用消息傳遞網關讓外部HTTP調用變得可靠 203
12.2.5實踐中的最終一致性 211
12.2.6有界上下文會存儲其本地所需的所有數據 212
12.2.7把所有內容都放在UI中 220
12.3維護消息傳遞應用程序 223
12.3.1消息版本管理 223
12.3.2監控和擴展 228
12.4將有界上下文與公共傳輸集成 231
12.4.1消息傳遞橋 232
12.4.2公共傳輸 233
12.5要點 240
第13章通過使用RPC和REST的HTTP來集成 241
13.1為何選用HTTP 242
13.1.1沒有平臺耦合 243
13.1.2每個人都理解HTTP 243
13.1.3大量的成熟工具和庫 243
13.1.4內部測試你的API 243
13.2RPC 244
13.2.1在HTTP上實現RPC 244
13.2.2選擇一種RPC風格 259
13.3REST 260
13.3.1深入淺出地解釋REST 260
13.3.2用于有界上下文集成的
REST 263
13.3.3維護REST應用程序 297
13.3.4將REST用于有界上下文集成的缺點 298
13.4要點 299
第Ⅲ部分戰術模式:創建有效的領域模型
第14章構造塊領域建模介紹 303
14.1戰術模式 304
14.2對領域建模的模式 305
14.2.1實體 305
14.2.2值對象 308
14.2.3領域服務 310
14.2.4模塊 312
14.3生命周期模式 312
14.3.1聚合 312
14.3.2工廠 316
14.3.3存儲庫 316
14.4顯露模式 317
14.4.1領域事件 317
14.4.2事件溯源 319
14.5要點 320
第15章值對象 323
15.1何時使用值對象 324
15.1.1表示描述性的、欠缺身份的概念 324
15.1.2增強明確性 325
15.2定義特征 327
15.2.1欠缺身份 327
15.2.2基于特性的相等性 327
15.2.3富含行為 331
15.2.4內聚 331
15.2.5不可變 331
15.2.6可組合性 333
15.2.7自驗證 335
15.2.8可測試 338
15.3常見的建模模式 339
15.3.1靜態工廠方法 339
15.3.2微類型 341
15.3.3規避集合 343
15.4持久化 346
15.4.1NoSQL 346
15.4.2SQL 347
15.5要點 354
第16章實體 355
16.1理解實體 356
16.1.1具有身份和連貫性的領域概念 356
16.1.2上下文依賴 356
16.2實現實體 357
16.2.1分配標識符 357
16.2.2將行為推入到值對象和領域服務中 363
16.2.3驗證并強制不變性 365
16.2.4專注于行為,而非數據 368
16.2.5避免“建模現實世界”的謬誤 371
16.2.6分布式設計 371
16.3常見的實體建模原則和模式 373
16.3.1使用規范實現驗證和不變條件 373
16.3.2避免狀態模式;使用顯式建模 376
16.3.3避免將接收器和設置器與備忘錄模式結合使用 379
16.3.4選用無隱藏意外影響的功能 380
16.4要點 382
第17章領域服務 383
17.1理解領域服務 384
17.1.1何時使用領域服務 384
17.1.2領域服務解析 388
17.1.3避免使用貧血領域模型 389
17.1.4與應用程序服務對比 390
17.2利用領域服務 390
17.2.1服務層中 390
17.2.2領域中 391
17.3要點 397
第18章領域事件 399
18.1領域事件模式的實質 400
18.1.1已經發生了的重要領域事件 400
18.1.2響應事件 401
18.1.3可選的異步性 401
18.1.4內部事件與外部事件對比 402
18.2事件處理操作 403
18.2.1調用領域邏輯 403
18.2.2調用應用程序邏輯 404
18.3領域事件的實現模式 404
18.3.1使用.Net框架的事件模型 404
18.3.2使用內存中的總線 406
18.3.3UdiDahan的DomainEvents靜態類 409
18.3.4返回領域事件 412
18.3.5使用IoC容器作為事件分發器 415
18.4測試領域事件 416
18.4.1單元測試 416
18.4.2應用服務層測試 417
18.5要點 419
第19章聚合 421
19.1管理復雜對象圖形 422
19.1.1選用單一遍歷方向 422
19.1.2合格的關聯關系 424
19.1.3選用ID而不是對象引用 425
19.2聚合 428
19.2.1圍繞領域不變條件進行設計 429
19.2.2高層次的領域抽象 429
19.2.3一致性邊界 429
19.2.4選用較小的聚合 434
19.3定義聚合邊界 435
19.3.1eBidder:在線拍賣案例研究 435
19.3.2與不變條件保持一致 437
19.3.3與事務和一致性保持一致 439
19.3.4忽略用戶界面影響 440
19.3.5避免無用的集合與容器 441
19.3.6不要專注于HAS-A關系 441
19.3.7重構聚合 441
19.3.8滿足業務用例——非現實環境 441
19.4實現聚合 442
19.4.1選擇一個聚合根 442
19.4.2引用其他聚合 446
19.4.3實現持久化 450
19.4.4實現事務一致性 454
19.4.5實現最終一致性 455
19.4.6實現并發性 458
19.5要點 459
第20章工廠 461
20.1工廠的作用 461
20.1.1從構造中分離出應用 462
20.1.2封裝內部事物 462
20.1.3隱藏創建類型的決策 464
20.1.4聚合上的工廠方法 466
20.1.5用于重構的工廠 467
20.1.6務實地使用工廠 469
20.2要點 469
第21章存儲庫 471
21.1存儲庫 471
21.2一種被誤解的模式 473
21.2.1存儲庫是一種反模式嗎 473
21.2.2領域模型和持久化模型之間的區別 474
21.2.3通用存儲庫 475
21.3聚合持久化策略 477
21.3.1使用能在不損壞領域模型的情況下將其映射到數據模型的持久化框架 478
21.3.2使用不能在不影響領域模型的情況下直接映射它的持久化框架 478
21.3.3公共接收器和設置器 479
21.3.4使用備忘錄模式 480
21.3.5事件流 482
21.3.6求真務實 483
21.4存儲庫是一個明確的約定 483
21.5事務管理和工作單元 484
21.6保存或不保存 488
21.6.1持久化追蹤領域對象變更的框架 489
21.6.2必須將變更顯式保存到聚合 490
21.7充當防止損壞層的存儲庫 491
21.8存儲庫的其他職責 491
21.8.1實體ID生成 492
21.8.2集合匯總 494
21.8.3并發性 494
21.8.4審計追蹤 498
21.9存儲庫反模式 498
21.9.1反模式:不要支持即席查詢 498
21.9.2反模式:延遲加載是一種設計異味 499
21.9.3反模式:不要為了報告需要而使用存儲庫 499
21.10存儲庫實現 499
21.10.1持久化框架可以在不損壞領域模型的情況下將其映射到數據模型 500
21.10.2持久化框架不能在不損壞領域模型的情況下直接映射領域模型 550
21.11要點 586
第22章事件溯源 587
22.1將狀態存儲為快照的限制 588
22.2通過將狀態存儲為事件流來獲得競爭優勢 589
22.2.1時態查詢 589
22.2.2投影 590
22.2.3快照 591
22.3源自事件的聚合 591
22.3.1構造 592
22.3.2持久化與再融合 596
22.4構建一個事件存儲 603
22.4.1設計一種存儲格式 604
22.4.2創建事件流 605
22.4.3附加到事件流 606
22.4.4查詢事件流 606
22.4.5添加快照支持 607
22.4.6管理并發性 609
22.4.7一個基于SQLServer的事件存儲 613
22.4.8構建你自己的事件存儲是一個好主意嗎 619
22.5使用專門構建的EventStore 619
22.5.1安裝GregYoung的EventStore 619
22.5.2使用C#客戶端庫 620
22.5.3運行時態查詢 624
22.5.4創建投影 627
22.6使用事件溯源的CQRS 629
22.6.1使用投影創建視圖緩存 630
22.6.2CQRS和事件溯源協作 630
22.7簡要復述事件溯源的好處 631
22.7.1競爭性業務優勢 631
22.7.2專注于表述性行為的聚合 631
22.7.3簡化的持久化 632
22.7.4更好的調試 632
22.8衡量事件溯源的代價 632
22.8.1版本控制 632
22.8.2要學習的新概念和要磨練的技能 632
22.8.3需要學習和掌握的新技術 633
22.8.4大量的數據存儲需求 633
22.9額外的學習資源 633
22.10要點 633
第Ⅳ部分有效應用程序的設計模式
第23章應用程序用戶界面的架構設計 637
23.1設計考量 638
23.1.1占有式UI與構成式UI的對比 638
23.1.2HTMLAPI與數據API的對比 640
23.1.3客戶端與服務器端聚合/協作對比 641
23.2示例1:用于非分布式有界上下文的一個基于HTMLAPI的、服務器端的UI 643
23.3示例2:用于分布式有界上下文的一個基于數據API的客戶端UI 650
23.4要點 658
第24章CQRS:一種有界上下文的架構 659
24.1為兩個上下文維護單個模型的挑戰 660
24.2用于復雜有界上下文的一種更好的架構 661
24.3命令端:業務任務 662
24.3.1顯式建模意圖 662
24.3.2不受展現干擾所影響的模型 663
24.3.3處理業務請求 665
24.4查詢端:領域報告 665
24.4.1直接映射到數據模型的報告 666
24.4.2從領域事件中構建的具體化視圖 667
24.5對CQRS的誤解 668
24.5.1CQRS很難 668
24.5.2CQRS是最終一致的 668
24.5.3模型需要源自事件 669
24.5.4命令應該是異步的 669
24.5.5CQRS僅適用于消息傳遞系統 669
24.5.6需要將CQRS用于領域事件 669
24.6可以擴展應用程序的模式 669
24.6.1擴展讀取端:一個最終一致的讀取模型 670
24.6.2擴展寫入端:使用異步命令 672
24.6.3對一切進行擴展 673
24.7要點 674
第25章命令:用于處理業務用例的應用程序服務模式 677
25.1區分應用程序邏輯和
領域邏輯 678
25.1.1應用程序邏輯 678
25.1.2來自應用程序服務角度的領域邏輯 690
25.2應用程序服務模式 690
25.2.1命令處理程序 690
25.2.2發布/訂閱 694
25.2.3請求/回復模式 696
25.2.4async/await 698
25.3測試應用程序服務 699
25.3.1使用領域專業術語 699
25.3.2測試盡可能多的功能 700
25.4要點 702
第26章查詢:領域報告 703
26.1有界上下文中的領域報告 704
26.1.1從領域對象中派生報告 704
26.1.2直接訪問數據存儲 710
26.1.3從事件流構建投影 716
26.2跨有界上下文的領域報告 723
26.2.1復合UI 723
26.2.2單獨的報告上下文 724
26.3要點 726