领域驱动读书笔记
如何使用本书
战略设计与战术设计
通用语言作用于某个限界上下文。 在一个特定的限界上下文中只使用一套通用语言,并且保证它的清晰性与简洁性。
通过战略设计与战术设计而成的领域模型应该是架构中立的。在模型周围和模型之间则是存在架构的。
DDD入门
贫血模型、javaBean标准以及相关的一些历史缘由等,以数据为中心,只有数据,没有行为。
如何ddd?
通用语言和限界上下文
使用ddd的业务价值
使用DDD的原因
- 使领域专家和开发者在一起工作,这样开发出来的软件能够”准确地传达业务规则”。
- 在领域专家、开发者和软件本身不存在“翻译”,大家都使用相同的语言进行交流。
- 设计就是代码,代码就是设计。
- 战略设计帮助我们理解哪些投入是最重要的,哪些既有软件资产是可以重新拿来使用的;那些人应该被加入到团队中?
- 战术设计则帮助我们创建DDD模型中各个部件。
基本概念
领域:从广义上讲,领域是一个组织所做的事情以及其中所包含的一切,领域可以表示整个业务系统,也可以表示其中的某个核心域或者支撑子域。在DDD中,一个领域被分为若干子域,领域模型在限界上下文中完成开发。事实上,在开发一个领域模型时,我们关注的通常只是这个业务系统的某个方面,试图创建一个全功能的领域模型是非常困难的,对领域的拆分将有助于我们成功。
领域模型:领域模型是关于某个特定业务领域的软件模型,通常领域模型通过对象模型来实现,这些对象同时包含了数据和行为,并且表达了准确的业务含义。
通用语言Uniqutious Language:团队自己创建的公用语言,作用于某个限界上下文。在一个特定的限界上下文中只使用一套通用语言,并且保证它的清晰性和简洁性。
限界上下文Bounded Context:
- 一种概念上的边界,领域模型便工作于其中。同时限界上下文为通用语言提供了一套环境,项目成员便通过通用语言来表达软件模型。
- 限界上下文是一个显式边界,领域模型便存在于边界之内。在边界内,通用语言中的所有术语和词组都有特定的含义,而模型需要准确地反映通用语言。
- 当使用IDE时,比如Eclipse或者Intellij IDEA,一个限界上下文通常是一个工程项目。
问题空间:
解决方案空间:
上下文映射图Context Map:
子域: 子域的边界由通用语言划分。
核心域:
支撑子域: 对应着业务的某些重要方面,但却不是核心,那么它便是一个支撑子域。
通用子域:某个支撑子域的运用范围是整个系统,那么这个子域便是通用子域。如何一步一步用DDD设计一个电商网站
筒仓效应 :
- 指企业内部因缺少沟通,部门间各自为政,只有垂直的指挥系统,没有水平的协同机制,就象一个个的谷仓,各自拥有独立的进出系统,但缺少了谷仓与谷仓之间的沟通和互动。—百度百科
防腐层:
六边形模型:
事件驱动:
开放主机服务:
DDD的分层
DDD语境下,分层结构包含: 用户界面层(user interface)、应用层(application)、领域层(domain)、基础设施层(infrastructure)
用户界面层(user interface)
- 概述: 在底层系统之上封装了一层可访问外壳,为特定类型的外部用户(人或计算机程序)访问底层系统提供访问入口,并将底层系统的状态数据以该类型客户需要的形式呈现给它们。
- 职责:
- 接收命令操作,改变底层系统状态
- 接收查询操作,将底层系统状态以合适的形式呈现给用户
- 校验、转换、转发
- 校验:校验外部客户输入的数据是否合法
- 转换:将外部客户的输入转换成对底层系统的方法调用参数,以及将底层系统的调用结果转换成外部客户需要的形式
- 转发:将外部客户的请求转发给底层系统
- 有时我们会把转换工作分离出一个亚层-门面层(Facade)
- 查询结果通常以数据传输对象(DTO)的形式表示,由用户界面层而不是应用层界定,代表前端需要的数据形式。
- 将数据装配职责委托给专门的Assembler工具类去执行
- 特点:
- 不同类型的用户需要不同形式的用户接口
- 不同类型的用户需要不同形式的数据表示
- 用户接口层对应用层进行封装,用户接口层的操作与应用层上定义的操作通常是一一对应的关系。
应用层(application)
- 概述:整个系统的外观、封装了领域层的复杂性,并隐藏了其内部实现机制;映射到系统用例模型,是系统用例模型在软件中的反映
- 特点:
- 编排和转发:不实现业务逻辑,通过排列组合领域层的领域对象来实现用例
- 系统用例模型中的所有用例都可以在应用层接口中找到对应的方法
领域层(domain)
- 概述:领域层实现业务逻辑,映射到领域模型,是问题域的领域模型在软件中的反映
- 模型:实体、值对象、领域服务,通常这些领域对象和问题域中的概念实体一一对应,具有相同或相似的属性和行为
- 特点:
- 业务规则:在实体、值对象和领域服务等领域对象的方法中封装实现业务规则,有数据有行为。
- 完整性约束:领域对象在实现业务逻辑上具备坚不可摧的完整性,意味着不管外界代码如何操作,都不可能创建不合法的领域对象。
- 内聚性:任何不涉及业务逻辑的复杂的组合操作都不在领域层而在应用层中实现
- 完备性:系统的所有行为都可以由领域层中的领域对象组合实现
- 通过仓储(respository)接口定义持久化需求,基础设施层通过采用jdbc、jpa、hibernate、nosql等实现领域层的仓储接口
基础设施层(infrastructure)
- 概述: 为领域层、应用层、用户界面层提供具体的技术支持(如持久化、消息通信)
- 特点:
- 提供系统的全部技术性需求。
- 一些例子:
- 领域层需要持久化服务,在DDD中,领域层通过仓储(Repository)接口定义持久化需求,基础设施层通过采用jdbc、jpa、hibernate、nosql等实现领域层的仓储接口
- 领域层需要消息通知服务,在领域层定义了一个NotificationService领域服务接口,基础设施层通过采用手机短信、电子邮件、Jabber等技术实现NotificationService领域服务接口,为领域层提供消息通知服务。
- 用户界面层需要一个对象序列化服务,可以在用户界面层定义一个ObjectSerializer服务接口,基础设施层通过Gson实现着一接口,为用户界面层提供对象序列化服务
通用说明:
- 在四层架构中,领域层和应用层纯粹表达业务意图和机制,不包含任何技术逻辑;而基础设施层和用户接口层纯粹提供技术实现,不包含任何业务逻辑。在业务和技术之间存在清晰的关注点分离
- 应用层定义系统的全部业务功能,领域层具体实现这些功能。领域层“动于内”,应用层“形诸外”。
- 应用层和领域层合在一起代表了整个业务系统,具备概念上的完整性(包含了全部领域概念,实现了全部的业务行为),但不具备实现上的完整性(没有基础设施层的技术支持,系统不具备可运行性;没有用户接口层支持,系统不具备可访问性)
- 所有业务逻辑都在领域层实现,业务逻辑泄漏到应用层是一个错误,泄露到基础设施层或用户接口层是严重错误(在用户接口层中实现业务逻辑是采用CRUD模式的常犯的典型错误
- 判断业务层(领域层和应用层)是否被具体技术污染一个方便的方式是检查它们是否有对具体技术框架(例如Spring和Hibernate)的编译时依赖。业务层代码应该只依赖于JDK(java.)、Java规范(javax.),以及一些被广泛使用的类库如commons-lang、Guava、SLF4J、JodaTime等,这些类库本质上可视为对JDK的补充,不是一种具体技术框架
- 领域层在履行职责的过程中如果需要技术支持,则在领域层中定义一个表达业务意图的领域服务接口,交由基础设施层采用各种具体技术去实现这一接口。保证领域层(和应用层)不被各种具体技术污染是逻辑分层的第一要务。
- 应用层和门面层的区别:应用层属于后端,门面层属于前端。应用层方法的参数和返回值可以包含领域对象,门面层方法的参数通常是字符串和数字等简单值,返回值是简单值或DTO
- 可以基于相同的应用层建立不同的用户接口层
问题与思考
-
限界上下文对应于我们工作中的什么?
-
限界上下文和领域是一一对应的么?
理论上,一个Domain可能会对应多个Bounded Context;同样,一个Bounded Context可能也会对应多个Domain;所以他们之间没有绝对的关系。主要是他们划分的依据不同,一个是针对领域(问题空间),一个是针对领域模型(解决方案空间);理想情况,一个Domain最好对应一个Bounded Context; 领域面向的是问题空间,限界上下文针对的是解决方案空间。
-
实体和我们的数据库的DO的关系是什么?
-
两阶段提交
-
观察者模式 推和拉, kafka的拉模型
参考
DDD entity and database representation
Good Domain Driven Design samples
领域驱动设计(Domain Driven Design)参考架构详解
Sub-domains and Bounded Contexts in Domain-Driven Design (DDD)