一 前言
领域驱动设计简称“DDD”,一套“知易行难”的方法论。同时我所工作的这些年,尤其在某大厂做初创项目的那段时间,经常会产生各式各样的“思想碰撞”,特别在设计中台基建类领域时,为了保证充足的扩展性和稳定性,都要好好的“碰撞”一下。虽然在设计过程中,每个人的想法不尽相同,但是最终达成一致的那一刻,每个人的技术思想都会得到提升。
对于DDD,我的观点是,它是一套非常优秀的能提升个人认知高度的方法论。注意,我说的是个人认知,不仅是它所带来的业务和团队价值(它所带来的业务和团队价值会在下面讲)。它的战略设计方法论能很好提升技术人员的全局视野,它的战术设计方法论也能强化个人的技术细节把控力和结构性思维。除此之外,好的DDD设计也反映出一个技术人员对于业务的理解力,往往优秀的领域专家也是半个业务专家。
如果你一直困惑于自己究竟该如何提升技术和业务思考能力;如何提升全局视野,提升自己的结构化思维的能力;如何在写了这么多代码,做了这么多需求的情况下,补充系统化的技术理念。如果这些疑惑点你都涉及,那么理解DDD,同时按照DDD的方式去思考和建设,能够为你带来显著的提升。
同时我还要说明下,因为DDD的一些概念比较抽象,会让刚了解的同学产生困惑和模糊感,所以关于战略和战术设计部分,我都会用实际的例子来解释。基于我的经验,最简单的解释才是有效的,所以我会用非常白话的方式表述清楚DDD的实战部分,所以大家不用担心理解问题。
PS:我最后想了下,还是要用个完整的示例来演示下DDD的建模流程,否则光说理论体感太弱,所以文章最后部分,我结合四色建模,加上我自己的过往建模经验,演示了某体验产品0-1建设的具体流程(暂不涉及代码和工程部分),比较喜欢看具体示例的可以直接拖到最后一部分。
二 DDD是什么
2004年,Eric Evans在发表了一部名为《Domain Driven Design》的著作,其中提及了一套从系统分析到软件设计的方法论——领域驱动设计,简称DDD,领域建模的思想随即铺展开来。
DDD设计的目标是实现软件系统与业务需求的高度契合,提高开发效率和质量,同时也能更好地应对复杂性和变化性。它强调以业务为中心,通过深入领域知识和建立有效的领域模型,来驱动软件设计和开发的整个过程。其中几个核心理论提炼如下:
领域驱动设计——软件设计复杂性解决之道。它是为了解决复杂软件设计的一种优秀方案,但不是唯一。
它把所有的业务规则、定义、范围、知识等抽象成了一个大的概念,叫做领域。比如用户支付的业务场景,叫做交易域;平台提供售后等服务叫做服务域(或客服域),还有其他诸如金融域,人效域,物流域等。
它应对复杂性的思想,总结下来既简单,又精炼,叫做“分而治之”。把最大化的领域(复杂问题)分为下层的一个个子域,同时每个子域又规定好边界和核心实体,通过一系列的拆分、归类、衍生,最终找到更优解。
业务是在变的,如何从多变的业务环境中,保持内核的稳定性和扩展性,适应多变的业务发展,这是应对复杂性的第二个关键点。
领域模型是一套贯穿了整个软件,从设计到交付的生命周期的方法论,因为他的共识性,可以让开发、产品、架构师围绕着统一的模型去设计和探讨,不至于走样。
领域模型的图形表达方式,在实操上除了实体模型图的表达比较特殊,其他的时序、状态机、流程图其实无特殊性。
领域模型是业务的抽象,这点很关键,同时领域模型的设计应该是基于现实,但不等于现实。
评论领域模型设计是否优秀的方法很简单:5年后,剔除掉所有的增值域,第一版建设的域模型是否还符合优秀的稳定性、扩展性和灵活性。
领域模型不是所有的软件工程都适合,我经常会问面试者一个问题,一个FBI(数据看板系统),一个电商交易系统,它们都适合用DDD吗,为什么?
三 DDD和MVC的比较
在讲解DDD的价值前,我们先看下DDD这个理念提出来之前,经典的MVC开发模式。
如图,Controller负责业务逻辑的处理,Model代表和持久层交互的数据模型,View层负责视图展示。MVC架构其实很精粹,清晰,对于业务逻辑并不复杂,单一化的场景其实效率是很高的。但是随着业务的多变性和不断复杂化,MVC架构就会暴露以下问题:
MVC架构没有边界划分的概念和规范,在复杂的业务场景下会造成盘根交错的逻辑依赖,同时随着业务场景的不复杂化,代码意图会逐渐模糊,维护成本增加,对于系统的稳定性也会带来挑战。
MVC仅反映软件架构的分层,不定义业务语义的抽象和表达,对于业务知识的沉淀和复用性来说,不太友好。
MVC分割了数据和行为的表达,Model层(pojo)定义数据,Service层表述行为,会造成业务逻辑的首尾分离。
于是,为了解决以上问题,DDD的概念被提了出来。
四 DDD究竟能带来什么价值
业务(团队)价值
统一语言
同一团队,同一语言。这里的团队不仅是指技术团队,也包含业务、运营、产品、质量等。所有角色的认知语言统一化,不论是在沟通、设计、文档编写、画图、编码等任何环节,都使用同一种语言,保证效率的最大化。
清晰的边界定义
DDD的非常重要的一个概念,就是划分领域和子域的边界,通过边界和核心实体的聚合与建立,定义出清晰的业务范围,避免边界纷争(技术人员应该经常会遇到,明明这个事情属于A范围,但是却要B的应用改造;明明很基础的一个通用能力,AB两个应用各做了一个,改造成本*2,同时还要兜底解决一系列不一致问题)。
领域能力沉淀和复用
业务能力的可复用性,是衡量软件架构设计优秀与否的一个重要指标,强大的复用能力,对于研发效能和业务效能的提升具有很好的正向作用。DDD通过领域能力的沉淀和打磨,使业务和模型统一,也使领域能力得以传承。
面向业务建模
基于现实业务做业务领域的抽象,切分数据和领域(业务)模型,从而降低整个软件复杂度。开发人员应始终聚焦于领域模型,而不是传统理念中关注数据层和接口层的设计。
设计和代码的等价
设计即代码,代码直观表现设计。好的DDD设计,在方案上一句代码都没有,但是却已经清晰的表明了所有的代码实现(尤其在代码结构、层次、定义上会感受得更清楚)。
个人价值
提升全局视野
做领域建模的第一阶段是战略设计,其实就是在做全局业务,流程的梳理,同时对于其中的域划分都要有清晰的标准。要梳理清楚刚说的几项内容,没有全局的认知和思考是不行的,同时当负责人员梳理完这一阶段的时候,潜移默化的其实就已经提升了个人的全局意识和视野了。这也就是我们常说的一个领域专家,也往往是半个业务专家的由来了。
提升业务sense
这个和团队价值中“面向业务建模”具备强关联性,因为DDD是面向业务建模为出发点,所以一切都需要在具备优秀的业务敏感度下进行,没有业务sense也做不好DDD,而做好了DDD,业务sense也一定不错。同时在某大厂接触DDD前期,让我收益最大的一句话是——“业务不吃透,不聊技术”。
构建体系化思维
体系化思维强调将事物、概念和关系组织成一个有条理、有结构的整体,能够更全面、深入地理解问题本质,提供更有效的解决方案(体系化思维其实也是结构化思维的一种呈现,在这里推荐一本书《金字塔思维》,讲的是从过程化思维向结构化思维升级的一些方式方法)。DDD的几个核心概念,要求负责人不能只从单点去看问题,需要从线和面上去深入理解,这点能很好的帮助个人去构建体系化思维的能力。
五 DDD缺点
任何事物都一定存在正反两面,虽然DDD在构建复杂软件模型上,有天然的优势,但同时这套方法论的缺点也非常明显:
逻辑相对简单的业务和产品(比如一些小型公司的内部OA系统),用传统的MVC架构会更适合,构建也更快速。
非业务形态产品和应用并不适合,比如bigdata。这类应用和业务专注于数据层的交互和适配,并无强业务语义类诉求,而DDD最关键的一部分就是业务领域的抽象和包装,切记,它解决的是负责业务问题。
六 核心概念
DDD战略+战术全景图
DDD的核心理念有两部分,“战略设计,战术设计”,理解清楚了这两部分,其实DDD的精髓也就理解了。但是在这之前,先简单描述下DDD这套方法论的一个完整设计流程。
首先第一步,根据业务诉求,提炼出整体的业务流程,同时拆解出里面的关键事件,角色,参与者等核心实例。整个拆解和梳理的方法论,目前业界有一些比较成熟的,比如事件风暴,四色建模法等,后面单独讲。
提炼完整个业务流程后,进入战略设计阶段,这个阶段主要是从全局和顶层的视角,把整个业务语义转换为结构化分层。通过领域和子域的划分,同时结合通用域、支撑域、限界上下文等设计,分解问题复杂度,其实就是前面说到的“分而治之”的思想。
接下来就会到具体的战术设计阶段,通过前面的战略设计阶段,已经把整个领域、边界、上下文等关键模块都梳理完成,现在就是从各个域中再次拆解更细粒度的模块,去指导最终的编码实现,这些更细粒度的模块包括实体、聚合、聚合根等。
最后就到了编码实现阶段,DDD有一个关键价值,叫做“设计即实现”,所以在战术阶段的设计,理论上是可以直接作用于代码的分层结构,如果架构和战术阶段有出入,说明之前的设计有问题,可以复盘重新推演。
以上就是最基本的一个的设计流程,要完整的理解这个流程,“战略设计,战术设计”两个阶段尤其关键,接下来先说明战略设计(战略方法论)的核心概念。同时整体的战略和战术设计,光描述有点抽象,我提炼了下整个DDD的分层架构,只保留了最核心的部分,后面理解完了整个理论知识和部分实战后,可以回来再看这张图,会更有体感。
战略方法论
领域
领域(Domain)是指业务问题的特定领域范围,它涉及到特定业务的规则、概念、业务流程等。领域是对业务问题进行分解和组织的基本单位。
子域
子域(Subdomain)是指在一个大的领域中划分出的相对独立的子领域,它通常代表一个独立的业务领域,具有特定的业务逻辑和功能需求。子域可以是整个系统的一个功能模块,也可以是一个独立的业务流程。
通用域
通用域(Generic Domain)是指与特定业务领域无关的通用功能,它是在整个领域中被多个子域所共享和复用的功能。通用域包括一些通用的服务、工具、组件等,用于支持多个子域的实现。
支撑域
“支撑域”(Supporting Domain)指的是与核心业务的实现和发展密切相关的非业务功能。这些支撑域可以包括安全认证、用户管理、日志记录等在整个系统中被多个子域所共享和使用的基础设施功能。支撑域和通用域概念上有些类似,区分他们的标准简单归纳下的话,支撑域是由外域提供的能力,通用域是本域提供。
限界上下文
“限界上下文”(Bounded Context)则是DDD中的一个重要概念,用于划分和隔离不同的领域或子系统。一个限界上下文指的是一个明确定义了特定业务领域所围绕的边界,它包含了领域模型、业务规则、相关的领域服务和持久化逻辑等。不同的限界上下文之间可以是相互隔离的,每个上下文内部有其自己的语言和模型,但是它们之间也需要通过明确定义的接口进行通信。
小结
在DDD战略设计中,首先需要进行领域建模,即通过与领域专家的合作和深入领域知识的研究,将业务需求转化为领域模型。接下来,根据领域模型进行软件设计和开发,实现业务逻辑和功能。在整个过程中,需要保持与业务专家的紧密合作,不断迭代和验证领域模型的准确性和有效性。下图是体验VOC产品在做设计时的战略架构:
某体验产品的整体战略设计
战术方法论
实体
代表领域中具有唯一身份和生命周期的对象。实体有自己的行为和状态,并通过标识属性进行唯一标识。
贫血模型:贫血模型是指领域对象只具有数据属性,缺乏相关的行为逻辑。在贫血模型中,业务逻辑主要存在于服务层或者其它外部对象中,领域对象仅被视为被动的数据容器。这种模型在领域驱动设计(DDD)中被认为是反模式,因为它无法更好地体现领域的核心概念和规则。
失血模型:和贫血模型相似,指的是领域对象缺少业务逻辑和领域行为,以至于数据和行为的重要部分都被丢失。这种模型经常出现在面向对象的开发中,尤其是基于关系数据库的实现中。
充血模型:充血模型是在领域对象中充分体现了业务逻辑和行为的模型。充血模型积极地包含了数据和相关的行为逻辑,它使得领域对象能够更好地封装与之相关的业务规则和行为,提供了更加一致和抽象的编程接口。充血模型是DDD中推崇的设计模式,使得领域对象能够成为业务规则的中心。
涨血模型:涨血模型是指在充血模型的基础上,进一步将领域对象的状态和行为扩展到前沿技术和新的设计模式中(有些理念力,涨血模型和充血模型的区别在于,涨血模型添加了持久层的行为)。
充血模型虽然是DDD中推崇的设计模式,通过领域实体,一些关键行为和逻辑其实也能一起拿到了,但是在我的经验中,我更喜欢使用贫血+充血的混合模型(或者叫充血模型的简化版),因为这里涉及到一个标准的建立问题,如果只用充血模型的话,哪些行为和逻辑该下方到接口服务层,哪些又该收拢到实体中,这里面每个人的理念不一样。而我的标准是,涉及到持久层和复杂行为都下放到服务层,简单行为放到实体模型中。这样有个好处,随着业务的发展,如果只用充血模型,你的实体会越来越臃肿;如果只有贫血模型,自身又太单薄。所以一部分行为下放到服务层,我可以更细粒度的拆分服务接口,保证更优良的边界和代码可读性,同时也保证了模型自身的健壮性。
最后,不论哪种模型,都没有绝对的好坏,能够很好的定义出设计标准,同时基于自己的理解设计出符合业务扩展的实体和服务就是好的模型。
值对象
代表领域中没有唯一标识的对象,它的相等性是通过值的相等性来判断的,而不是通过标识。比如地址信息,手机号码,标签属性等。
聚合根
聚合根是聚合的根实体,它是一组相关对象的入口点,管理着聚合内其他对象的生命周期和完整性。聚合根通过封装聚合内部的对象,并定义了聚合的一致性边界,确保聚合内的对象之间的关系和约束得到维护。外部对象只能通过聚合根来访问和操作聚合内的对象,从而保证了聚合的完整性和一致性。
聚合
一组相关对象的集合,由一个根实体(Aggregate Root)作为集合的入口点。聚合定义了一致性边界,通过聚合根管理其内部对象的生命周期和完整性。
领域服务
代表领域中的一些操作或业务逻辑,它不属于特定的实体或值对象,而是为解决特定领域问题提供通用的服务。
领域事件
代表领域中的发生的重要事件,可以用于通知其他领域对象或跨限界上下文进行解耦和协作。
资源库
资源库是用于管理领域对象的创建、更新和持久化的接口。它实现了将领域对象从内存中存储到持久化介质(如数据库)中,以及从持久化介质中检索对象并还原为领域对象的功能。资源库隐藏了底层的数据访问细节,提供了一致的接口和抽象,使得领域对象的访问和持久化变得简单和统一。
小结
DDD战术设计是在DDD战略设计的基础上,着重于解决如何将业务需求和设计模型有效地映射和实现的具体方法和技术。它的目标是根据战略设计的指导,通过合理的领域建模和架构设计,将领域问题转化为高内聚、低耦合的代码实现,从而更好地满足业务需求。
某体验产品协同域的战术设计
七 领域建模
到这里,DDD的核心概念基本已经讲述完。基于以上的核心概念,接下来就是DDD最关键的部分——领域建模,它的目的归纳起来就一句话:提炼业务知识,形成统一语言,沉淀领域模型。
领域建模的优秀与否,可以说直接决定着本次设计的成败,因为一旦发生建模边界不清晰,实体划分错乱,核心属性没有遵守开闭原则等问题,虽然当下可以正常交付业务,但是对于整个项目的后续发展可以说是灾难性的(之前接触过一个系统,因为一个实体的关键属性在最初设计时,没有制定标准规范,语义不统一,造成使用混乱。最后不得以重新设计,结果造成上游的业务使用方全要配合改造回归,不仅改造成本巨大,同时引发了P级故障)。
我最开始说的“优秀的领域专家也是半个业务专家”,其实就体现在这一环节,好的领域建模,前提一定是深刻理解完业务的,同时再次强调下这个观点:领域建模,是基于现实,但不完全等价于现实。
以下是领域建模的交付物:
领域模型:包含领域对象、属性、关系、行为、边界范围等各个方面,用于描述业务的本质,这也是最重要的产出物。
用例图:用于明确系统的功能。
数据模型:描述系统的数据结构和关系,包括实体关系模型、关系数据库模型等。
状态图:用于描述系统各个状态及其转移条件。
活动图:用于描述系统流程中的各个活动及其关系。
序列图:描述系统中各个对象之间的交互过程和消息传递序列。
架构模型:包含系统的物理和逻辑结构,包括组件、模块、接口等。
事件风暴建模
事件风暴(Event Storming)是一种用于快速探索、理解和设计领域模型的合作工作坊技术。它是由Alberto Brandolini于2013年提出的。
事件风暴通过团队协作的方式,以用户的视角来讨论和探索整个业务流程。参与者将自己的理解和知识通过贴在墙上的便利贴上表达出来,核心会围绕着事件去编排整个业务流程。事件可以是任何对业务、系统或用户有意义的事情,包括用户触发的操作、系统的状态转换、通信和消息传递等。这些事件以一种自顶向下的方式,以时间线的形式贴在墙上。随着讨论的深入,团队可以探索和辨识出各种概念、实体、聚合根、资源库、上下文边界、业务流程和事件的关联关系。这有助于更全面地理解整个领域的复杂性,并为后续的领域建模和业务流程设计提供线索和洞察。
事件风暴具有高度可视化的特点,能够促进团队之间的沟通和共享知识。它也可以帮助团队快速理解现有系统的复杂性,并为系统的重构和演进提供指导。此外,事件风暴还可以用作需求分析、业务流程优化和团队协作的工具。
需要注意的是,事件风暴并非一种正式的建模方法,而是一种协作工作坊技术。它可以结合其他建模方法(如领域驱动设计)和工具(如UML、流程图等)来进一步详细和完善领域模型。
在事件风暴中,没有确定的固定语法,但是有一些常用的技术和简写符号,用于记录和表示不同的业务事件和概念。
以下是一些常见的事件风暴语法和符号:
用户角色:通常使用人物标签或者角色名字来代表具体的用户,例如 “客户”、“管理员”等。
业务事件:使用动词来描述业务活动或事件,如“创建订单”、“审核申请”、“发货”等。
识别的领域概念:在事件风暴中,通过写在有色便利贴上来标记关键的业务概念,例如“订单”、“产品”、“支付”等。这些概念有助于团队识别和理解业务的重要方面。
粘贴便利贴:使用不同颜色的便利贴来表示不同的类型或者关注点。例如,可以使用黄色便利贴表示业务活动和概念,使用蓝色便利贴表示抽象的过程和规则,使用粉色便利贴表示意见、问题或待解决的事项。
关系箭头:可以使用箭头来表示业务事件之间的关系,例如表示事件的先后顺序、依赖关系等。
事件风暴的语法并不是严格规定的,而且可以根据团队的需要和偏好进行适当的调整。重点是通过快速的头脑风暴,来协作识别和探索业务领域的关键事件,以促进团队的共享理解和协作。
事件风暴的本质上是通过脑暴的方式,围绕关键领域事件串联整个业务场景的生命周期,通过发散去收集,通过收敛去提炼,要真正把这个方法用好,有两个关键点:
主持人的综合能力,尤其体系在最后的收敛上,是否能把如此多的脑暴信息,提炼成关键点。
事件风暴是一个比较“重”的方法,对于一些0-1建设的大型项目(1000人日以上)比较适合,一些中小型项目有些“过渡设计”。
这个方法大家了解下就行,我不展开讲,实战中不常用
四色建模
Peter Coad在他的书《Java Modeling In Color With UML》中,提出了一种与颜色相关的建模方法,被称为Color Modeling。这种方法使用颜色作为一种可视化技巧,用于在领域模型中表示不同的对象和概念。它的目的是通过使用颜色来帮助开发者更清晰地理解和传达模型的结构和关系。
四色建模的思想是通过使用不同的颜色来标识不同的概念和角色,以增加模型的可读性和可理解性。每种颜色都代表一个特定的责任或角色,通过这种方式可以更好地定义和呈现领域模型的各个组成部分,使得开发团队在理解和沟通模型时更加容易。
需要注意的是,四色建模并非DDD的核心概念或原则,它更多地是作为一种模型建立和可视化的辅助工具。DDD更关注于如何基于通用语言、领域模型和限界上下文等概念进行软件系统的设计与开发。
以下是四色模型的语法:
时标原型(Moment-Interval Archetype,也称业务关键时刻,简称MI):表示事物在某个时刻或某一段时间内发生的,如销售订单、收款记录等,使用浅红色表示。
PPT原型(Part-Place-Thing Archetype,人/事/物原型,简称PPT):表示参与扮演不同角色的人或事物,如商品、账户、店铺等,使用浅绿色表示。
角色原型(Role Archetype,简称ROLE):抽象了一种参与方式,由人或组织机构、地点或物品来承担,如客户、商家、财务组织等,使用浅黄色表示。
描述原型(Description Archetype,简称DESC):对上述颜色表示的内容进行解释,用于分类或者描述建模过程中产生的数据、事件或者活动,使用浅蓝色表示。
用一句话来概括四色原型就是:一个什么样的人或物品以某种角色在某个时刻或某段时间内参与某个活动。其中“什么样的”就是DESC,“人或物品”就是PPT,“角色”就是ROLE,而“某个时刻或某个时间段内的某个活动”就是MI。按照这个逻辑,整体流程如下:
建立时标原型:寻找需要追溯的事件,根据追溯事件寻找足迹。
建立PPT原型:丰富模型,寻找时标原型周围的人/事/物,使它可以更好地描述业务概念。
建立角色原型:进一步从中抽象出可以参与到不同流程中去的角色。
建立描述原型:把一些信息用描述对象补足。
八 建模实例
就结合刚说的四色建模来演示,否则光说还是不够有体感。我以目前负责的“某体验平台(简称VOC)”结合四色建模法来具体演示下。
梳理业务流程
首先描述下VOC的背景和目的,一句话:站在横向和全局的视角,快速发现用户在得物系产品使用过程中发生的体验问题,同时及时定位,解决该问题,最终提升用户体验。
以下是之前某大厂的体验中台的目标描述,和VOC类似。
为了能达成上述目标,我们究竟应该怎么做,或者说具备什么样的能力呢,总结下来其实是以下几点:
具备收集用户所有原始“声音”的能力,否则我们无法从全局的角度去分析这个事情,这里的原声渠道需要尽可能多的涵盖用户想表达诉求的入口,才能全面,比如在线咨询、热线咨询、工单、评价等。
有了声音之后,我们需要具备分析声音,同时通过声音提炼出具体问题的能力,让分析人员能够快速精准的判别用户的问题是什么。
同时平台也应该具备快速及时的前置发现问题的能力,把这些重要的、紧急的问题通知到关键人员手上,让他们第一时间知晓。
最后,不管是主动分析出问题,还是收到了重要的问题通知,都应该立即着手处理这些问题。同时因为这些问题涉及的业务,bu,归属都不尽相同,所以处理的方案和流程也应该体现不同,这也衍生出在协作处理过程中,链接的上下游平台应该会非常多,处理动作和内容会很丰富。
根据以上的分析思路,我们可以把整体的业务流程梳理出来,同时结合四色建模法,我们把除DESC的其他关键元素体现到流程里(为了便于理解,我画的是比较粗的流程,实际流程会比这个复杂):
体验VOC产品业务流程
从图中可以明显看出来,这个流程的关键四色要素:
时标原型:用户原声、原声问题明细、预警单等,表述某一时刻产生的关键事件,一般是运行态的实体。同时基于VOC的业务,我们分别划分了3个阶段:分析问题、定位问题、解决问题。同时结合上面的思考,最关键的几个时标原型分别是分析阶段的用户原声,定位阶段的预警单,解决阶段的协同单(按照战术方法论,这3个时标原因就是聚合根)。
PPT原型:数据渠道、分析视图、问题标签模板等,一般是配置态或维度相关实体。
角色原型:系统、运营管理员、分析师等,这块比较好理解,使用产品的角色(一般可以不把系统角色放进去,这里放上去是为了便于理解)。
有了这个基本的业务流程和关键要素后,接下来进入概念模型的设计阶段。
建模-概念模型
首先什么是概念模型,一句话总结:概念模型是一个高层次的抽象模型,独立于具体实现的领域模型,它关注业务领域的核心概念和关系,以及团队之间的共享理解。
一般我们做建模设计的时候,很多经验丰富的领域专家会略过这一环节,直接抵达领域模型的建模阶段。当然,这并无任何不妥,因为我们最终在做软件开发和编码的时候,必然是基于具体的领域模型去设计的,但是概念模型对于整体建模流程来说,任然非常重要,主要体现在以下几点:
概念模型因为是更高层次的抽象,所以只表述核心的概念和关系,不表述细节和完整实体,所以会更简单,清晰。
团队之间交流共享时,尤其是在和业务,产品同学交流时,他们往往不会太过关注细节,用概念模型来交流理解会更合适。
概念模型一般用在一级域的设计上,它必须要体现全局性,整体性。所以它是具备方向上的指导意义,我建议在新的一级域项目建设初期,一定要做概念模型的建模(像交易、商品、营销、体验、客服这些都属于一级域)。
回到主线,基于第一步我们梳理完的业务流程和四色要素,我们做下编排,围绕着上述3个关键时标原型为核心,结合其他几个要素和关系,即可得到体验VOC的完整概念模型。
某体验产品概念模型
建模-领域模型
在完成概念模型的设计后,终于到了我们最终的环节,也是建模流程里最重要的阶段——领域建模。具体的领域模型是在概念模型的基础上进行具体的实现,除了表述清楚核心概念和关系外,还需要能够表达非核心的实体关系的能力,同时它还是指导技术实现的标准。基本上完成这个阶段后,微服务拆分、代码架构的设计、模块划分、核心流程也就确定了。
我们做领域建模时,一般会按照一级子域做拆分,一般一级子域代表了一个完整的业务域,独立解决一类业务问题。参考“体验VOC产品的整体战略设计”部分,我们划分的是洞察子域,协同子域,预警子域和问题子域,所以理论上会拆分4个微服务应用,同时各自去做自己子域的领域建模。下面我例举其中的协同子域来做演示。
整体的建模思路如下:
第一步:定义解决标准。首先,协同域的目标是高效的助力业务解决问题,那边这里就涉及到如何解决,用什么样的方案解决,解决的流程是怎么样的,谁来解决。首先要确定这个解决标准,我们抽象为“协同方案”,他的核心就是制定解决标准,包括我刚描述的那一系列要解决的问题
第二步,根据解决标准定义执行标准。有了解决标准后,具体如何解决,这个时候我们就需要有个根据解决标准(协同方案)履约的载体,他会按照方案上制定的流程,处理人,解决方式等去流转,这个载体我们抽象为“协同单”
第三步,围绕着上述两个标准,去完善域边界,实体关键属性,周边实体和关系网。比如,协同方案里的流程,我们是希望抽象成独立模版做复用性,还是一个方案就代表了一个流程(协同流程)?协同单履约当中的所有记录是否需要留痕和外化,那是否需要提炼一个服务记录的概念(协同记录)?流转里的内容呈现是否需要单独抽出来,做成业务可自定义配置化(表单模版)?协同方案和协同单应该是怎么样的关系?等等这所有的业务逻辑,都需要反映到领域模型中表达出来。
最终以上三步完成后,整个协同域的领域模型也就基本确认好了。因为协同域不复杂,领域模型结合实际做了简化,所以就没有表示核心的领域服务,限界上下文等概念。具体呈现如下:
九 总结
对于领域驱动设计来说,应该遵循一个道理:不拘于形式(有点类似电影里的,剑客最高的境界是身边无剑,但是任何所见皆可为剑的感觉)。文章的前面部分,我讲了许多的概念:聚合根、值对象、领域事件、限界上下文等,但是实际设计开发过程中,并不需要照搬全套的体现出来,只要能够表达清楚核心的实体和关系、清晰的边界和合理的扩展性即是好的领域设计。当然这篇文章主要是理论部分,实战部分我还是想先把战术设计的全貌先展现一遍,最终再做精简,这样可以既知全貌,却不教条。
同时我再强调下,合格的技术专家一定是半个业务专家,而DDD这套方法论,可以让技术同学很好的去全局理解业务形态,同时以结构化的思维去抽象业务概念,既能提升全局的认知高度和架构能力,也能加强细节把控力,所以它是一套很好的软件设计复杂性解决之道。
最后回到最初那个问题,一个FBI(数据看板系统),一个电商交易系统,它们都适合用DDD吗,为什么?