领域驱动设计实践

109
领域驱动设计实践 @ 瑞友科技IT应用研究院池建强 Twitter: @sagacity Weibo: @池建强 Mail: [email protected]

Upload: jacky-chi

Post on 06-Jul-2015

5.888 views

Category:

Documents


0 download

DESCRIPTION

相对全面的领域驱动设计分享,包括设计元素,生命周期,模式,策略和实践经验,同时包含相关的案例阐述。

TRANSCRIPT

Page 1: 领域驱动设计实践

领域驱动设计实践 @

瑞友科技IT应用研究院池建强Twitter: @sagacity

Weibo: @池建强Mail: [email protected]

Page 2: 领域驱动设计实践

About ME• 池建强,70后程序员,98年毕业,先后就职于洪恩软件、

RocketSofeware和用友集团-瑞友科技,现任瑞友科技IT应用研究院副院长

• 先后从事互联网和企业应用开发,目前致力于基础应用平台的研究

• 热爱技术和编码工作,坚持年轻时的理想,倒霉的乐观者• 技术领域:Java、Python、Ruby、Objective-C、DDD、

OSGi、App Platform

Page 3: 领域驱动设计实践

Domain  Model  -­‐  What  Why  How?

模型是抽象的现实是形象的技巧是重要的思想是永恒的

Page 4: 领域驱动设计实践

从软件系统诞生之初,程序设计者就开始梦想有⼀一天能够像建造桥梁和房屋那样“透明”的构造软件,让现实和代码对应起来

Page 5: 领域驱动设计实践

软件开发总是比任何人估计的慢,如果不是有意的放宽项目期限,几乎不会出现提前完成的软件项目和产品。有时候我们必须耐下心来把所有琐碎的、困难的、细节的问题都解决并不断打磨,才能完成,有时候没有别的办法,只能等待

Page 6: 领域驱动设计实践

⼀一个案例

Page 7: 领域驱动设计实践

2010-01 2010-032010-05

2010-12......

采用领域驱动的方式开发

幸福的时光总是短暂的......

Page 8: 领域驱动设计实践

2010-01 2010-032010-05

2010-12......

商务要求尽快出⼀一个版本

2010-01 2010-032010-05

2011-04......

好日子结束了苦逼的总是开发者

采用领域驱动的方式开发

Page 9: 领域驱动设计实践

领域驱动设计不是用来解决开发速度的领域驱动设计是用来解决软件核心复杂性的

Page 10: 领域驱动设计实践

软件系统面向对象的设计思想可谓历史悠久,20世纪70年代的Smalltalk可以说是面向对象语言的经典,直到今天我们依然将这门语言视为面向对象语言的基础面向对象是大部分语言的⼀一个基本特性,像C++、Java、Objective-C这样的静态语言,Ruby、Python这样的动态语言都是面向对象的语言

面向对象的分析设计

Page 11: 领域驱动设计实践

2004年著名建模专家Eric Evans发表了他 具影响力的书籍《Domain-Driven Design》

——Tackling Complexity in the Heart of Software

中文译名:领域驱动设计—软件核心复杂性应对之道,书中提出了“领域驱动设计(简称 DDD)”的概念。

Page 12: 领域驱动设计实践

领域驱动设计事实上针对是OOAD的⼀一个扩展和延伸,DDD基于面向对象分析与设计技术,对技术框架进行了分层规划,同时对每个类进行了策略和类型的划分

Page 13: 领域驱动设计实践

采用DDD的设计思想,业务逻辑不再集中在几个大型的类上,而是由大量相对小的领域对象(类)组成,这些类具备自己的状态和行为,每个类是相对完整的独立体,并与现实领域的业务对象映射。领域模型就是由这样许多的细粒度的类组成

Page 14: 领域驱动设计实践

领域驱动设计是技术人员和领域专家沟通的桥梁

技术人员和领域专家沟通的桥梁是领域驱动设计

技术人员 领域驱动设计 沟通 领域专家 桥梁

Page 15: 领域驱动设计实践

public  interface  IBookService  {

       double  submitOrder(int  orderId);

}

不容易理解的抽象ûpublic  interface  IBookService  {

       double  submitOrder(Order  order);

} ü

Page 16: 领域驱动设计实践

����� �����

抽象 - 打折策略

