第一部分 领域驱动设计的原则与实践
第一部分 领域驱动设计的原则与实践
- 第一部分 领域驱动设计的原则与实践
- 引言
- Ubiquitous Language(通用语言)的定义:
- 通用语言的目的:
- 通用语言的实现:
- 示例:
- 第1章 什么是领域驱动设计
- 1.1 为复杂问题域创建软件的挑战
- 1.2 领域驱动设计模式如何管理复杂性
- 问题空间
- 解空间
- 1.3 领域驱动设计的实践与原则
- 1.3.1 专注于核心领域
- 1.3.2 通过协作进行学习
- 1.3.3 通过探索和实验来创建模型
- 1.3.4 通信
- 1.3.5 理解模型的适用性
- 1.3.6 让模型持续发展
- 1.4 领域驱动设计的常见误区
- 1.4.1 战术模式是 DDD 的关键
- 1.4.2 DDD 是一套框架
- 1.4.3 DDD 是一颗灵丹妙药
- 1.5 要点
- 第2章 提炼问题域
- 2.1 知识提炼与协作
- 2.1.1 通过通用语言达成共识
- 2.1.2 领域知识的重要性
- 2.1.3 业务分析员的角色
- 2.1.4 一个持续过程
- 2.2 与领域专家一起获得领域见解
- 2.3 有效提炼知识的模式
- 2.4 查看现有模型
- 2.5 要点
- 第3章 专注于核心领域
- 3.7 要点
- 第4章 模型驱动设计
- 4.1 什么是领域模型
- 4.2 模型驱动设计
- 4.3 使用通用语言将分析和代码模型绑定在一起
- 4.4 基于通用语言进行协作
- 4.5 如何创建有效的领域模型
- 4.6 何时应用模型驱动设计
- 4.7 要点
- 第5章 领域模型实现模式
- 5.1 领域层
- 5.2 领域模型实现模式
- 5.2.1 领域模型
- 5.2.2 事务脚本
- 5.2.3 表模块
- 5.2.4 活动记录
- 5.2.5 瓮血领域模型
- 5.2.6 贫血领域模型和函数编程
- 5.3 要点
- 第6章 使用有界上下文维护领域模型的完整性
- 6.1 单个模型的挑战
- 6.2 使用有界上下文划分和破除大模型
- 6.3 实现有界上下文
- 6.4 要点
- 第7章 上下文映射
- 7.1 一个现实情况的映射
- 7.2 认识有界上下文之间的关系
- 7.3 传递上下文映射
- 7.4 上下文映射的战略重要性
- 7.5 要点
- 第8章 应用程序架构
- 8.1 应用程序架构
- 8.2 应用程序服务
- 8.3 应用程序客户端
- 8.4 要点
- 第9章 团队开始应用领域驱动设计通常会遇到的问题
- 9.1 过分强调战术模式的重要性
- 9.2 缺失了DDD的真实价值:协作、通信和上下文
- 9.3 在不重要的部分花费太多时间
- 9.4 简单问题复杂化
- 9.5 低估应用DDD的成本
- 9.6 要点
- 第10章 应用DDD的原则、实践与模式
- 10.1 推广使用DDD
- 10.2 应用DDD的原则
- 10.3 探究和实验
- 10.4 让隐式内容变得显式
- 10.5 问题解决人先行,技术专家后行
- 10.6 如何才能知道我在正确地工作
- 10.7 要点
- 资料
第一部分 领域驱动设计的原则与实践
引言
Ubiquitous Language(通用语言)的定义:
通用语言是 DDD 中的一个核心概念,它指的是在项目开发过程中,团队成员之间共享的、统一的沟通语言。这种语言专注于业务领域,用于描述业务概念、业务规则和业务流程,确保所有团队成员对业务领域有共同的理解和表达方式。
通用语言的目的:
- 促进沟通:通用语言作为团队内部沟通的桥梁,确保不同背景的团队成员(如开发人员、业务分析师、产品经理等)能够使用相同的术语和概念进行交流,减少误解和歧义。
- 指导设计:通用语言直接影响软件设计。在 DDD 中,软件的设计应该反映业务领域的概念和流程。通用语言为这种设计提供了基础,使得软件设计更加贴近业务需求。
- 提高理解:通过具体的文字描述,帮助团队成员更好地理解业务领域和需求,从而设计出更符合业务目标的系统。
- 文档化:通用语言可以作为项目文档的一部分,为未来的团队成员或系统维护者提供宝贵的参考。
- 促进协作:当团队成员使用通用语言进行交流时,可以促进不同背景的团队成员之间的协作,因为每个人都在讨论相同的概念。
通用语言的实现:
- 提炼业务概念:从业务领域中提炼出关键的概念和术语,形成通用语言的词汇表。
- 达成共识:团队成员需要对通用语言中的术语和概念达成共识,确保每个人都理解并使用相同的语言。
- 文档化:将通用语言的词汇表和相关概念记录在项目文档中,作为项目团队共享的参考资料。
- 代码实现:在代码中使用通用语言的术语和概念,使得代码成为通用语言的持久表达,确保业务需求被正确理解和实现。
示例:
假设你正在开发一个在线书店系统,以下是如何使用通用语言的具体例子:
- 业务讨论:在会议中,业务分析师可能会说,“客户可以浏览图书,将图书添加到购物车,并进行结账。”
- 通用语言:从这个讨论中,可以提炼出通用语言的术语,如“客户”、“图书”、“购物车”和“结账”。
- 文档化:这些术语被记录在项目文档中,成为项目团队共享的词汇表。
- 代码实现:在代码中,可能会有如下类和方法:
Customer
类表示客户。Book
类表示图书。ShoppingCart
类表示购物车,其中包含addBook(Book book)
方法。CheckoutService
类包含processCheckout(ShoppingCart cart)
方法处理结账。
通过这种方式,通用语言不仅帮助团队达成共识,而且确保了这种共识在代码中得到体现,从而使得软件设计与业务需求紧密对齐。
第1章 什么是领域驱动设计
1.1 为复杂问题域创建软件的挑战
1.2 领域驱动设计模式如何管理复杂性
问题空间
解空间
1.3 领域驱动设计的实践与原则
1.3.1 专注于核心领域
- 这是产品成功与否的卖点
1.3.2 通过协作进行学习
- 开发团队与业务专家协作创造模型
1.3.3 通过探索和实验来创建模型
- Eric Evans 建议,对于每一个良好设计都必须有至少三个较差的设计,这将避免团队在首
个有用模型处就停止前进。
1.3.4 通信
- 通过ul(通用语言)
1.3.5 理解模型的适用性
- 模型在对应的上下文会定义一些特殊的ul,而上下文会定义一个语言边界,避免语言中的歧义(如果语言在多个模型都有定义)
1.3.6 让模型持续发展
- 新的业务用例可能会破坏之前有用的模型,或者可能必须进行变更
以便让新的或现有的概念更易于理解。
1.4 领域驱动设计的常见误区
1.4.1 战术模式是 DDD 的关键
- Evans 介绍了使用软件设计模式的技术,以便让由开发团队和业务专家创建的模型能
够使用 UL实现。不过,如果没有分析和协作的实践,编码实现本身实际上意义不大。DDD
并不是以代码为中心的;其目的并非编写优雅的代码。软件不过是DDD的一个构件而已。
1.4.2 DDD 是一套框架
- DDD在架构上具有不可知性,因为不存在你必须遵循的固定单一的架构样式以实现 它。Evans 的文章中介绍了一种分层架构样式,但这并非唯一的选项。架构样式可以变化, 因为它们应该在有界上下文级别应用,而非应用程序级别。某个产品可能包括一个遵循以 事件为中心的架构的有界上下文,另一个产品则可能使用了分层的富领域模型,而第三个 产品可能应用了活动记录模式。
1.4.3 DDD 是一颗灵丹妙药
- 简单项目不适合,浪费时间
1.5 要点
- 领域驱动设计(DDD)是一种开发思想体系,它旨在管理为复杂问题域编写的软件的创建和维护工作。
- DDD 是模式、原则和实践的集合,它可以被应用到软件设计以管理复杂性。
- DDD 具有两种模式类型。战略模式影响的是解决方案,而战术模式用于实现富领域模型。战略模式对于任何应用程序都有用,但战术模式只有当模型在领域逻辑中足够丰富时才有用。
- 将大的问题域提炼成子域可以揭示核心领域——价值最大的区域。并非一个系统的所有部分都会被精心设计;团队必须在产品的核心子域中投入更多时间。
- 为每一个子域创建一个抽象模型以便管理领域问题。
- 可以使用一种通用语言将分析模型绑定到代码模型,以便开发团队和领域专家能够在模型设计方面进行协作。学习和创建一种语言以便交流与问题域有关的信息正是DDD的处理过程。代码是其构件。
- 为保留模型的完整性,要在有界上下文中定义它。模型要与应用程序基础架构所涉及的内容分离,以便将技术复杂性与业务复杂性分开。
- 对于模型或者共同工作的多个团队来说,如果术语存在歧义,则模型可以被划分并在较小的有界上下文中定义。
- DDD 并不会为开发强制规定任何特定的架构样式,它只会确保模型与技术复杂性保持分离,这样它就能专注于领域逻辑方面的内容。
- DDD 侧重于将关注点放在这些内容上:核心领域、协作、与领域专家进行探讨、实验研究以生成更有用的模型,以及对于在复杂问题域中起作用的各种上下文的理解。
- DDD 并非一种模式语言,它是专注于交付的一种协作思想体系,其中通信起着核心作用。
- DDD 是进行软件开发的一种以语言和领域为中心的方式。
第2章 提炼问题域
2.1 知识提炼与协作
2.1.1 通过通用语言达成共识
2.1.2 领域知识的重要性
- 领域知识是关键,其重要性甚至要远甚于技术知识。
2.1.3 业务分析员的角色
- 千万别将开发团队和最理解该部分业务的人之间的直接沟通完全屏蔽。
2.1.4 一个持续过程
- 知识提炼是一个持续过程;团队应该持续地为问题域的简单视图而努力,该简单视图
只专注于相关内容以便实现创建有用模型的目标。随着每一次的迭代完成,团队对于问题域的理解都会提升
2.2 与领域专家一起获得领域见解
2.3 有效提炼知识的模式
- 2.3.1 专注在最有意思的对话上
- 2.3.2 从用例开始
- 2.3.3 提出有力的问题
- 2.3.4 草图
- 2.3.5 CRC卡
- 2.3.6 延迟对模型中概念的命名
- 2.3.7 行为驱动开发
- 2.3.8 快速成型
- 2.3.9 查看基于纸面的系统
2.4 查看现有模型
- 2.4.1 理解意图
- 2.4.2 事件风暴
- 2.4.3 影响地图
- 2.4.4 理解业务模型
- 2.4.5 刻意发现
- 2.4.6 模型探讨漩涡
2.5 要点
-
知识提炼是处理领域信息以识别出能用于构建有用模型的相关碎片知识的技术。
-
知识是由开发人员与领域专家协作而获得的。协作有助于弥补所有的知识漏洞并促成共识。
-
共识是通过一种称为通用语言(UL)的共享语言来达成的。
-
知识提炼是一个持续过程;协作和业务人员的参与不应该局限于项目的初始阶段。深层见解和突破仅会产生于为解决问题而进行的多次开发迭代之后。
-
知识是团队所有成员在项目任何时点围绕白板讨论、在人们放松闲谈的场所进行讨论、头脑风暴以及用协作方式制作原型的过程中得到的。
-
领域专家是组织的主题专家。他们是那些能够提供问题域中见解的人(用户、产品所有者、业务分析员、其他的技术团队)。
-
你的业务相关人员将为你提供应用程序的需求,但他们可能并非解答领域详细问题的最佳人选。在对问题域的核心或复杂部分建模时可以借助领域专家的力量。
-
让你的领域专家参与到系统的最重要部分。不要仅列出所有需求并让他们对每一项表达意见。
-
要有计划地修改你的模型;不要太过投入,因为知识提炼中的突破可能会被废弃。
-
在与领域专家一同工作时,要关注问题域的最重要部分;要在使得应用程序取得成功的区域投入最多精力。
-
要围绕系统最重要的用例驱动知识提炼。要求领域专家遍历系统用例的具体场景,以便帮助弥补知识漏洞。
-
提出有力的问题并了解业务的意图。不要仅仅实现一组需求,而要主动让业务人员参与其中;与他们一同工作,而不是为他们工作。
-
使用草图和事件风暴技术可视化你所学到的知识。可视化一个问题域能够提升与业务专家的协作并让知识提炼环节更有趣。
-
使用BDD以专注于应用程序的行为,并让领域专家和业务相关人员关注在具体场景上。BDD是与领域专家和业务相关人员沟通的一个重要催化剂。它使用一种模板语言以一种标准可行的方式来捕获行为。
-
在代码中进行实验以证明模型的有效性,并提供出于技术原因需要对模型进行修改的反馈。
-
查看行业中已有的处理过程和模型,以避免重新发明轮子的情况以及加速领域知识的获取。
-
找出你不知道的内容,尽早识别出团队的知识漏洞,然后启用刻意发现。消除不了解的未知知识并尽早增长领域知识。
-
当需要如何探讨模型的指导时,可以借助Eric Evans的模型探讨漩涡。漩涡中的活动对于沟通障碍、过于复杂的设计或者团队遇到他们不太了解的问题域部分的情况尤其有用。
第3章 专注于核心领域
- 3.1 为何要分解一个问题域
- 3.2 如何捕获问题的实质
- 3.2.1 超越需求
- 3.2.2 为达成什么是核心内容的共识而捕获领域愿景
- 3.3 如何专注于核心问题
- 3.3.1 提炼问题域
-
3.3.2 核心领域
-
3.3.3 将你的核心领域当作一款产品而非一个项目
-
3.3.4 通用域
-
3.3.5 支撑域
-
3.4 子域如何决定解决方案的形成
-
3.5 并非一个系统的所有部分都会经过良好设计
-
3.5.1 专注于清晰边界而非完美模型
-
3.5.2 -开始核心领域不必总是需要是完美的
-
3.5.3 构建用于替代而非重用的子域
-
3.6 如果没有核心领域怎么办
3.7 要点
-
提炼用于分解大的问题域以便找出核心、支撑和通用域。
-
提炼有助于降低问题空间的复杂性。
-
专注和精力应该投入到核心领域。在此处使用你最好的开发人员。
-
核心领域是你编写软件的原因。
-
要考虑外包开发、采购支撑和通用域或者将初级开发人员放到支撑和通用域。
-
一份领域愿景说明会揭示对产品取得成功的核心内容的共识。使用领域专家、项目启动文档以及业务战略介绍来帮助发出领域愿景说明的通告。
-
随着你更多地了解问题,要规划核心领域内模型的变更。不要太过于重视一个解决方案——你的核心领域会随着时间变化而改变。
-
并非一个系统的所有部分都会被精心设计。将精力专注在核心领域上。对于遗留的BBoM系统,应该定义一个防止损坏边界来避免新代码变得与混乱的旧代码交织在一起。
第4章 模型驱动设计
4.1 什么是领域模型
4.1.1 领域与领域模型的对比
4.1.2 分析模型
4.1.3 代码模型
4.1.4 代码模型是领域模型的主要表现
4.2 模型驱动设计
- 模型驱动设计与 DDD的区别在于,模型驱动设计专注于实现以及对于初始模型可能需要修改的约束,而 DDD 专注于语言、协作和领域知识。二者彼此互补;模型驱动设计方法使得领域知识和共同语言能够被纳入软件模型中,该模型反映了业务专家的语言和思维模型。
4.2.1 预先设计的挑战
图 4-4 显示出,当开发团队未参与到领域知识提炼中时,分析和代码模型会如何彼此
分离。
4.2.2 团队建模
4.3 使用通用语言将分析和代码模型绑定在一起
- 4.3.1 语言的生存周期将大于软件
- 4.3.2 业务语言
- 4.3.3 开发人员和业务之间的转
4.4 基于通用语言进行协作
4.4.1 通过使用具体示例来定制出语言
4.4.2 教导你的领域专家专注在问题上而不要跳到解决方案
4.4.3 塑造语言的最佳实践
4.5 如何创建有效的领域模型
4.5.1 不要让实情妨碍一个好模型
4.5.2 仅对相关内容建模
4.5.3 领域模型都是暂时有用的
4.5.4 要十分清楚专业术语
4.5.5 限制你的抽象
-
1.将你的抽象重点放在合适的抽象层级
-
2.对行为而非实现进行抽象
-
3.尽早频繁地在代码中实现模型
-
4.不要止步于第一个好想法
4.6 何时应用模型驱动设计
- 4.6.1 如果它不值得花费精力,则不要尝试对其建模
- 4.6.2 专注于核心领域
4.7 要点
-
领域是问题的实际情景。领域模型是基于旨在处理特定业务用例的领域映射的一组抽象。
-
模型是由分析模型和代码模型来表示的。它们完全是一回事。
-
领域模型是作为分析模型和代码模型存在的。模型驱动设计通过通用语言的使用将分析模型和代码模型绑定在一起。
-
分析模型只有在它保持与代码模型协同时才有用。
-
如果正在构建分析或代码模型,那么必须亲自实践并为代码贡献自己的力量。也有架构师的一席之地,但他们必须也是编程者。
-
代码是表述模型的主要形式,需要使用通用语言来约束它。
-
开发 UL 的过程都是领域驱动设计(DDD)最重要的一环,因为它能促进沟通和学习。
-
必须明确定义领域专业术语以确保含义准确,因为沟通中使用的专业语言会被融入代码实现中。
-
要让团队需要理解的领域中隐含的观念变得明确并赋予会组成共享通用语言的名称。
-
领域充满了以清晰、准确方式描述复杂概念的特殊术语和语言。
-
特色事例和场景能帮助你理解系统的行为,而领域专家将帮助你构建能够支持特定行为的模型。
-
通用语言应该用于测试、命名空间、类名称和方法。
-
关心对话沟通很重要;通用语言关乎协作,而不仅仅是开发团队采用该业务语言而已。
-
使用领域场景来证明模型的可用性并验证团队对于领域的理解。
-
仅为核心领域应用模型驱动设计并创建 UL 才能带来变化。不要将这些实践应用到整个应用程序。
第5章 领域模型实现模式
5.1 领域层
5.2 领域模型实现模式
- 领域模型
- 事务脚本
- 表模块
5.2.1 领域模型
图 5-4 显示了一家在线拍卖网站领域模型的一部分。该模型中的对象代表了用于满
足一次拍卖行为的问题域的概念。
代码清单 5-1:一个丰富领域模型中的 Auction 类
public class Auction
{
// 其他成员和方法...
public void PlaceBidFor(Bid bid, DateTime currentTime)
{
if (StillInProgress(currentTime))
{
if (FirstOffer())
{
PlaceABidForTheFirst(bid);
}
else if (BidderIsIncreasingMaximumBid(bid))
{
WinningBid = WinningBid.RaiseMaximumBidTo(bid.MaximumBid);
}
else if (WinningBid.CanBeExceededBy(bid.MaximumBid))
{
Place(WinningBid.DetermineWinningBidIncrement(bid));
}
}
}
// 其他成员和方法...
}
5.2.2 事务脚本
public class BidOnAuction : ICommand
{
public BidOnAuction(Guid auctionId, Guid bidderId, decimal amount, DateTime timeOfBid)
{
// 构造函数的实现(初始化代码等)
}
public void Execute()
{
using (TransactionScope scope = new TransactionScope())
{
// 如果拍卖ID、出价者ID、金额或出价时间无效,则抛出异常
ThrowExceptionIfNotValid(auctionId, bidderId, amount, timeOfBid);
// 如果拍卖已结束,则抛出异常
ThrowExceptionIfAuctionHasEnded(auctionId);
// 如果是第一次出价
if (IsFirstBid(auctionId))
{
PlaceFirstBid(auctionId, bidderId, amount, timeOfBid);
}
// 如果出价者在增加其最大出价
else if (IsIncreasingMaximumBid(auctionId, amount, bidderId))
{
IncreaseMaximumBidTo(amount);
}
// 如果出价可以满足或超过出价增量
else if (CanMeetOrExceedBidIncrement(amount))
{
UpdatePrice(auctionId, bidderId, amount, timeOfBid);
}
// 提交事务
scope.Complete();
}
}
// 其他成员和方法...
}
5.2.3 表模块
表模块模式会将对象模型映射到数据库模型。
5.2.4 活动记录
5.2.5 瓮血领域模型
5.2.6 贫血领域模型和函数编程
5.3 要点
- 领域层包含领域模型,且与基础架构和呈现问题相分离。
- 领域模型可以使用多种领域逻辑模式来实现。
- 一个大型项目可能有多个模型在发挥作用,因此也就有多个模式来表示领域逻辑。
- 只要该模式能够将表示领域逻辑的代码与技术代码分离开,那么它就适合于 DDD。
- 领域模型模式适合于复杂问题域。领域中的概念被封装为同时包含数据和行为的对象。
- 事务脚本模式会在程序模块中组织所有的领域逻辑来满足业务事务或用例。
- 表模块模式代表着以对象形式建模的数据。表模块可用于紧密反映底层数据结构的数据驱动模型。
- 活动记录模式类似于表模块模式,它也是数据驱动的,但是它表示的是表中的行而不是表本身。它适合于具有低复杂性逻辑而又高度基于 CRUD 的模型。
- 贫血模型类似于领域模型模式,不过该模型不包含任何行为。它纯粹是一个对象状态模型,所有行为都驻留在修改的服务类中。
- 函数编程是构建领域模型的一种同样有效的方法。
- 在使用函数编程时,可以将行为分组成聚合(表示领域概念)并应用于纯粹的不可变的数据结构(也表示领域概念)。
第6章 使用有界上下文维护领域模型的完整性
6.1 单个模型的挑战
-
6.1.1 模型的复杂性可能会增加
-
6.1.2 多个团队处理单个模型
-
6.1.3 模型语言中的歧义
-
6.1.4 领域概念的适用范围
- 6.1.5 集成遗留代码或第三方代码
- 6.1.6 领域模型并非企业模型
6.2 使用有界上下文划分和破除大模型
错误的定义产品
正确的定义产品
6.2.1 定义模型的边界
6.2.2 子域和有界上下文之间的差异
6.3 实现有界上下文
6.4 要点
-
尝试将单个模型用于复杂问题域通常会导致代码变成大泥球。
-
单个模型会增加团队之间的协作成本并且降低其交付业务价值的效率。
-
对于在应用程序中发挥作用的每个模型来说,必须明确定义其上下文并与其他团队就它进行沟通。
-
一个有界上下文就是一个语言边界。它会隔离模型以免除用户界面(UI)中的歧义。
-
有界上下文会保护领域模型的完整性。
-
识别并创建有界上下文是领域驱动设计的一个最重要的内容。
-
没有用于定义模型边界的规则,因而也就没有定义有界上下文的规则。应该转而根据围绕语言边界、团队组织、子域和物理部署来定义。
-
在问题空间中使用子域以便对问题域分区。有界上下文用于定义解空间中模型的适用范围。
-
单个团队应该拥有一个有界上下文。
-
架构模式是在有界上下文的级别而非应用程序级别应用的。如果有界上下文中没有复杂逻辑,则可以使用简单的创建、读取、更新和删除(CRUD)架构。
-
在明确的有界上下文中使用通用语言。
-
有界上下文中使用通用语言应该自主拥有从展现到领域逻辑,再到数据库和结构的完整代码堆栈。
第7章 上下文映射
7.1 一个现实情况的映射
7.1.1 技术的现实
7.1.2 组织的现实
7.1.3 映射一个相关现实情况
7.1.4 用X标记核心领域的位置
7.2 认识有界上下文之间的关系
7.2.1 防止损坏层
7.2.2 共享内核
7.2.3 开放宿主服务
7.2.4 分道扬镳
7.2.5 合作关系
7.2.6 一种上游/下游关系
7.3 传递上下文映射
7.4 上下文映射的战略重要性
7.4.1 保持完整性
7.4.2 解决计划的基础
7.4.3 理解所有权和职责
7.4.4 揭示业务工作流中的混乱区域
7.4.5 识别非技术障碍
7.4.6 鼓励良好的沟通
7.4.7 帮助加入的新员工
7.5 要点
- 上下文映射会反映现有情况的样子。它会提供技术集成方法以及有界上下文之间关系的完整视图。如果没有它们,模型就会受损,而在集成让模型适用性的边界线变得模糊不清时,有界上下文会迅速变成泥球。
- 防止损坏层会在与另一个上下文交互时为模型提供隔离。该层会通过提供一个上下文到另一个上下文的转译来确保不损害完整性。
- 使用共享内核模式的集成可用于有重叠且共享一个公用模型的上下文。
- 集成通过开放宿主服务公开一个外部 API,而不是请求客户端将一个模型转换成另一个模型。通常来说。这会为客户端创建一个可使用的发布语言。
- 有界上下文之间的关系应该从相互成为彼此的上游或下游这方面来理解。上游上下文对下游上下文有影响。
- 不为了共同目标工作或者不在同一项目上工作的两个团队之间的协作称为顾客-供应商关系。下游顾客可以与其上游供应商协作以集成上下文。
- 遵从模式描述了上游和下游团队之间的关系,该模式中上游团队不会与下游团队协作。这就是当上游团队是第三方团队时通常会出现的情形。
- 合作伙伴关系模式描述了具有共同目标且通常在同一个项目上处理的却是两个不同上下文的两个团队。
- 如果有界上下文的集成成本太高且没有其他可用的非技术方法,那么应该遵循分道扬镳方式。
第8章 应用程序架构
8.1 应用程序架构
8.1.1 分离应用程序的问题
8.1.2 从领域的复杂性中进行抽象
8.1.3 分层架构
8.1.4 依赖倒置
8.1.5 领域层
8.1.6 应用程序服务层
8.1.7 基础架构层
8.1.8 跨层通信
8.1.9 隔离测试
8.1.10 不要在有界上下文之间共享数据结构
8.1.11 应用程序架构与用于有界上下文的架构的对比
8.2 应用程序服务
8.2.1 应用程序逻辑与领域逻辑的对比
8.2.2 定义和公开能力
8.2.3 业务用例协作
8.2.4 应用程序服务表示的是用例,而不是创建、读取、更新和删除
8.2.5 作为实现详情的领域层
8.2.6 领域报告
8.2.7 读取模型与事务模型的对比
8.3 应用程序客户端
8.4 要点
- DDD 不需要特殊的架构,只要是能将技术问题与业务问题分离的架构即可。
- 分离应用程序的问题,通过对应用程序进行分层来将业务复杂性从技术复杂性中隔离出来。
- 外围层依赖于内部层。内部层会公开外围层必须遵从和实现的接口。这一依赖倒置形式将保护领域和应用层的完整性。
- 领域层位于应用程序的核心位置。它是通过应用层从技术复杂性中隔离出来的。
- 应用程序服务会通过将领域逻辑抽象到一个较高的层级来公开系统能力。
- 应用程序服务的基础是围绕业务用例,它们是领域层的客户端。它们将委托领域层来满足用例。
- 应用程序服务应该对使用它们的客户端保持毫不知情的状态。客户端应该遵从应用程序的 API,该 API 将能够支持有差异的客户端。
- 应用程序服务层是有界上下文边界的具体实现。
第9章 团队开始应用领域驱动设计通常会遇到的问题
9.1 过分强调战术模式的重要性
9.1.1 将相同架构用于所有的有界上下文
9.1.2 力求战术模式尽善尽美
网9.1.3 错误估计构造块对于DDD的价值
9.1.4 专注于代码而非DDD的原则
9.2 缺失了DDD的真实价值:协作、通信和上下文
9.2.1 由于低估上下文的重要性而产生大泥球
9.2.2 未能成功创建UL将造成歧义和误解
9.2.3 由于缺乏协作将只能设计专注于技术的解决方案
9.3 在不重要的部分花费太多时间
9.4 简单问题复杂化
9.4.1 将DDD原则应用到具有少量业务预期的琐碎领域
9.4.2 别将CRUD作为反模式
9.4.3 将领域模型模式用于每一个有界上下文
9.4.4 问一问自己:额外的复杂性是否值得
9.5 低估应用DDD的成本
9.5.1 尝试在没有积极专注的团队的情况下取得成功
9.5.2 项目背后没有领域专家时的协作尝试
9.5.3 在非选代式开发方法中进行学习
9.5.4 将DDD应用到每一个问题!
9.5.5 为不必要的纯粹性而牺牲实用主义
9.5.6 寻求验证会浪费精力
9.5.7 永远力求代码之美
9.5.8 DDD关乎的是提供价值
9.6 要点
-
DDD的战术模式可以指导你通向创建有效领域模型之路;不过,DDD的这一方面是不断发展的,而实现的细节会被过度强调。该模式可能会有价值,但这并非DDD的真正价值所在。
-
DDD远不止编码这么简单。与领域专家的协作以进行知识提炼,以及对在通用语言中表述的问题域达成共识才是DDD 的支柱。
-
上下文就是一切:上下文和隔离将保持代码的完整性。它会降低认知负荷并让模型具有特定用途。
-
需要一个愿意学习该领域的聪明专注的团队。
-
需要领域专家的参与。没有他们,团队就无法揭示更深层的见解。
-
将CRUD用于具有低复杂性的有界上下文。如果没有领域模型,则你就不是差劲的编程人员。
-
有界上下文和通用语言是DDD的基础。
-
DDD关乎为了在协作中找出一个有用模型而进行学习、提炼、实验以及探究的过程。
第10章 应用DDD的原则、实践与模式
10.1 推广使用DDD
10.1.1 培训团队
10.1.2 与业务人员进行交流
10.2 应用DDD的原则
10.2.1 理解愿景
10.2.2 捕获所需的行为
10.2.3 理解环境的现实情况
10.2.4 对解决方案建模
10.3 探究和实验
10.3.1 质疑假设
10.3.2 建模是一项持续性活动
10.3.3 不存在错误的模型
10.3.4 灵活的代码有助于探素发现
10.4 让隐式内容变得显式
网10.4.1 处理歧义
网10.4.2 为事物命名
10.5 问题解决人先行,技术专家后行
10.6 如何才能知道我在正确地工作
10.6.1 好用就足够了
10.6.2 实践、实践、实践
10.7 要点
-
不要把DDD当作灵丹妙药来推广使用。要专注于与业务保持一致并且学习与正在为之构建软件的领域有关的更多知识。
-
仅在需要时应用DDD原则。不要将其用作解决所有问题的工具。
-
分解问题空间并专注于核心领域。所有利益相关的对话都在此处发生。这就是应用DDD原则以便最大化价值的地方,也是应该投入最大精力的地方。
-
在对解决方案建模之前,要捕获环境的现实情况,并理解发挥作用的其他模型和上下文。谁对其负责?你与它们之间有什么关系?交换了什么数据以及怎么交换的?
-
构建一个模型来满足功能场景。从最具风险或最复杂的场景开始。在此处利用好领域专家的时间,并且不要用简单的数据管理来打扰他。
-
如果正在一个遗留环境中工作,则要确保能保护好你自己免受外部代码干扰,不要相信任何人,并且要强化边界。分割出一个区域以添加新的功能。不要试图清理所有内容。
-
持续集成、改进和挑战模型。不要止步于第一个好想法。通过尝试新的模型和解决方案来探究和实验,并且验证好的想法。至少要有3个有用模型。
-
不要作任何假设,保持事物的简单性,推迟进行大的设计决策,等待复杂性或新的行为挑战解决方案。然后在需要时朝着战略模式的方向进行重构。
-
建模是一项团队活动,并且应该在团队停滞、遇到不确定的区域或者需要阐明的时候进行建模。它不应该受限于项目时间线中的预定义步骤。
-
模型和语言要一同演化。不能轻易交流和谈论的模型其实用性将很有限并且将很难对其演化。
资料
域驱动设计的模式、原则和实践 |威利这里边的下载