软件架构模式大体上经历了从单机架构 -> 集中式架构 -> 分布式微服务三个阶段的架构演进。
在单机和集中式架构模式下,软件无法快速响应需求和业务的迅速变化,直到微服务架构时代的来临。微服务架构解决了单机和集中式架构的很多问题,比如扩展性、弹性伸缩性、小规模团队的敏捷开发等。
但是,带来好处的同时,微服务实践过程中也产生了不少争议性的问题:“微服务到底应该怎么拆分和设计才算合理,拆多小才叫微服务”,而微服务的边界历来也是最容易产生争议的地方。
2004年埃里克·埃文斯发表了《领域驱动设计》这本书,DDD(Domain Driven Design)由此诞生。
DDD核心思想是通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模式和系统架构模式的一致性。
DDD不是架构,而是一种架构设计方法论,它通过边界划分将复杂的业务领域简单化,从而设计出清晰的领域和应用边界,进而可以非常容易地实现架构演进。
DDD主要包括战略设计和战术设计两大部分。
DDD 战略设计主要从业务视角出发,建立业务领域模型,领域模型可以用于指导微服务的设计和拆分。事件风暴是建立领域模型的主要方法,它是一个从发散到收敛的过程。
什么是事件风暴?
事件风暴是一种协作的过程,通常采用用例分析、业务场景分析和用户旅程分析等,尽可能全面不遗漏地分解业务领域,并梳理领域对象之间的关系,这是一个发散的过程。事件风暴过程会产生很多实体、命令、事件等领域对象,通过将这些领域对象从不同维度进行聚类(将数据集中的对象或数据点按照某种相似性或相关性的标准分成不同的组别,即“簇”。聚类的目标是将相似的数据点分到同一簇中,使得同一簇内的数据点之间更加相似,而不同簇之间的数据点相对较不相似。),形成聚合、聚合根、限界上下文等边界,建立领域模型,这是一个收敛的过程。
事件风暴可以帮助开发团队、业务团队共同理解和共享对业务领域的见解,有助于捕获关键的业务事件(领域事件)、过程和概念,以指导软件系统的设计和实施,从而更好地支撑业务需求落地。此外,事件风暴有助于提高团队的沟通、协助和业务理解能力。
在战略设计中建立了领域模型,划定了业务领域的边界,并建立了通用语言和限界上下文,确定了领域模型中各个领域对象的关系,如上图所示。
当领域模型的设计工作完成后,基本也就确定了应用端的微服务边界。在从领域模型向微服务架构设计落地的过程中,也就是从战略设计向战术设计的实施过程中,开发人员会将领域模型中的领域对象(聚合、聚合根、实体、值对象等)与代码模型中的对象建立映射关系(可以通过表格进行罗列记录),将业务架构和系统架构进行绑定。
战术设计则从技术视角出发,侧重于领域模型的技术实现,完成软件开发和落地,包括:聚合根、实体、值对象、领域服务、应用服务和资源库等代码逻辑的设计和实现。
经验:
可通过 Excel 表格记录、罗列战术设计中的聚合根、实体、值对象等关系、属性
DDD 的知识体系提出了很多的名词,像:领域、子域、核心域、通用域、支撑域、通用语言、限界上下文、聚合、聚合根、实体、值对象等等,非常多,下面一一进行解释。
领域,指的是一个特定业务领域或问题领域,它通常涉及一组相关的业务规则、概念和数据。领域可以进一步划分为子领域,我们把划分出来的多个子领域称为子域,每个子域对应一个更小的问题域或更小的业务范围。
在领域不断划分的过程中,领域会细分为不同的子域,子域可以根据自身重要性和功能属性划分为三类子域,它们分别是:核心域、通用域和支撑域。
在事件风暴的过程中,领域专家、业务人员、开发人员会一起建立领域模型,在领域建模的过程中会形成通用的业务术语和用户故事,进而形成能够简单、清晰、准确描述业务含义和规则的通用语言。通用语言可以解决交流障碍问题,使得领域专家、业务人员和开发人员能够更加高效的协同合作,进而确保业务需求的正确表达与落地。
通用语言贯穿 DDD 的整个设计过程(事件风暴 -> 领域故事分析 -> 提取领域对象 -> 领域对象与代码模型映射 -> 代码落地),基于通用语言,可以设计出可读性更好的代码,将业务需求准确转化为代码设计。
任何语言都存在语义环境的,在不同的时空和背景下,同一句话会存在不同的含义,比如语言:“衣服能穿多少就穿多少。”,在夏天表就是要穿少一点儿,冬天却表示需要穿的很多。所以DDD的通用语言也存在它的语义环境,为了避免同样的概念或语义在不同的环境中产生企业,DDD提出了 限界上下文 用来确定语义所在的领域边界。限界上下文可以通过将其拆分为限界、上下文来进行理解。
限界上下文是用来封装通用语言和领域对象,提供上下文环境,保证在领域内的一些术语、业务相关对象等有一个唯一的含义。例如,在电商领域中,商品在不同阶段存在不同的含义,在销售、售卖时是商品,在打包运输时则为货物,所以在销售领域和运输领域之间,存在限界上下文,如下:
限界上下文是微服务设计和拆分的主要依据,它确定了微服务的设计和拆分方向,在事件风暴中,领域专家、架构师和开发人员的主要工作就是划分限界上下文。理论上,可以将一个限界上下文设计为一个微服务,当然还需根据其他限制因素考虑,防止过度拆分。
实体和值对象都是用来表示领域模型中的事物或概念的重要元素。它们有不同的特性和用途。实体和值对象是组成领域模型的基础单元。
实体一般对应业务对象,它具有业务属性和业务行为。而值对象主要是多个相关属性集合,对实体的状态和特征进行描述。例如人员实体原本包括:姓名、身份证号、性别、年龄以及所在省、市、县和街道等属性。我们可以将 “省、市、县和街道等属性” 抽离出来,构建一个地址属性集合,这个集合对象就是值对象。如下:
一个实体可以存在多个值对象。
由业务和逻辑紧密关联的实体和值对象组合而成的对象称为聚合。聚合都存在一个聚合根和上下文边界。聚合是数据修改和持久化的基本单位。
如何设计聚合???
DDD 领域建模通常采用事件风暴,通过用例分析、场景分析和用户旅程分析等方法,列出所有可能的业务行为和事件,然后找出产生这些行为的领域对象,并梳理领域对象之间的关系,找出聚合根,找出与聚合根业务紧密关联的实体和值对象,再将聚合根、实体和值对象组合,构建聚合。
下面我们以大家都熟悉的学校选课业务场景为例,看一下聚合的构建过程主要包括哪些步骤。
第一步:采用事件风暴,通过用例分析、场景分析和用户旅程分析等方法,如下,梳理出在选课过程中发生这些行为的所有的实体和值对象,比如课程、老师、学生、选课规则、上课时间等等。
第二步:从众多实体中选出适合作为对象管理者的根实体,既聚合根。
如何判断一个实体是否为聚合根:可以通过是否有独立的生命周期?是否有全局唯一ID? 是否可以创建或修改其它对象?是否有专门的模块来管这个实体。图中的聚合根分别是课程和用户实体。
第三步:根据业务单一职责和高内聚原则,找出与聚合根关联的所有紧密依赖的实体和值对象。构建出1个包含聚合根(唯一)、多个实体和值对象的对象聚合,在图中我们构建了课程和用户这两个聚合。
第四步:在聚合内根据聚合根、实体和值对象的依赖关系,画出对象的引用和依赖模型。
第五步:多个聚合根据业务语义和上下文一起划分到同一个限界上下文内。
聚合的设计原则:
这些原则有助于创建具有高内聚性、低耦合性和良好一致性的聚合,从而更好地管理领域中的复杂性。在DDD中,良好的聚合设计有助于将复杂的领域问题划分为更容易管理和理解的单元。
事件风暴是一种协作的过程,通常采用用例分析、业务场景分析和用户旅程分析等,尽可能全面不遗漏地分解业务领域,并梳理领域对象之间的关系,这是一个发散的过程。事件风暴过程会产生很多实体、命令、事件等领域对象,通过将这些领域对象从不同维度进行聚类(将数据集中的对象或数据点按照某种相似性或相关性的标准分成不同的组别,即“簇”。聚类的目标是将相似的数据点分到同一簇中,使得同一簇内的数据点之间更加相似,而不同簇之间的数据点相对较不相似。),形成聚合、聚合根、上下文边界、限界上下文等边界,建立领域模型,这是一个收敛的过程。
事件风暴可以帮助开发团队、业务团队共同理解和共享对业务领域的见解,有助于捕获关键的业务事件(领域事件)、过程和概念,以指导软件系统的设计和实施,从而更好地支撑业务需求落地。此外,事件风暴有助于提高团队的沟通、协助和业务理解能力。事件风暴的过程可以大概分为以下几步:
事件风暴是一种非常有用的工具,用于在项目的早期阶段构建共享理解和对业务领域进行深入挖掘。它有助于软件团队更好地满足业务需求,确保领域知识的一致性,并提高团队协作的效率。
在进行事件风暴时,除了命令和操作等业务行为以外,还有一种非常重要的事件,这种事件发生后通常会导致进一步的业务操作,例如:当老师做完课程信息上传时,需在某一个时间后通知学生进行选课,在 DDD 中这种事件被称为领域事件。
领域事件是领域模型中非常重要的一部分,用来表示领域中发生的事件。一个领域事件将导致进一步的业务操作,在实现业务解耦的同时,还有助于形成完整的业务闭环。领域事件也是微服务解耦的关键。
如何识别领域事件呢?
在做用例分析、业务场景分析和用户旅程分析时,我们要捕捉业务、需求人员或领域专家口中的关键词:“如果发生……,则……”、“当做完……的时候,请通知……”、“发生……时,则……”等。在这些场景中,如果发生某种事件后,会触发进一步的操作,那么这个事件很可能就是领域事件。
领域事件有的发生在微服务内,有的发生在微服务之间,还有两者皆有的场景,一般跨微服务的领域事件大多会用到消息中间件,实现跨微服务的事件发布/订阅。消息中间件的产品非常成熟,市场上可选的技术也非常多,比如RabbitMQ、Kafka、RocketMQ等。
DDD 是一种架构设计方法,微服务是一种架构风格,两者都强调从业务出发,其核心要义是强调根据业务发展,合理划分领域边界,持续调整现有架构,优化现有代码,以保持架构和代码的生命力,也就是我们常说的演进式架构。
DDD 强调领域模型和微服务设计的一体性,先有领域模型然后才有微服务,而不是脱离领域模型来谈微服务设计。首先通过DDD战略设计,建立领域模型,划分微服务边界,每个边界都由一个或多个领域模型或聚合组成。然后通过战术设计,将领域模型转化为微服务设计,并进行落地。
DDD 包括战略设计和战术设计两部分。
战略设计:战略设计主要从业务视角出发,建立业务领域模型,划分领域边界,建立通用语言的限界上下文,限界上下文可以作为微服务设计的参考边界。 战略设计通过事件风暴,通常采用用例分析、业务场景分析和用户旅程分析等,找出领域对象和聚合根,对实体和值对象进行聚类组成聚合,划分限界上下文,建立领域模型的过程。
战术设计:战术设计侧重于从技术视角出发,根据领域模型进行微服务设计。这个阶段主要梳理微服务内的领域对象, 梳理领域对象之间的关系,确定它们在代码模型和分层架构中的位置,建立领域模型与微服务模型的映射关系,以及服务之间的依赖关系,进而完成软件开发和落地,主要包括:聚合根、实体、值对象、领域服务、应用服务和资源库等代码逻辑的设计和实现。
“中台” 是一种在软件和业务领域中经常使用的概念,它涉及到软件系统和业务流程的架构和设计。
中台的核心思想是将系统或业务流程中的共享资源、功能和服务抽象成一个中间层,以便多个应用程序或模块可以共享和重用这些资源。这种架构方法有助于提高系统的效率、可维护性和可扩展性,同时减少了冗余工作和开发成本。
中台的设计思想与“高内聚、低耦合”的设计原则是高度一致的。高内聚是把相关的业务行为聚集在一起,把不相关的行为放在其它地方,按照“高内聚、松耦合”的原则,实现企业级的能力复用。
中台的目标是通过资源共享、业务模块化、标准化接口和降低复杂度,使企业的IT系统更具弹性,更容易适应快速变化的业务需求。
将重复的需要共享的通用能力、核心能力沉淀到中台,将分离的业务能力重组为完整的业务板块,构建可复用的中台业务模型。中台业务建模有自顶向下和自底向上两种策略,这两种策略有自己的适用场景,你需要结合自己公司的情况选择合适的策略。
自顶向下策略是先做顶层设计,从最高领域逐级分解为中台,分别建立领域模型,根据业务属性分为通用中台或核心中台。领域建模过程主要基于业务现状,暂时不考虑系统现状。自顶向下的策略适用于全新的应用系统建设,或旧系统推倒重建的情况。
由于这种策略不必受限于现有系统,你可以用 DDD 领域逐级分解的领域建模方法。从下面这张图我们可以看出它的主要步骤:
自底向上种策略是基于业务和系统现状完成领域建模。首先分别完成系统所在业务域的领域建模;然后对齐业务域,找出具有同类或相似业务功能的领域模型,对比分析领域模型的差异,重组领域对象,重构领域模型。这个过程会沉淀公共和复用的业务能力,会将分散的业务模型整合。自底向上策略适用于遗留系统业务模型的演进式重构。
如何采用自底向 上的策略来构建中台业务模型,主要分为这样三个步骤。
第一步:锁定各个系统所在业务域,构建领域模型。
锁定各个系统所在的业务域,采用事件风暴,找出领域对象,构建聚合,划分限界上下文,建立领域模型。那在构建中台业务模型时,需要重点关注那些存在业务能力重复的领域模型,将这些不同领域模型中重复的业务能力沉淀到中台业务模型中,将分散的领域模型整合到统一的中台业务模型中,对外提供统一的共享的中台服务。
第二步:对齐业务域,构建中台业务模型。
构建多业务域的中台业务模型的过程,就是找出同一业务域内所有同类业务的领域模型,对比分析域内领域模型和聚合的差异和共同点,打破原有的模型,完成新的中台业务模型重组或归并的过程。构建中台业务模型的要点总结成一句话就是:“分域建模型,找准基准域,划定上下文,聚合重归类。”
第三步:中台归类,根据领域模型设计微服务。
完成中台业务建模后,就可以通过其领域模型中看到总共需要构建了多少个中台,中台下面有哪些领域模型,哪些中台是通用中台,哪些中台是核心中台,中台的基本信息等等,都一目了然。最后就可以根据中台下的领域模型进行微服务的设计。
我认为,要想应用 DDD,首要任务就是要吃透 DDD 的核心设计思想,搞清楚 DDD、微服务和中台之间的关系。中台本质是业务模型,微服务是业务模型的具体实现,DDD 是一种设计思想,它可以同时指导中台业务建模和微服务设计,它们之间就是这样的一个铁三角关系。DDD 强调领域模型和微服务设计的一体性,先有领域模型然后才有微服务,而不是脱离领域模型来谈微服务设计。DDD主要包括战略设计和战术设计两大部分。战略设计用于定义领域模型,确定业务边界,这对于中台和微服务的构建至关重要。在战术设计阶段,你需要将领域模型映射到微服务设计中,并严格遵循DDD原则,确保微服务与领域模型保持一致性。
拥有一套清晰的微服务设计和拆分方法是确保微服务架构的成功的关键。这种方法可以帮助你建立清晰的微服务边界,确保微服务系统的可维护性和可持续演进。
最终,DDD、中台和微服务的结合可以为企业提供高度灵活性和创新性,帮助他们更好地应对不断变化的市场需求。这种铁三角关系可以帮助企业建立坚实的技术基础,实现持续增长和竞争优势。