设计理念
设计理念
领域驱动设计的战略核心即是将问题域与应用架构相剥离,将业务语义显现化,把原先晦涩难懂的业务算法逻辑,通过领域对象(Domain Object
-
统一语言,软件的开发人员
/ 使用人员都使用同一套语言,即对某个概念,名词的认知是统一的,建立清晰的业务模型,形成统一的业务语义。将模型作为语言的支柱。确保团队在内部的所有交流中,代码中,画图,写东西,特别是讲话的时候都要使用这种语言。例如账号,转账,透支策略,这些都是非常重要的领域概念,如果这些命名都和我们日常讨论以及PRD 中的描述保持一致,将会极大提升代码的可读性,减少认知成本。。比如不再会有人在会议中对“工单”、 “审核单”、 “表单”而反复确认含义了,DDD 的模型建立不会被DB 所绑架。 -
面向领域,业务语义显性化,以领域去思考问题,而不是模块。将隐式的业务逻辑从一推
if-else 里面抽取出来,用通用语言去命名、去写代码、去扩展,让其变成显示概念;很多重要的业务概念,按照事务脚本的写法,其含义完全淹没在代码逻辑中没有突显出来。 -
职责划分,根据实际业务合理划分模型,模型之间依赖结构和边界更加清晰,避免了混乱的依赖关系,进而增加可读性、可维护性;单一职责,模型只关注自身的本职工作,避免“越权”而导致混乱的调用关系。通过建模,更好的表达现实世界中的复杂业务,随着时间的发展,不断增加系统对实际业务的沉淀,也将更好的通过清晰的代码描述业务逻辑,模型的内聚增加了系统的高度模块化,提升代码的可重用性,对比传统三层模式中,很有可能大量重复的功能散落在各个
Service 内部。- 限界上下文:通过限界上下文对整个系统进行划分,将庞大的软件系统划分为松散耦合的多个小系统,基于业务进行垂直切割
- 利用分层架构和六边形架构思想:利用 分层架构 与 六边形架构 思想对其进行逻辑分层,以确保业务逻辑与技术实现的隔离
接触到需求第一步就是考虑领域模型,而不是将其切割成数据和行为,然后数据用数据库实现,行为使用服务实现,最后造成需求的首肢分离。以银行账号
设计原则
-
Focusing on the Core Domain: DDD 强调需要将最多精力集中在核心子域上,核心子域是产品成败的关键,它的是产品的独特卖点,是它被建造而不是购买的原因。核心领域,将为您提供竞争优势,并为您的产品创造真正的商业价值,所有团队都了解核心领域是至关重要的。 -
Learning through Collaboration: DDD 强调开发团队和业务专家之间合作的重要性,以产生解决问题的有用模型。如果没有业务专家的这种协作和承诺,很多知识共享将无法进行,开发团队也无法对问题领域有更深的了解。事实也是如此,通过协作和知识紧缩,企业有机会了解到更多关于其领域的知识。 -
Creating Models through Exploration and Experimentation: DDD 将分析模型和代码模型视为一个整体,这意味着技术代码模型通过共享UL 与分析模型绑定。这意味着技术代码模型通过共享UL 与分析模型绑定。分析模型的突破会导致代码模型的改变。代码模型的重构,揭示了更深层次的洞察力,又会体现在业务的分析模型和心理模型中。只有当团队有时间去探索一个模型并对其设计进行实验时,才会有突破性的进展。花时间进行原型设计和实验,可以在很大程度上帮助你塑造一个更好的设计。它也可以揭示出一个糟糕的设计是什么样子的。埃里克- 埃文斯建议,每一个好的设计至少要有三个坏的设计,这样可以防止团队停留在第一个有用的模型上。 -
Communication: 有效描述为代表问题领域而建立的模型的能力是DDD 的基础。这就是为什么,毫无疑问,DDD 最重要的一个方面就是创建UL 。如果没有一种共享的语言,业务团队和开发团队之间为解决问题而进行的协作就不会有效。团队之间在知识紧缩会议中产生的分析和心智模型需要一种共享的语言来将其与技术实现结合起来。如果没有一个有效的方式来沟通问题领域内的想法和解决方案,设计的突破就不可能发生。 -
Understanding the Applicability of a Model: 建立的每个模型都是在其子域的背景下理解的,并使用UL 进行描述。然而,在许多大型模型中,UL 内可能存在模糊性,组织的不同部分对一个共同的术语或概念有不同的理解。DDD 通过确保每个模型都有自己的UL ,且只在特定上下文中有效来解决这个问题。每个上下文定义了一个语言边界;确保模型在特定的上下文中被理解,以避免语言的歧义。因此一个具有重叠术语的模型被分为两个模型,每个模型在自己的上下文中被明确定义。在实现方面,策略模式可以强制执行这些语言边界,使模型能够孤立地发展。这些策略模式导致有组织的代码,能够支持变化和重写。 -
Constantly Evolving the Model: 任何一个从事复杂系统的开发人员都可以写出好的代码,并在短时间内维护好它。然而,如果没有源代码和问题域之间的协同,继续开发很可能最终导致代码库难以修改,从而导致BBoM 。DDD 有助于解决这个问题,它强调团队要不断审视模型对当前问题的有用性。它挑战团队在获得领域洞察力时,对领域的复杂模型进行进化和简化。DDD 仍然不是什么灵丹妙药,需要奉献精神和不断的知识紧缩,才能生产出可维护多年的软件,而不仅仅是几个月。新的业务案例可能会打破以前有用的模型,或者可能需要改变,使新的或现有的概念更加明确。
DDD 价值
应对复杂业务
引起软件系统复杂度的主要因素是需求,软件系统需求又可以分两个方面:业务需求和技术需求。我们分析系统的复杂度时就可以从业务复杂度和技术复杂度这两个维度出发。
业务复杂度跟系统的业务需求规模和需求之间的关系层级有直接关系,需求的数量和关系的层级决定代码的规模和逻辑循环或递归的层级,系统的需求数量越大,需求之间的关系越复杂,系统的业务复杂度就越大。
$$ C=\sum_{p} \mathrm{C}{p} \mathrm{t}{p} $$
子模块的复杂度(cp)乘以该模块对应的开发时间权重值(tp
快速响应业务变化
不确定性和变化是这个时代的主旋律,业务需要快速上线,并根据用户的反馈不停地调整和升级,有生命力的业务主动寻求变化,不变则亡是很多行业目前的共识,企业应对变化的响应力成了成败的关键。同时一个长期困扰软件研发的问题是,需求总是在变化,无论预先设计如何“精确”,总是发现下一个坑就在不远处。相信很多技术人员都有这样的经历,架构和响应能力越来越糟糕,也就是我们常说的架构腐化了,最后大家不得不接受重写。软件架构设计的另一个关键方面是让系统能够更快地响应外界业务的变化,并且使得系统能够持续演进。在遇到变化时不需要从头开始,保证实现成本得到有效控制。
与微服务相得益彰
在面对复杂业务和快速变化需求时,

辅助中台战略落地
领域驱动设计让参与者基于统一语言沟通和协作,围绕一个统一和一致的领域模型工作,传统的分析模型和设计模型不再割裂;显式地把业务领域和设计放到了软件开发的核心,软件人员和业务人员合作来构建领域模型,使得软件的交付质量更高且维护成本更低;利用限界上下文来分解问题域,识别核心领域,有效分解和控制了业务的复杂度;利用
设计过程
领域驱动设计是一套面对复杂业务进行建模和设计的方法论和实践,建立了以领域为核心驱动力的设计体系。我们首先可以将领域设计模式分解到问题空间(Problem Space)与解空间(Solution Space)两大类中:问题空间的划分更多着眼于业务上值得注意的、重要的点;解空间则更关注与应用的组织架构,保证应用本身更易于管理。


这里领域专家会起到关键的作用,他应该通晓研发的这个产品需要解决哪些问题,专业术语,关联关系。对于简单的业务领域,一个领域可能就是一个小的子域。领域建模过程相对简单,根据事件风暴可以分解出事件、命令、实体、聚合和限界上下文等,根据领域模型和微服务拆分原则设计出微服务即可。对于复杂的业务领域,领域可能还需要拆分为子域,甚至子域还会进一步拆分,如:保险领域可以拆分为承保、理赔、收付费和再保等子域,承保子域还可以再拆分为投保、保单管理等子子域。对于这种复杂的领域模型,是无法通过一个事件风暴完成领域建模的,即使能完成,其工程量也是非常浩大,效果也不一定好。
从领域驱动设计落地的过程中,又可以划分为战略设计与战术设计:

-
在战略设计阶段,面对纷繁复杂的业务需求,领域专家和研发团队进行紧密合作、充分沟通,进行事件风暴或场景驱动设计,分析需求并提炼知识,得到比较清晰的问题域,输出由领域专家和研发团队达成共识的统一语言(UL,Ubiquitous Language
) ,基于统一语言对问题域进行分析和建模,识别业务边界,确定限界上下文,根据限界上下文划分独立的领域,建立限界上下文彼此之间的关系,接着引入系统上下文(System Context) 确定系统的边界,并确定它的外部环境,包括与其集成的第三方系统与基础设施。利用DDD 分层架构或六边形架构界定业务领域和技术实现的边界,让稳定的核心领域模型处于架构的最内部,避免技术实现和架构变动带来的影响。 -
接着进入战术设计阶段,一个大的业务问题被分解为多个限界上下文(问题域
) ,团队视野和专注就可以聚焦到每一个内聚的限界上下文,进行战术设计。战术设计的重点是利用领域驱动设计的元模型对领域的复杂性进行分解和建模。领域驱动设计强调和突出了领域模型的重要性,通过整个领域驱动设计过程,绑定领域模型和技术模型,以保证领域模型和技术模型在贯穿整个软件开发的生命周期中(需求分析、建模、架构、设计、编码、测试与持续重构)的强一致性。领域模型指导着软件设计以及技术编码实现,接着通过重构实践来挖掘隐式概念,完善统一语言和模型,运用设计模式改进设计与开发质量。
以下是领域驱动设计的粗略过程:

对于这种复杂的领域,我们可以分三阶段来完成领域模型和微服务设计:
- 拆分子域建立领域模型:根据业务特点考虑流程节点或功能模块等边界因素(微服务最终的拆分结果很多时候跟这些边界因素有一定的相关性
) ,按领域逐级分解为大小合适的子域,针对子域进行事件风暴,记录领域对象、聚合和限界上下文,初步确定各级子域的领域模型。 - 领域模型微调:梳理领域内所有子域的领域模型,对各子域模型进行微调,这个过程重点考虑不同限界上下文内聚合的重新组合,同步需要考虑子域、限界上下文以及聚合之间的边界、服务以及事件之间的依赖关系,确定最终的领域模型。
- 微服务设计和拆分:根据领域模型的限界上下文和微服务的拆分原则,完成微服务的拆分和设计。