��� �� ���

���� ��

Page 17: 领域驱动设计实践
Page 18: 领域驱动设计实践

领域模型和事务脚本

Page 19: 领域驱动设计实践

事务脚本(Transaction Script)的核心是过程,每个过程处理来自表现层的单个请求。大部分业务应用都可以被看成⼀一系列事务,从某种程度上来说,通过事务脚本处理业务,就像执行⼀一条条Sql语句来实现数据库信息的处理

Page 20: 领域驱动设计实践

事务脚本(Transaction Script)的核心是过程,每个过程处理来自表现层的单个请求。大部分业务应用都可以被看成⼀一系列事务,从某种程度上来说,通过事务脚本处理业务,就像执行⼀一条条Sql语句来实现数据库信息的处理事务脚本把业务逻辑组织成单个过程,在过程中直接调用数据库,业务逻辑在服务(Service)层处理

Page 21: 领域驱动设计实践

Action处理UI层的动作请求,将Request中的数据组装后传递给BusinessService,BS层做简单的逻辑处理后,调用数据访问对象进行数据持久化,其中VO充当了数据传输对象的作用,只具备getter和setter方法,没有状态和行为

Transaction Script

Page 22: 领域驱动设计实践

效果?后果?看代码

Page 23: 领域驱动设计实践

事务脚本模式的特点是简单容易理解,面向过程设计。

Page 24: 领域驱动设计实践

事务脚本模式的特点是简单容易理解,面向过程设计。 对于少量逻辑的业务应用来说,事务脚本模式简单自然,性能良好,容易理解,而且⼀一个事务的处理不会影响其他事务。

Page 25: 领域驱动设计实践

事务脚本模式的特点是简单容易理解,面向过程设计。 对于少量逻辑的业务应用来说,事务脚本模式简单自然,性能良好,容易理解,而且⼀一个事务的处理不会影响其他事务。 不过缺点也很明显,对于复杂的业务逻辑处理力不从心,难以保持良好的设计,事务之间的冗余代码不断增多,通过复制粘贴方式进行复用。可维护性和扩展性变差。

Page 26: 领域驱动设计实践

Smart UI-反模式——在用户界面中实现大部分业务逻辑

Page 27: 领域驱动设计实践

领域模型(Domain Model)

‣面向对象分析和设计‣领域模型具备自己的属性行为状态,并与现实世界的业务对象相映射‣各类具备明确的职责划分,领域对象元素之间通过聚合和引用等关系配合解决实际业务应用和规则‣可复用,可维护,易扩展‣可以采用合适的设计模型进行详细设计‣要求设计人员有良好的抽象能力

Page 28: 领域驱动设计实践

Domain Model

Page 29: 领域驱动设计实践

我们也来看代码

Page 30: 领域驱动设计实践

在实际的设计中,我们需要根据具体的需求选择相应的设计模式。具备复杂业务逻辑的核心业务系统适合使用领域模型,简单的信息管理系统或大数据处理可以考虑采用事务脚本模式

Page 31: 领域驱动设计实践

领域驱动设计元素

Page 32: 领域驱动设计实践

• 成熟、清晰的分层架构

• 领域对象与现实世界的业务映射• 明确的职责划分

分层架构

• 领域对象是核心• 领域对象复用:完整的业务对象描述

• 设计复用:设计基于领域对象而非数据库复用

• 具备复杂业务逻辑的软件开发

• 对设计和开发人员要求较高

• 不适用普通CRUD的业务

• 软件的维护性和扩展性良好

使用场景

Page 33: 领域驱动设计实践

分层架构

Page 34: 领域驱动设计实践

名称 职责

展现层 负责向用户展现信息以及解释用户命令

应用层 很薄的⼀一层,用来协调应用的活动。它不包含业务逻辑。它不保留业务对象的状态,但它保有应用任务的进度状态

领域层本层包含关于领域的信息。这是业务软件的核心所在。在这里保留业务对象的状态,对业务对象和它们状态的持久化被委托给了基础设施层。

基础设施层 本层作为其他层的支撑库存在。它提供了层间的通信,实现对业务对象的持久化,包含对用户界面层的支撑库等作用

Page 35: 领域驱动设计实践

实体,值对象,服务

Page 36: 领域驱动设计实践

