与系统架构设计相关的有两种角色
业务架构驱动技术架构,而不是技术架构驱动业务架构。
以下问题,如果前两个为"是",则系统本身并不具备复杂的业务逻辑。否则可使用领域驱动设计。
在领域驱动设计中,有两个主要的设计维度
设计的策略维度关注如何设计领域模型及对领域模型的划分,其目的在于清楚划分不同的系统与业务关注点。策略维度是一个面向业务、具备较高层次的的设计维度,偏重于业务架构的梳理及考虑如何把业务架构和技术架构相结合的问题。
设计的技术维度关注技术实现,从技术的层面指导我们如何具体地实施领域驱动,关注基于技术设计工具按照领域模型开发软件。
也称为统一协作语言,思路是面向领域和业务,统一团队成员对领域知识的一致认识,促进后续代码模型中的命名等使用领域词汇而不是技术词汇。
如图,系统从简单到复杂,以至于不可维护,就需要重构拆分,这便是架构的轮回:
概念
子域存在于界限上下文中。这里的界限指的是每个模型概念、属性和操作,在特定边界之内具有特定的含义。这些含义只限于该界限之内。
示例
整合子域与界限上下文的示例结构如图
说明:
该图根据业务功能的特性把整个系统拆分成4个主要的子域,分别包含一个核心子域、两个支撑性子域及一个通用子域。每个子域都有其界限上下文,各个界限上下文之间可以根据需要有效整合从而构成完整的领域。
违背了业务架构驱动技术架构的原则,在对业务梳理尚不完善、系统的策略设计尚不健全的情况下就考虑技术架构和实现方法,往往会导致返工,在不断的系统修改中腐化架构。
一种跨职能(Cross Function)的团队构建方式,团队中包括服务端、前端等各种角色。
虽然大泥球是一个反设计、具有讽刺意味的词语,但仍然是最常见的软件设计表现形式。
系统集成模式的基本思路在解耦和统一。因此抽象出两种基本的集成模式:
防腐层强调下游上下文根据领域模型创建单独一层。该层完成与上游上下文之间的交互,从而隔离业务逻辑,实现解耦。
统一协议则是提供一致的协议定义,促使其他上下文通过协议访问。
比如,数据相关操作对于领域模型而言只是持久化的一种抽象,不应该关联具体的实现方式,这些数据访问的实现可以统一放在基础设施组件中,也就是说基础设施组件实现了领域组件中的抽象接口。
我们可以通过上移、下移、回调等手段打破循环依赖。
认为被依赖者应该比依赖者更稳定,也就是说如果包B还不如包A稳定的话,就不应该让包A依赖包B。
稳定抽象原则(Stable Abstractions Principle,SAP)
依赖倒置原则(Dependency Inversion Principle DIP)
领域组件
应是抽象且稳定的,也就是说它应该位于系统分层的底端被其他组件所依赖。
用户接口组件
通常是最不稳定的,应处于系统的顶层
应用组件
处于用户接口组件和领域层之间
基础设施组件
事件驱动作为一种典型的架构风格同样包含在领域驱动设计过程中,并应用于上下文集成的解耦。
上图说明:
领域事件由事件源生成,并通过事件发布器进行发布,各种事件的订阅方根据需要进行订阅。订阅方根据自身需求可以直接处理该事件,自身不能处理可以即时转发给其他订阅方,事件作为一种业务数据的载体,也可以进行存储以便后续处理。
当我们面对有限的系统需求信息,基本思路是根据以下问题找到合适的答案。
找到系统的核心域,并根据核心域的定位和作用梳理其通用语言。核心域的通用语言包括该子域的名称及基本需求约束。
有了核心域,下一步就是判断系统是否只要一个核心域就能满足建模需求。如果不是,那就要判断是否需要相应的支撑子域和通用子域。支撑子域和通用子域不一定都需要,但有时候系统也会存在多个支撑子域或通用子域。
系统的交互和集成以核心域为主体展开。当核心域面对支撑子域或通用子域时,使用的协作和集成策略往往是不一样的。这方面需要根据具体的子域进行分析和设计。
子域的关系图
子域的交互时序图
案例的架构风格基本可以沿用通用的领域驱动架构风格,平面形架构和事件驱动架构构成了案例系统架构设计的基本组成。对于三大子域之间的界限上下文,我们可以抽象出一批端点和适配器。对于每种界限类型,都有一套端口和适配器与之相对应,确保内部领域模型不会泄露到外部系统。而具体使用基于HTTP的RESTful亦或消息传递系统等方式进行各个界限上下文之间的集成实现,我们将在面向领域的技术设计中具体展开讨论。