SlideShare a Scribd company logo
1 of 87
Download to read offline
领 域 驱 动 设 计 精 要
钟玮军
2019-10
讲师简介
• 领域驱动设计实践者、传播者
• 企业敏捷转型咨询师、资深SOA系统架构师
• 从零到百打造优秀创业技术团队的经历
• 从业多个业务领域的系统分析与架构设计
– 电信设备制造
– 移动飞信即时通讯
– 物联网/车联网
– O2O汽车后服务
– 露天矿无人驾驶运输
课程目的
• 理解系统设计的目的、意义与本质方法
• 学会如何在团队沟通中建立“统一语言”
• 领域驱动战略设计
– 理解“限界上下文”的本质
– 掌握划分限界上下文的方法
– 了解集成限界上下文的架构方法
• 领域驱动战术设计
– 理解领域驱动分层架构设计
– 掌握实体、值对象、聚合、资源库、工厂、服务等构造块
– 重点把握聚合和领域对象的概念和设计要点
• 学习通过“事件风暴”工具进行业务全景探索和领域分
析建模
系统设计概述
软件研发面临的挑战
• 软件开发的不确定性贯
穿了整个软件工程的生
命周期
• 软件工程中不可能有任
何“银弹”解决软件的
复杂性问题
• 软件工程核心实质是社
会工程,优秀团队的核
心竞争力来源于互相的
信任和良好的沟通
系统设计是为了解决系统复杂度带来的问题
无法回避系统的复杂性,我们只有学会去控制这种复杂性
“优秀设计”与“糟糕设计”
除了优秀设计就是糟糕设计,根本不存在“不做设计”一说
从一个励志的故事开始
从“杂货铺”到“超级卖场”
组织/社会的分工与协作
客户服
务部
销售部
华南销
售中心
华北销
售中心
资料/档
案室
项目管
理部
财务部
人力资
源部
经营管
理层
部门协作流程
客户
客户
客户
客户
A事业部
B事业部 C事业部
内部协作流程
研发中心 技术支持中心
产品中心 运营中心
价值提供
价值提供
价值提供
价值提供
引入信息系统后的分工与协作
人机交互流程
客户
客户
客户
客户
人力资源
部门协作流程
一级部门C 一级部门D
一级部门A 一级部门B
信息系统
系统接口协议
应用子系统C 应用子系统D
应用子系统A 应用子系统B
客户
接触
部门
客户
门户
应用子系统E
一级部门E
内部协
作流程
二级部门a 二级部门b
二级部门c 三级部门d
组件接
口协议
组件 a 组件 b
组件 c 组件 d
部
门
接
口
人
系
统
接
口
服
务
“分而治之”是系统设计的本质方法
业务过程建模 系统设计建模
问题空间与解决方案空间
Business
Strategy
(业务战略)
Business
Objectives
(业务目标)
Business
Operational
Model
(运营模式)
Enterprise
Architecture
(企业架构)
Business
Processes
(业务流程)
Business
Systems
(业务系统)
Solution
Delivery
(解决方案交付)
Management
and Operations
(管理和运营)
Solution
Architecture
(解决方案架构)
Problem Space(Value)
问题空间
Solution Space(Capability)
解决方案空间
战略设计与战术设计
Enterprise Architect
(企业架构)
Solution Architect
(解决方案架构)
Technical Architect
(技术架构)
•企业IT战略规划
•业务架构
•应用架构
•数据架构
•技术架构
•安全架构
•企业IT战略的实现与交付
•特定领域或特定问题->产品或技术解决方案
•自研 / 外采 / 外包
•项目管理要素(范围、成本、进度、质量)
•产品/技术解决方案的实现与交付
•技术架构、技术路线、技术规范、技术选型、技术实现
•软件架构:面向组件开发技术、分层架构、…
战
略
设
计
战
术
设
计
系统设计面临的几大挑战
• 客户不知道想要什么
• 技术人员不懂业务知识
• 系统边界不清晰
• 需求冲突/需求变更
• 业务复杂度高
• 工期或资源受限
• 软件资产重用
• 大规模跨团队合作开发
领域驱动设计
领域驱动设计历史由来
50s 60s 80s 90s 2000s70sOOP
1967
OOAD
1982
DDD
2003
2003
Eric Evans
2013
Vaughn Vernon
2016
Vaughn Vernon
2013
Alberto Brandolini
2002
Martin Fowler
领域驱动设计—软件核心复杂性应对之道
• 业务驱动 => “通用语言”
• 化繁为简 => “限界上下文”
• 价值优先 => “核心域”
• 随事而制 => “事件风暴”
• 明晰概念 => “领域模型”
• 区分职责 => “核心构造块”
• 集成协作 => “上下文映射、架构风格”
• 能力复用 => “分层架构(技术)、六边形架构(业务)”
领域驱动设计过程概述
开发团队与领域专家
问题域
+
业务期望
通用语言
战
略
设
计
限界上下文 限界上下文 限界上下文
U D D U
战
术
设
计
领域模型
程序设计重构
编码实现
改进限界上下文
的划分
领域驱动设计全景图
(模型一致性)
(控制复杂度)(敏捷/产品聚焦)
(集成/协作)
(编码规范性)
(敏捷/快速迭代)
战
略
设
计
战
术
设
计
“通用语言”
“通天塔”
“通用语言”
“通用语言”的好与坏
“好” “坏”
正确性 真实需求 “伪”需求
准确性 语言/文字表达没有二义性 语言/文字表达有两种以上的解释
一致性 需求逻辑一致、术语使用一致; 需求相互矛盾或术语使用不一致
完整性 功能完备、概念完整 功能遗漏,或概念遗失
必要性 不包含不必要的内容 文字中夹杂无关内容,令人费解
易懂性 业务意图清晰,非技术人员也能懂 晦涩难懂,难以把握业务意图
及时性 及时更新,并及时通告 更新不及时,或通告不及时
可测性 所定义的功能需求可被验证 所定义的功能需求无法被验证
统一性 语言、文字、代码始终保持统一 客户、需求、设计、实现术语不统一
构建“通用语言”
• 有效沟通是前提
• 概念思维最关键
• 共同遵循成习惯
• 变更管理须及时
• 从通用语言到概念模型
(1)建立信任
与领域专家“有效沟通”
与领域专家“有效沟通”
(2)客观记录
用户提交资料,获得报价。
投保人向保险业务员提交投保资
料,出单员把投保信息准确录入
出单系统后向客户报价。
(3)见微知著
与领域专家“有效沟通”
…投保人…保单持有人…受益人…保
单贴现人…
概念 概念定义/说明
投保人
proposer
是与保险人订立保险合同,并按照保险合同负有支付
保险费义务的人。
保单持有人
policyholder
是指拥有保单各种权利的人。保单所有人是在投保
人与保险人订立保险合同时产生的,他可以与投保
人、受益人是同一人,也可以是其他任何人。
保单贴现人
viator
即保单持有人。
保单持有人在保单贴现交易中充当卖方角色(policy
seller),被称为保单贴现人(viator)
==? Bounded Context?
(4)溯本求源
与领域专家“有效沟通”
作为4S店营销人员,
我想要类似于围栏告警形式的客户流
失预警功能,
以便于我能在客户流失之前发起客户
挽回的营销行为。
4S店希望加围栏告警功能,他们的客
户驶入或驶离特定区域产生报警。
“通用语言”与概念思维
(1)沿用成熟概念
金融 交通 通信 电力 商业 ……
行业标准
地方标准
企业标准
行业参考
DLJT YDJR
国家标准 GB XXXX
国际标准
SB
ISO XXXX
OMG-Finance,
IFX, BIAN, …
TMF
(eTom, SID, …)
Transmodel,
SAE, OTA, …
IEC CIM, ETSI-
SGAM, ERA, …
OMG-Retail,
OFBiz, …
“通用语言”与概念思维
(2)提取新的概念
商
品
SPU
SKU
“通用语言”与概念思维
(3)洞察细微差异
后
台
类
目
保持稳定性
前
台
类
目
保持灵活性
实体类目
虚拟类目
搜词链接
顶通导航
频道页
无线类目
商品类目
意图差异
“通用语言”与概念思维
(4)杜绝命名恶习
Created.
Read.
Updated.
Deleted.
Noted.
Edited.
Ticked off.
Resumed.
Discarded.
Archived.
Or?
使用“通用语言”
(1)“通用语言” 成为全员习惯
使用“通用语言”
(2)“通用语言”之于沟通交流
概念 概念定义/描述 概念说明和使用规则
银行客户
Bank
Customer
是指在银行开立账户办理存款、贷
款或结算业务的单位或个人。
银行系统根据客户身份号码生成的
一个客户号。
对要求建立业务关系的客户身份
进行识别,要求客户出示真实有
效的身份证件或者其他身份证明
文件,进行核对并登记,客户身
份信息发生变化时,应当及时予
以更新。
对银行来说每个客户只有一个客
户号,利用这个号码可以查到此
客户名下所有的账户。
银行账户
Bank
Account
是指客户一间金融机构和一名银行
客户之间的财政帐户,又称为户口
(香港、澳门)或户头(台湾、中
国大陆)。按照开设主体的不同,
可以分为个人银行账户和对公银行
账户。
银行账号是银行为客户在银行开立
的账户的编码,用于区分账户。
个人账户分为I类银行账户、II类银
行账户、III类银行账户,不同类别
的个人银行账户有不同的功能和
权限。同一个银行法人为同一个
人只能开一个I类账户,为同一个
人开立II类、III类账户的数量原则
上分别不得超过5个。
对公账户分为:基本账户、一般
账户、临时账户及专用账户。同
一个银行法人为一个公司只能开
一个基本账户,但是可以设立多
个一般账户。
使用“通用语言”
(3)“通用语言”之于模型构建
银行账户
个人银行账户 对公银行账户
银行客户
主体分类
个人银行客户 单位银行客户
主体分类
开立
分类
I类
账户
III类
账户
II类
账户
基本
账户
临时
账户
一般
账户
专用
账户
分类约束 约束
个人银行账户
分类账户开户规则
对公银行账户
分类账户开户规则
具有 具有
使用Concept Map辅助构建概念模型
使用“通用语言”
(4)“通用语言”之于编码实现
实现代码时,项目的限
界上下文、类名、方法
名、仓储、接口等,都
应该使用通用语言的英
文术语来命名
使用“通用语言”
(5)“通用语言”之于系统测试
Title (one line describing the story)
Narrative:
As a [role]
I want [feature]
So that [benefit]
Acceptance Criteria: (presented as Scenarios)
Scenario 1: Title
Given [context]
And [some more context]...
When [event]
Then [outcome]
And [another outcome]...
Scenario 2: ...
Story: Account Holder withdraws cash
As an Account Holder
I want to withdraw cash from an ATM
So that I can get money when the bank is closed
Scenario 1: Account has sufficient funds
Given the account balance is $100
And the card is valid
And the machine contains enough money
When the Account Holder requests $20
Then the ATM should dispense $20
And the account balance should be $80
And the card should be returned
Scenario 2: Account has insufficient funds
Given the account balance is $10
And the card is valid
And the machine contains enough money
When the Account Holder requests $20
Then the ATM should not dispense any money
And the ATM should say there are insufficient funds
And the account balance should be $20
And the card should be returned
Scenario 3: Card has been disabled
Given the card is disabled
When the Account Holder requests $20
Then the ATM should retain the card
And the ATM should say the card has been retained
【Who】
【What】
【Why】
【Where, When】
【How】
Specification By Example & BDD
public class CashWithdrawingSteps {
private Account account;
private ATM atm;
private Card card;
private BigDecimal dispense;
private Throwable throwable;
@BeforeScenario
public void beforeScenario{
……
}
@Given(“the card is disabled”)
public void givenCardIsDisabled() {
card.setValid(false);
}
@Then("the ATM should retain the card")
public void thenATMShouldRetainCard() {
Assert.assertNull(dispense);
Assert.assertTrue(throwable instanceof CardRetainedException);
}
/**
* @param amount
* the amount of requested money
*/
@When("the account holder requests $amount")
public void whenAccountHolderRequestsMoney(@Named("amount") BigDecimal amount) {
try {
dispense = atm.withdraw(card, amount);
} catch (CardRetainedException exception) {
throwable = exception;
} catch (InsufficientFundsException exception) {
throwable = exception;
}
}
}
public class AccountStories extends JUnitStories {
protected List<String> storyPaths {
return new StoryFinder().findPaths(CodeLocations.codeLocationFromPath(), “xyz/stories/*.story”, “”);
}
}
“通用语言”与变更管理
(1)“通用语言”一致性与“技术债务”
围栏
监测
技术
组件
围栏告警
业务组件
客户流失预警
业务组件
围栏
告警
业务
组件
位置数据 围栏告警
位置数据 围栏
监测
事件
围栏告警
客户流失预警
Continuous Refactoring?Simply Change? or
执行变更
“通用语言”与变更管理
提出变更申请 分析项目影响开始流程
结束流程 申请有效关闭变更申请 No Yes
进行变更决策
接受变更No
涉及基准CCB变更申请CCB审批No
No
Yes
Yes
PM批准变更更新管理计划
通知相关方
记录执行情况总结经验教训
更新过程资产
设计 开发需求 测试 部署 维护
“通用语言”变更
Yes
Keep Model Unified by Continuous Refactoring & Continuous Integration
(2)“通用语言”一致性与需求变更管理流程
“通用语言”与变更管理
(3)刨根问底 – 为什么需求老变
• 问题空间(业务)不会经常变,经常会变的是解决方案空间(系统);
• 因此如果前期花更多的时间分析问题空间,未来就能节约更多构建解决方案空间的时间。
业务层
目标
服务层
目标
服务层
场景
交互层
目标
内部层
目标
交互层
场景
内部层
场景
精化
实现
发掘
实现
发掘
实现
组
织
维
度
系
统
维
度
问
题
方
案
业
务
系
统
“通用语言”与变更管理
(4)User Story需求描述 – 知其然知其所以然
As a <USER ROLE/STAKEHOLDER>,
I want a <FUNCTIONALITY>
So that I can get
<BUSINESS VALUE>
限界上下文/子域
Big Ball of Mud
• 概念太多,语言模糊不
清,对同一术语有着不
同理解,维护统一的语
言/模型变得困难和不现
实
• 模型过于复杂,多个团
队在其中工作,研发过
程变得难以控制和管理,
软件变得难以理解和维
护,需求变更和系统测
试的成本变得越来越高
限界上下文
• 针对特定的问题空间
• 是语义和语境的边界,限界上下
文内部模型是逻辑一致的,术语
不会有摸棱两可的意义,也不会
有规则冲突
• 在Context中,不用考虑内部模
型是否适用于边界之外的情况,
在其他Context中,会使用其他
的模型,这些模型具有不同的通
用语言(术语、概念、规则)
• 是团队工作的边界,通常有独立
的源代码仓库,由一个团队负责
• 粗粒度限界上下文也会随着业务
和系统模型复杂度的发展而演进,
进一步裂变为多个细粒度限界上
下文。
限界上下文是领域建模思考的边界
领域、子域和限界上下文
• 子域是对领域功能职责和核心概
念的逻辑划分,代表一个明确的
专业领域,思维重心在于业务层
面的分解
• 子域代表的是一个单一的、有逻
辑的领域模型
• 限界上下文是对系统及模型复杂
度的控制手段,已经存在设计层
面的考量(折衷的结果)
• 随着系统及模型复杂度的发展,
限界上下文中的子域可能裂变出
新的限界上下文(如Shipping
Subdomain)
• 跨两个限界上下文的子域,代表
存在上下文映射/集成,该子域的
同一概念在两个限界上下文中可
能设计为不同的模型
领域的裂变
(1)识别不同业务线(分区的引入)
Manage Enterprise
(Manage Processes)
Support Activities
(Support Processes)
Value Chain
(Core Processes)
Value Chain
(Core Processes)
A value chain is a set of
activities that a firm
operating in a specific
industry performs in
order to deliver a
valuable product( i.e., go
od and/or service) for
the market.
领域的裂变
(2)分解业务功能域(分层的细化)
• 纵向:业务运营
组织的不同阶段
进行划分
• 横向:业务运营
管理的资源对象
进行划分
• 内部:按照专业
领域再进行分层
细化
领域的裂变
(3)提取通用构造块(机制的提取)
CEO
张勇(逍遥子)
中台总裁
张建锋
搜索事业部
共享业务平台
数据技术及产品部
闲鱼
淘宝头条
零售电商事业群
中台
事业
群
阿
里
妈
妈
事
业
群
淘
宝
手
机
淘
宝
天
猫
云
计
算
事
业
群
菜
鸟
事
业
群
B
2
B
平
台
治
理
部
公
关
部
商
家
事
业
部
聚
划
算
创意
产品
9人班委
刘
博
谷
雪
梅
墙
辉
朋
新
宇
俞
永
福
胡
晓
明
童
文
红
吴
敏
芝
周
桓
张
阔
郑
俊
芳
小前台
敏捷响应
大中台
数据支撑
新兴业务
全面独立发展
职能部门
增信赋能
创意孵化
领域的裂变
(4)3种裂变策略背后的4大原则
职责分离原则
通用专用分离原则
技能分离原则
工作量均衡原则
分层的细化
机制的提取
分区的引入
决定性原则 影响性原则
(ref: 温昱,《一线架构师实践指南》)
核心域、支撑子域和通用子域
• 核心域:决定产品独特竞争
力的子域,是产品之所以被
创建和存在的首要原因
• 支撑子域:功能不是通用的,
但又是必须的,但又不是产
品的核心竞争力
• 通用子域:也存在于其他产
品和竞争者的产品中的通用
功能,不具有个性化的诉求
• 站在不同组织或产品的角度,
结论会有所不同
• 是组织对于产品竞争战略分
析的结果,随时间可能发生
转化(物流->当日达)
投入大量资源
精心打磨
围绕核心域而
建模,可以做
得很薄
可以采购或利
用现成的方案
限界上下文与微服务
• 微服务本质上等同于DDD中的限界上下
文
• 限界上下文首先是领域模型/语言逻辑性
统一边界的划分,其次是在此基础上要求
不同限界上下文之间技术实现松耦合(如
语言和存储实现),而微服务只是物理部
署的一种架构抉择
• 有时人们说微服务比限界上下文大或者小,
可能只是基于不同的思维粒度
(Granularity)而做出的结论,粗粒度的
限界上下文随着系统支撑业务功能或性能
要求的演进仍可能需要分解为细粒度的限
界上下文(犹如社会分工的细化)
• 假如限界上下文由多个微服务实现,需要
对限界上下文应采用Façade或Proxy模式进
行封装(如SDK或API Gateway),客户端不
应该知道这些内部细节
• 以上说明同样适用于理解限界上下文和子
系统之间的关系
上下文映射/集成
上下文映射
• 不同限界上下文之间需
要进行集成,这种集成
关系被成为上下文映射
(Context Mapping)
• 包含三层含义:
– 通用语言之间的转译
– 团队之间的集成关系
– 系统集成的技术架构
通用语言转译
• 两个不同的限界上下文/
子域存在着两种通用语言,
两种通用语言之间存在转
译过程
• 从两个团队的集成关系而
言,通用语言翻译的职责
可以由
– (1)由Context A或者Context B
的开发团队承担 或
– (2)由独立的第三方集成团队
/系统承担
• 限界上下文/子域的开发
团队,应当采用防腐层确
保自身领域模型的纯粹性
Context A
(Language A)
Context B
(Language B)
Context Integration
(Language Interpreter)
团队集成关系
(1) 合作关系Partnership (2) 共享内核Shared Kernel
(3) 遵奉者Conformist (4) 防腐层Anticorruption Layer
(5) 开放式主机服务Open Host Service (6) 已发布语言Published Language
微服务/SOA架构
微服务/SOA架构
(2) RPC
(3) RESTful
(4) 消息机制
(1) 六边形架构
CQRS架构
Client
Commands
Command
Bus
Sends
Command
Handlers
Modify
Repositories
Read Write
Data
store
Event
Bus
Command Services
Event
Handlers
Events
Read
storeQuery
Handlers
Query
Results
Queries
Query Services
Events
Domain
(1) 传统CRUD
(2) 读写分离
(3) 事务模型与查询统计模型分离
Command
Validator
IOC
事务一致性架构设计
事务一致性方案
(1) 数据库本地事务特性
(2) 数据库全局事务特性
(3) 两阶段事务提交
领域驱动战术设计
回顾 – 战略设计和战术设计
(模型一致性)
(控制复杂度)(敏捷/产品聚焦)
(集成/协作)
(编码规范性)
(敏捷/快速迭代)
战
略
设
计
战
术
设
计
领域驱动设计事实上针对是OOAD的
一个扩展和延伸,DDD基于面向对象
分析与设计技术,对技术框架进行了
分层规划,同时对每个类进行了策略
和类型的划分
分层架构(Layered Architecture)
Cross-Cutting
Infrastructure Layers
Operations
Cache
Security
UI Views
Controllers
Sync
Agents
‘Rich Client’/ RIA Web Client
UI Views
Controllers
Presentation
Distributed Interface Layer (Web-Services)
Application Layer
Application Services Workflows Adapters
Domain Model Layer
Infrastructure Layer for Data Persistence
Repositories
(Implementation)
Persistence
(ORMs)
Bases
(Layer Supertype)
Data Model Svc Agents
Domain Services
Domain Entities
(Aggregates)
Repositories (Interfaces)
Data
Stores
External
Services
App Server
Components
用户界面
/展现层
负责向用户展现信息以及解释用户命
令。展示层的组件实现用户与应用交
互的功能。
一般建议用MVC,MVP或者MVVM模
式来分隔这些组件为子层
应用层 很薄的一层,用来协调应用的活动,
实现协调应用的“通道”,例如事务、
执行单位操作、调用应用程序的任务。
它不包含业务逻辑。它不保留业务对
象的状态,但它保有应用任务的进度
状态。
类似于Façade模式,调用领域层和基
础设施层来完成应用的用例。
领域层 本层包含关于领域的信息。这是业务
软件的核心所在。在这里保留业务对
象的状态,对业务对象和它们状态的
持久化被委托给了基础设施层。
基础设施
层
本层作为其他层的支撑库存在。它提
供了层间的通信,实现对业务对象的
持久化,包含对用户界面层的支撑库
等作用。
服务(Services)
• 服务(Services)是由提供
者和使用者之间的契
约定义的,契约规定
了服务使用方法和使
用者期望的最终结果,
此外,还可以在其中
规定服务质量。服务
契约必须进行精确定
义。
• SOLID原则
– SRP(单一职责)
– OCP(开放封闭)
– LSP(可替换)
– ISP(接口隔离)
– DIP(依赖倒置)
实体 (Entities)
• 实体(Entity)具有唯一身
份标识,并且可以在相
当长时间内持续地变化。
• 我们可以对实体做多次
修改,故一个实体对象
可能和它先前的对象大
不相同,但由于它们拥
有相同的身份标识
(identity),它们依然是同
一个实体。
• 很多时候,一个领域概
念应该建模成值对象,
而不是实体对象
• 需要注意DDD的实体概
念和数据库的实体概念
并不完全等同
ApplicationService
DomainService
Domain Event
Aggregate
Aggregate
Root Entity
Entity
Value
Object
值对象(Value Objects)
• 值对象(Value Objects)是对
一个不变的概念整体所建
立的模型,它没有唯一标
识符,而是由值类型封装
的属性对比来决定相等性。
此外,一个值对象不是事
物,而是常常被用来描述、
量化或者测量一个实体。
• 尽量使用值对象来建模而
不是实体对象。
• 值对象可以与其所在的实
体对象保存在同一张表中,
值对象的每一个属性保存
为一列;值对象也可以独
立于其所在的实体对象保
存在另一张表中,值对象
获得委派主键,该主键对
客户端是不可见的。
ApplicationService
DomainService
Domain Event
Aggregate
Aggregate
Root Entity
Entity
Value
Object
聚合(Aggregates)
• 聚合(Aggregate)是一组
相关对象的集合,我们
把它作为修改数据的单
元。每个聚合都有一个
根和一个边界,边界定
义了聚合的内部都有什
么,根则是聚合中所包
含的一个特定实体。
• 根实体控制着所有聚集
在其中的其他元素,对
其他元素的变更应该通
过根实体来完成。
• 每个聚合都会形成事务
一致性的边界
• 业务的聚合概念在战术
上可能拆解为多个聚合
ApplicationService
DomainService
Domain Event
Aggregate
Aggregate
Root Entity
Entity
Value
Object
领域事件(Domain Events)
• 领域事件(Domain
Events)是一条记录,
记录着在限界上下
文中发生的对业务
产生重要影响的事
情。
• 领域事件可用于限
界上下文/子域/聚
合之间的状态同步,
实现业务的最终一
致。
ApplicationService
DomainService
Domain Event
Aggregate
Aggregate
Root Entity
Entity
Value
Object
资料库(Repositories)
• 资料库(Repository)代理了对领域对象的存储和访问操作,让领域模型层始终聚焦于业务。
• Repository的接口应当采用领域通用语言。作为领域模型层,不应当知道数据库实现的细节。
• 严格来讲,只有聚合才拥有资源库,每一个聚合类型都将拥有一个资源库。
工厂(Factories)
• 工厂(Factory) 承担
创建复杂对象和聚
合的职责,可以是
一个工厂类,也可
以是一个工厂方法。
• 有助于向客户端隐
藏创建细节
• 有助于向客户端分
离对象的抽象接口
和具体实现
模块(Modules)
• 模块(Module) 承担对
子域进行封装的工
作,模块名称应该
是领域通用语言中
的术语,模块及其
名称应反映出领域
的深层知识。
• 模块之间应该是低
耦合的,互相只依
赖于模块的对外服
务接口。
• 模块内部则是高内
聚的,应使之包含
一个内聚的概念集
合。
ApplicationServices
Domain
Service
Aggregate
Aggregate
Root Entity
Entity
Value
Object
Domain
Service
Module
ServiceOrchestration
Domain
Service
Domain
Event
Aggregate
Aggregate
Root Entity
Entity
Value
Object
Domain
Service
Module
Interface
Dependency
IOC
Domain
Event
设计实践-(1) DO/DTO/VO
• DO(Domain Object):现实世
界各种业务角色/对象的抽象,
不是简单的POJO,它具有领
域业务逻辑
• DTO(Data Transfer Object):
展示层和服务层之间传输的
数据传输对象,由于DO可能
具有不应该让展示层知道的
数据,同时为了避免客户端
绕过服务层直接调用DO中不
应该访问的操作,再考虑到
客户端调用DO的业务方法可
能导致事务难以控制,所以
应当避免在服务层中直接返
回DO
• VO(View Object):绝大场景
下,VO与DTO的属性值基本
一致,但对于设计层面来说,
概念上还是存在VO和DTO的
区别(如DTO中gender: 0表示
未指定性别,而我们希望交
互层展示为性别:秘密)
RDB
Form UI Reports UI
Presenter
View Object View Object
Data Transfer
Object
Data Transfer
Object
Data Transfer
Object
Data Transfer
Object
View Object View Object
Presenter
Remote Facade Remote Facade
Reporting Services
Domain Object Domain Object
ORM
Handcrafted SQL
Application Services
JSON/XML JSON/XML
设计实践-(2) 聚合设计基本原则
• 在聚合边界内保护
业务规则不变性
• 聚合要设计得小巧
• 只能通过标识符引
用其他聚合
• 使用最终一致性更
新其他聚合
大型聚合 小聚合
标识符引用 最终一致
设计实践-(3) 实体ID
• 实体可以有两类ID,
即实体的业务主键
ID(业务层面)和数据
库代理主键ID(实现层
面)
• 同一上下文内部可以
考虑采用数据库代理
主键标识互相引用,
因为业务主键标识可
能发生变更(如身份证
号码变更)
• 不同上下文之间必须
采用业务主键标识进
行引用,数据库代理
主键标识对外应该不
可见
Application Services
Resident Aggregate
Resident
IDNumber ID
RegisterEvent Aggregate
RegisterEvent
ResidentID
Application Services
SocialInsurance Aggregate
SocialInsurance
SocialInsur
anceNumb
er
ID
Resident
IDNumber
DB DB
Resident Management
Bounded Context
Social Insurance Management
Bounded Context
Database Delegate Key
Business Key
设计实践-(4) 领域实体关系建模
(4.1)继承关系(Inheritance)
Super Entity
Sub Entity A Sub Entity B
Entity ValueObject Entity Value Object
Entity Value Object
Aggregate A Aggregate B
Aggregate Super Single Table
Joined
Table Per Class
设计实践-(4) 领域实体关系建模
(4.2)聚合关系(Aggregate)
Aggregate
Root Entity
Entity
Value
Object
@Entity
@Table( uniqueConstraints = { @UniqueConstraint(columnNames = { "CLASSPACKAGE",
"NAME" }) })
public class SourceClass {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// 类的包路径
private String classPackage = "";
// 类名称
private String name = "";
// 类描述
@Column(name="remark", length=1000)
private String remark = "";
// 类的字段
@OneToMany(mappedBy = "sourceClass",cascade=CascadeType.ALL)
private Collection<SourceField> fields = new HashSet<SourceField>();
// 类的方法集合
@OneToMany(mappedBy = "sourceClass",cascade=CascadeType.ALL)
private Collection<SourceMethod> methods = new HashSet<SourceMethod>();
// …
}
聚合根确定了聚合的生
命周期,其他对象脱离
聚合根没有存在意义(可
对照UML中的组合关系)
设计实践-(4) 领域实体关系建模
(4.3)关联关系(RelationShip)
Aggregate
CellPhone
Aggregate
Person
PersonCellPhone
AssignedPersonID
Query Result
(AggregatedDTO)
Query Services
Query Handler
Aggregate
TeacherStudentRelationShip
TeacherStudent
RelationShip
Aggregate
Student
Student
Query Result
(AggregatedDTO)
Query Services
Query Handler
Aggregate
Teacher
Teacher
Teacher
ID
Student
ID
一对一/一对多关联关系建模 多对多关联关系建模
或直接
引用?
建模为聚合
实体对象
或直接
引用?
关系类型是
否应该有更
具象的名称?
具象的关
系名称
或建模为单
独的聚合实
体对象?
如何保证关联关系随
着Student或Teacher
生命周期改变而消亡?
1
*
设计实践-(5) 接口设计的幂等性
• 幂等性(Idempotent):
对同一个过程应用
相同的参数多次和
一次调用产生的效
果是一样的,这样
的过程被称为满足
幂等性。
• 系统接口对外的一
种承诺,不用担心
重复执行会对系统
造成改变。
• 幂等性是分布式系
统设计中十分重要
的概念。
(1) HTTP/Restful的幂等性 (2) 多版本并发及乐观锁
(3) 分布式事务及最终一致 (3) Log Trace及人工诊断
设计实践-(6) CQRS
(ref: http://williamverdolini.github.io/images/cqrses/CQRS-ES-architecture.png)
(1) Event Driven Architecture(EDA)
(2) Dependency Injection/Inversion of Control(DI/IOC)
(3) Event Sourcing(ES)
(4) Indexing and Search Technology
设计实践-(7) 重构遗留系统
(7.1)拆分单体应用
• 先将应用内部逻辑按照清晰的限界上下文拆分成两个模块
• 将数据库重构成两个独立的数据库
• 进一步将模块拆分为微服务
设计实践-(7) 重构遗留系统
(7.2)修缮模式
• 修缮模式在既有系统资产的基础上,通过剥离新业务和功能,逐步“释放”现有系统耦合度,解决遗
留系统质量不稳定和Bug多的问题。实现传统IT性能提升,面对传统的IT业务更加稳定灵活,降低维
护成本。
• 适用于需求变更频率不高的存量系统
设计实践-(7) 重构遗留系统
(7.3)绞杀模式
• 通过在新的应用中实现新特性,保持和现有系统的松耦合,仅在必要时将功能从原系统中剥离,以
此逐步地替换原有系统。
• 绞杀模式在既有系统资产的基础上实现数字IT创新,面对创新的数字IT业务更加灵活。
事件风暴
事件风暴(Event Storming)
• 事件风暴(Event
Storming):是一项团队
活动,旨在通过领域
事件识别出聚合根,
进而划分微服务的限
界上下文
• 业务人员和开发人员
在平等的基础上共同
学习,每个人都使用
通用语言提出建议
• 以“领域事件”为核
心,通过事件风暴方
法可以快速分析复杂
业务领域,完成领域
建模的目标
UML建模存在的问题
• 业务人员不能了解
或者精通UML,无
法参与整个过程
• 团队成员参与感不
强,无法取得对业
务理解的突破
• 由于需要对模型进
行反复沟通和确认,
建模周期长,投入
成本高
从最核心用例开始,采用
鲁棒图检查迭代补充完善
系统用例,识别接口需求
(Boundary),识别领域模
型对象(Entity),识别控制
层逻辑(Controllers)
事件风暴活动准备
(1) 邀请业务专家和团队成员一起参与
(2) 准备事件风暴活动环境
(3) 各色贴纸及书写笔
事件风暴建模步骤
(1) 通过领域事件的时间线快
速梳理业务流程
(4) 标识限界上下文,以及多个模型间流动的领
域事件
(3) 把命令和领域事件通过实
体/聚合关联起来
(2) 创建导致每个领域事件发
生的命令
(5) 标识用户视图、用户角色,以及其它关键
元素
• 从核心业务流程开始
• 利用聚合/实体的生
命周期完整性检查发
现和补充支撑业务流
程和领域事件
• 领域事件/流程建模
的粒度可以从粗到细
• 部门边界出现时、不
同业务人员对相同术
语的定义出现冲突时,
或者非常重要但并不
属于核心域的某个概
念出现时,限界上下
文也非常有可能随之
出现
事件风暴建模课程实战
领域驱动设计精要 (Domain Driven Design Inside and Outside)

More Related Content

What's hot

Advanced JavaScript
Advanced JavaScriptAdvanced JavaScript
Advanced JavaScriptNascenia IT
 
OAuth2 and Spring Security
OAuth2 and Spring SecurityOAuth2 and Spring Security
OAuth2 and Spring SecurityOrest Ivasiv
 
FinOps-Azure Capabilities
FinOps-Azure CapabilitiesFinOps-Azure Capabilities
FinOps-Azure CapabilitiesGordonByers3
 
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...Alex Cachia
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven DesignYoung-Ho Cho
 
Fraud Detection and Prevention on AWS using Machine Learning
Fraud Detection and Prevention on AWS using Machine LearningFraud Detection and Prevention on AWS using Machine Learning
Fraud Detection and Prevention on AWS using Machine LearningAmazon Web Services
 
BDA301 An Introduction to Amazon Rekognition
BDA301 An Introduction to Amazon RekognitionBDA301 An Introduction to Amazon Rekognition
BDA301 An Introduction to Amazon RekognitionAmazon Web Services
 
Neptune, the Graph Database | AWS Floor28
Neptune, the Graph Database | AWS Floor28Neptune, the Graph Database | AWS Floor28
Neptune, the Graph Database | AWS Floor28Amazon Web Services
 
Revolutionizing the Energy Industry with Graphs
Revolutionizing the Energy Industry with GraphsRevolutionizing the Energy Industry with Graphs
Revolutionizing the Energy Industry with GraphsNeo4j
 
Let's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APILet's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APIMario Fusco
 
MVC ppt presentation
MVC ppt presentationMVC ppt presentation
MVC ppt presentationBhavin Shah
 
Designing with malli
Designing with malliDesigning with malli
Designing with malliMetosin Oy
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)Scott Wlaschin
 
Scalable JavaScript Application Architecture
Scalable JavaScript Application ArchitectureScalable JavaScript Application Architecture
Scalable JavaScript Application ArchitectureNicholas Zakas
 
Oracle CodeOne 2019: Decompose Your Monolith: Strategies for Migrating to Mic...
Oracle CodeOne 2019: Decompose Your Monolith: Strategies for Migrating to Mic...Oracle CodeOne 2019: Decompose Your Monolith: Strategies for Migrating to Mic...
Oracle CodeOne 2019: Decompose Your Monolith: Strategies for Migrating to Mic...Chris Richardson
 
MLOps – Applying DevOps to Competitive Advantage
MLOps – Applying DevOps to Competitive AdvantageMLOps – Applying DevOps to Competitive Advantage
MLOps – Applying DevOps to Competitive AdvantageDATAVERSITY
 

What's hot (20)

Advanced JavaScript
Advanced JavaScriptAdvanced JavaScript
Advanced JavaScript
 
OAuth2 and Spring Security
OAuth2 and Spring SecurityOAuth2 and Spring Security
OAuth2 and Spring Security
 
FinOps-Azure Capabilities
FinOps-Azure CapabilitiesFinOps-Azure Capabilities
FinOps-Azure Capabilities
 
Angular 2 observables
Angular 2 observablesAngular 2 observables
Angular 2 observables
 
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...
No Onions, No Tiers - An Introduction to Vertical Slice Architecture by Bill ...
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
Fraud Detection and Prevention on AWS using Machine Learning
Fraud Detection and Prevention on AWS using Machine LearningFraud Detection and Prevention on AWS using Machine Learning
Fraud Detection and Prevention on AWS using Machine Learning
 
BDA301 An Introduction to Amazon Rekognition
BDA301 An Introduction to Amazon RekognitionBDA301 An Introduction to Amazon Rekognition
BDA301 An Introduction to Amazon Rekognition
 
Neptune, the Graph Database | AWS Floor28
Neptune, the Graph Database | AWS Floor28Neptune, the Graph Database | AWS Floor28
Neptune, the Graph Database | AWS Floor28
 
Revolutionizing the Energy Industry with Graphs
Revolutionizing the Energy Industry with GraphsRevolutionizing the Energy Industry with Graphs
Revolutionizing the Energy Industry with Graphs
 
Let's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APILet's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java API
 
MVC ppt presentation
MVC ppt presentationMVC ppt presentation
MVC ppt presentation
 
Designing with malli
Designing with malliDesigning with malli
Designing with malli
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)
 
Scalable JavaScript Application Architecture
Scalable JavaScript Application ArchitectureScalable JavaScript Application Architecture
Scalable JavaScript Application Architecture
 
Domain Driven Design 101
Domain Driven Design 101Domain Driven Design 101
Domain Driven Design 101
 
API Design - 3rd Edition
API Design - 3rd EditionAPI Design - 3rd Edition
API Design - 3rd Edition
 
Converting R to PMML
Converting R to PMMLConverting R to PMML
Converting R to PMML
 
Oracle CodeOne 2019: Decompose Your Monolith: Strategies for Migrating to Mic...
Oracle CodeOne 2019: Decompose Your Monolith: Strategies for Migrating to Mic...Oracle CodeOne 2019: Decompose Your Monolith: Strategies for Migrating to Mic...
Oracle CodeOne 2019: Decompose Your Monolith: Strategies for Migrating to Mic...
 
MLOps – Applying DevOps to Competitive Advantage
MLOps – Applying DevOps to Competitive AdvantageMLOps – Applying DevOps to Competitive Advantage
MLOps – Applying DevOps to Competitive Advantage
 

More from Weijun Zhong

高精地图数据协议标准探究
高精地图数据协议标准探究高精地图数据协议标准探究
高精地图数据协议标准探究Weijun Zhong
 
物联网终端与平台通讯协议设计模式
物联网终端与平台通讯协议设计模式物联网终端与平台通讯协议设计模式
物联网终端与平台通讯协议设计模式Weijun Zhong
 
项目管理敏捷方法
项目管理敏捷方法项目管理敏捷方法
项目管理敏捷方法Weijun Zhong
 
信息系统架构设计
信息系统架构设计信息系统架构设计
信息系统架构设计Weijun Zhong
 
敏捷开发技术最佳实践(统一敏捷开发过程)
敏捷开发技术最佳实践(统一敏捷开发过程)敏捷开发技术最佳实践(统一敏捷开发过程)
敏捷开发技术最佳实践(统一敏捷开发过程)Weijun Zhong
 
超越敏捷开发(成就敏捷企业之道)
超越敏捷开发(成就敏捷企业之道)超越敏捷开发(成就敏捷企业之道)
超越敏捷开发(成就敏捷企业之道)Weijun Zhong
 
敏捷开发全景视图(流程、方法和最佳实践)
敏捷开发全景视图(流程、方法和最佳实践)敏捷开发全景视图(流程、方法和最佳实践)
敏捷开发全景视图(流程、方法和最佳实践)Weijun Zhong
 
面向模式的软件体系架构
面向模式的软件体系架构面向模式的软件体系架构
面向模式的软件体系架构Weijun Zhong
 
需求分析及相关技术
需求分析及相关技术需求分析及相关技术
需求分析及相关技术Weijun Zhong
 
领域驱动设计与模型驱动开发
领域驱动设计与模型驱动开发领域驱动设计与模型驱动开发
领域驱动设计与模型驱动开发Weijun Zhong
 

More from Weijun Zhong (10)

高精地图数据协议标准探究
高精地图数据协议标准探究高精地图数据协议标准探究
高精地图数据协议标准探究
 
物联网终端与平台通讯协议设计模式
物联网终端与平台通讯协议设计模式物联网终端与平台通讯协议设计模式
物联网终端与平台通讯协议设计模式
 
项目管理敏捷方法
项目管理敏捷方法项目管理敏捷方法
项目管理敏捷方法
 
信息系统架构设计
信息系统架构设计信息系统架构设计
信息系统架构设计
 
敏捷开发技术最佳实践(统一敏捷开发过程)
敏捷开发技术最佳实践(统一敏捷开发过程)敏捷开发技术最佳实践(统一敏捷开发过程)
敏捷开发技术最佳实践(统一敏捷开发过程)
 
超越敏捷开发(成就敏捷企业之道)
超越敏捷开发(成就敏捷企业之道)超越敏捷开发(成就敏捷企业之道)
超越敏捷开发(成就敏捷企业之道)
 
敏捷开发全景视图(流程、方法和最佳实践)
敏捷开发全景视图(流程、方法和最佳实践)敏捷开发全景视图(流程、方法和最佳实践)
敏捷开发全景视图(流程、方法和最佳实践)
 
面向模式的软件体系架构
面向模式的软件体系架构面向模式的软件体系架构
面向模式的软件体系架构
 
需求分析及相关技术
需求分析及相关技术需求分析及相关技术
需求分析及相关技术
 
领域驱动设计与模型驱动开发
领域驱动设计与模型驱动开发领域驱动设计与模型驱动开发
领域驱动设计与模型驱动开发
 

领域驱动设计精要 (Domain Driven Design Inside and Outside)