En#ty(实体)—  人/座位-­‐先到先得?

Page 37: 领域驱动设计实践

Value  Object(值对象)—画笔/地址

Page 38: 领域驱动设计实践

��name�����

����

���� ����� ������������

�������

*

��name�����

����

���� ����� ������������

�������

Page 39: 领域驱动设计实践

Services(服务)

Page 40: 领域驱动设计实践

Entities:具备唯⼀一ID,能够被持久化,具备业务逻辑,对应现实世界业务对象

Page 41: 领域驱动设计实践

Entities:具备唯⼀一ID,能够被持久化,具备业务逻辑,对应现实世界业务对象Value objects:不具有唯⼀一ID,由对象的属性描述,⼀一般为临时对象,可以用来传递参数或作为实体的属性,也可以封装复杂的计算逻辑

Page 42: 领域驱动设计实践

Entities:具备唯⼀一ID,能够被持久化,具备业务逻辑,对应现实世界业务对象Value objects:不具有唯⼀一ID,由对象的属性描述,⼀一般为临时对象,可以用来传递参数或作为实体的属性,也可以封装复杂的计算逻辑Services:为上层建筑提供可操作的接口,负责对领域对象进行调度和封装,同时可以对外提供各种形式的服务

Page 43: 领域驱动设计实践

领域模型的生命周期

Page 44: 领域驱动设计实践

活动状态 数据库

数据库或文件

创建

存储

重建

归档

删除

删除

修改

关系数据库面向对象数据库

NoSql

Page 45: 领域驱动设计实践

Factory和Repository基于Aggregate,对特定生命周期转换的复杂性进行了封装

Page 46: 领域驱动设计实践

Aggregate(聚合)

Page 47: 领域驱动设计实践

什么是聚合,我们来画⼀一下

Page 48: 领域驱动设计实践

Aggregate  root

�����

������� �� ��������

Item Product

<<IPaymentStrategy>>

CashPay CreditCardPay

Page 49: 领域驱动设计实践

Factory  -­‐  IoC

Page 50: 领域驱动设计实践

<beans> <!--Volvo是ICar的实现类 --> <bean id="vcar" class="Volvo"> </bean> <!--为驾驶者提供用车,依赖注入--> <bean id="oneDriver" class="Driver"> <property name="car"> <ref bean="vcar"></ref> </property> </bean></beans> public Driver{

private ICar car; public Driver(){ } public void drive(){ car.method(); } //getter and setter}

Driver drive = helper.getBean( "oneDriver" );drive.drive();

Page 51: 领域驱动设计实践

Repository

Page 52: 领域驱动设计实践

‣ 操作持久对象并管理其生命周期‣ 领域对象和持久化解藕‣ 封装持久化技术‣ 多数据源、连接池、数据源访问代理‣ O/R Mapping技术‣ NoSql‣ 分布式文件系统

‣ 持久化层可替换

Page 53: 领域驱动设计实践

来自QCon淘宝的分享

Page 54: 领域驱动设计实践

规则引擎的案例

Page 55: 领域驱动设计实践

领域元素‣ Package——规则包‣ Rule——规则‣ Attribute——规则属性‣ When/Then——条件‣ ......

Page 56: 领域驱动设计实践

如何实现这样⼀一个设计呢?看例子吧

Page 57: 领域驱动设计实践

⼀一些原则

Page 58: 领域驱动设计实践

表意接口

Inten#on  Revealing  Interface

Page 59: 领域驱动设计实践

如果⼀一个开发人员为了使用⼀一个组件必须要去研究它的实现,那么就失去了封装的意义

Page 60: 领域驱动设计实践

无副作用函数

Side-­‐Effect-­‐Free  Func#on

Page 61: 领域驱动设计实践

所谓"副作用"(side effect),指的是函数内部与外部互动( 典型的情况,就是修改全局变量的值),产生运算以外的其他结果——函数式编程?

Page 62: 领域驱动设计实践

所谓"副作用"(side effect),指的是函数内部与外部互动( 典型的情况,就是修改全局变量的值),产生运算以外的其他结果——函数式编程?利用VO的不变性,创建无副作用的函数,例如,传入或返回的对象是by value,而不是by reference,对返回值的修改,不会影响原来的对象。

Page 63: 领域驱动设计实践

Conceptual Contour概念轮廓

Page 64: 领域驱动设计实践

通过坝或其他手段把⼀一个湖分割为几块,在任何⼀一块中投入石子都不会影响其他部分。把设计元素(行为、接口、类、聚合等)分解为内聚单元。通过重构,找出模型中经常变化的部分和基本稳定的部分。

Page 65: 领域驱动设计实践

如何实现组件之间的解耦

Page 66: 领域驱动设计实践

ESB也是⼀一种方式,但是远程调用?事务?设计时需要慎重选择

Page 67: 领域驱动设计实践

小结⼀一

表意接口把对象描述成有意义的单元。无副作用函数让我们可以安全的使用这些单元。概念轮廓让这些单元更稳定,更符合直觉,更容易组合

Page 68: 领域驱动设计实践

小结二

低耦合是对象设计的⼀一个基本要素,尽可能保持低耦合。把其他所有无关的概念提取到对象之外。消除所有不重要的依赖。限制交叉依赖的方法: 1、子系统 2、模块化 3、聚合 4、单向关联

Page 69: 领域驱动设计实践

领域模式

Page 70: 领域驱动设计实践

Specifica#ons

Page 71: 领域驱动设计实践

‣ 规约是⼀一种布尔断言‣ 规约是业务规则的⼀一部分‣ 理论上规约类中的方法只有⼀一个:IsSatisifedBy( Object )

‣ 规约用来测试对象是否满足某种条件,用来进行对象查询,也可以作为某个对象的创建条件‣ 单⼀一规约规则。多个规约通过组合表现复杂的规约

Page 72: 领域驱动设计实践

��������� ����

public class BookShelf { private List books; public BookShelf(){ books = new ArrayList(); } public void addBook( Book book ){ books.add(book); }}

增加规约:1、不同作者的书放到相应的书架2、不同类型的书放到相应的书架

Page 73: 领域驱动设计实践

�������� ����

<<Specification>>

������������� ��������������

引入规约

Page 74: 领域驱动设计实践

public class AuthorSpecification implements Specification {

private String author; public AuthorSpecification( String author ){ this.author = author; } public boolean isSatisfiedBy(Book book) { return ( book.getAuthor().equals(author) ); }}

public void addBook( Book book ){ if ( validate( book ) ) books.add(book);}

private boolean validate( Book book ){ AuthorSpecification as = new AuthorSpecification( author ); TypeSpecification ts = new TypeSpecification( type ); return ( as.isSatisfiedBy(book) && ts.isSatisfiedBy(book) );}

Page 75: 领域驱动设计实践

Bounded  Context

边界上下文

Page 76: 领域驱动设计实践

明确的定义模型所应用的上下文。根据团队的组织、软件系统的功能和物理表现(代码数据库)来设置模型的边界。在这些边界中严格保持模型的⼀一致性,而不要受到边界之外问题的混淆每个团队负责自己的模型,并为其他模型提供服务

Page 77: 领域驱动设计实践

使用共享内核来管理边界

Page 78: 领域驱动设计实践
Page 79: 领域驱动设计实践

Con#nuous  Integra#on

持续集成

Page 80: 领域驱动设计实践

经过单元测试的代码才能提交到代码库不要等到所有的功能都完成的时候再去集成,要有时间和频度规划,否则......持续集成是根据Bounded Context设计的,不是把系统所有的组件都进行集成

关于上线那些事儿......

Page 81: 领域驱动设计实践

Context  Map

上下文图

Page 82: 领域驱动设计实践

Context Map是用来描述全局的介于项目管理和软件设计之间,属于重叠区域识别模型,明确作用,定义模型边界的上下文。描述模型与模型之间的交互方式、上下文之间的交互方式

Page 83: 领域驱动设计实践

update()close()ship()...

datecustomeramount...

Order

<<Entity>>

subtotal()...

goodsquantitynotes

LineItem

plus(Money other)minus(Money other)...

currencyamount

Money

<<Value Object>>

<<Value Object>>

namesurname

CustomerData

<<Value Object>>

streetcitycountryzipcode

Address

<<Value Object>>

shipping address

billing address

updateDiscount()...

namesurnameaddress...

Customer

<<Entity>> <<Root>><<Root>>

Page 84: 领域驱动设计实践

衍生关系......

Page 85: 领域驱动设计实践

Shared Kernel-Core Domain团队之间共享部分领域模型

Page 86: 领域驱动设计实践

Customer/Supplier团队之间形成客户与供应商的关系

Page 87: 领域驱动设计实践

Conformist-跟随者严格遵守上游团队的模式

Page 88: 领域驱动设计实践

Anti-Corruption Layer(反腐层)创建⼀一个隔离的层,根据自己的领域模

型来为客户提供相关的功能

Page 89: 领域驱动设计实践

Open Host Service定义开放协议,提供服务(Web Service,SOA)

Page 90: 领域驱动设计实践

Published Language(公共语言)大家都是使用公共语言来交流

XML,JSON,Restful

Page 91: 领域驱动设计实践

领域驱动设计实践

Page 92: 领域驱动设计实践

DDD,避免纸上谈兵

Page 93: 领域驱动设计实践

改变代码 == 改变模型建模和编程过程息息相关

Page 94: 领域驱动设计实践
Page 95: 领域驱动设计实践

分层描述名称 职责

View由于该平台主要面向B/S架构,展示层主要由web资源文件组成,包括JSP,JS和大量的界面控件,采用了AJAX技术,负责向用户展现丰富的界面信息,并执行用户的命令

Control 负责展示层请求的转发、调度和验证,同时处理后台返回的异常信息,同时控制层可以通过Action做远程的请求

Domain 是系统 为丰富的⼀一层,主要负责处理整个系统的业务逻辑。这⼀一层主要包括业务服务和领域模型,同时负责系统的事务管理

Persistence 负责数据持久化,支持O/R Mapping和JDBC,对数据源的访问提供多种访问方式

系统的控制层、领域层和持久化层元素都有IOC容器统⼀一管理,实现完全的接口分离和解耦系统的控制层、领域层和持久化层元素都有IOC容器统⼀一管理,实现完全的接口分离和解耦

Page 96: 领域驱动设计实践

提炼业务服务

Page 97: 领域驱动设计实践

寻找领域模型

‣ 倾听领域专家的语言‣ 根据领域描述划分业务单元,每个业务服务对应⼀一个业务单元,覆盖相关的领域对象‣ 提炼领域对象,定义领域对象之间的关系,找到聚合根‣ 定义领域对象的属性、行为和边界‣ 重构和精化

Page 98: 领域驱动设计实践

总结

Page 99: 领域驱动设计实践

• 成熟、清晰的分层架构

• 领域对象与现实世界的业务映射• 明确的职责划分

分层架构

• 领域对象是核心• 领域对象复用:完整的业务对象描述

• 设计复用:设计基于领域对象而非数据库复用

• 具备复杂业务逻辑的软件开发

• 对设计和开发人员要求较高

• 不适用普通CRUD的业务

• 软件的维护性和扩展性良好

使用场景

Page 100: 领域驱动设计实践

DDD解决的主要问题是软件的复杂度DDD的应用场景是行为中心的软件系统,而不是数据中心

微博

供应链

Page 101: 领域驱动设计实践

命令与查询责任分离模式——Command Query Responsibility Segregation

Page 102: 领域驱动设计实践

读写分离 Event Handlers Pub/Sub机制

Page 103: 领域驱动设计实践

练习

Page 104: 领域驱动设计实践

网上书店(Book Store)

‣采用DDD设计思想构建的⼀一个应用系统‣通过网上书店系统,可以快速理解领域驱动设计‣该系统实现网上书店的常用功能:包括浏览书籍、挑选书籍、提交订单、查看订单、自动折扣、处理订单、取消订单等。未登录用户可以浏览和挑选书籍;已登录用户可以提交和查看自己相关的订单;管理员可以处理订单

Page 105: 领域驱动设计实践

领域对象‣ Account——账户‣ Order——订单‣ Book——书籍‣ Cart——购物车‣ Item——订单项‣ Discount——折扣

Page 106: 领域驱动设计实践

构建分层架构 提炼业务服务 寻找领域模型 图形展示

Page 107: 领域驱动设计实践

Service

Page 108: 领域驱动设计实践

架构永远变迁优化永无止境

Page 109: 领域驱动设计实践

Questions?

Follow me 微博:@池建强 | twitter: @sagacity