4.2 应用架构元模型
应用
4.2.1 平台化
趋势对应用架构
提出的新挑战
平台化
趋势意味着企业 IT 系统的形态逐渐从扁平结构转向分层结构,即一部分应用
提供可复用的能力
,组成底部的平台
,而其他应用
建立在平台
之上。
除了能力
复用外,另一个提升 IT 支撑响应力的关键是,提升 IT 系统各组成部分的自治性,使得变更能够相对独立的、以小步快跑的方式发生。因为无论是创新也好,集中管控也好,虽然变化速率不同,但变化始终存在,既然变化不可避免,我们应将精力投入到应对变化上。
在我们的经验中,应用
边界划分不合理会对应对变化产生明显的负面作用:
粒度过大 | 粒度过细 |
---|---|
功能 维度 |
多个团队在同一个物理边界 内,变更计划和所需资源容易冲突,协作复杂 变更实现难度高,质量保障困难或耗时 * 若一个变更常常散布在多个物理边界 内,集成、测试、部署负担重、耗时,且常常伴随着高成本的跨团队沟通协调 |
运行 维度 |
受限于物理边界 ,无法将故障隔离在局部区域,因故障级联影响业务支撑 受限于物理边界 ,无法按需调整应用的容量,造成资源浪费 基础设施升级、变更工作量大,或对团队自动化运维能力要求高 平添大量网络通信的开销,反而降低整体性能 |
这些负面作用会拖慢 IT 支撑的响应力或稳定性,因此,“如何划分 IT 系统的边界,以合理的布局更好地应对变化”是需要解决的挑战。在平台化
趋势之前就已经开始流行的微服务架构
风格的催化下,这个挑战就已凸显,而平台化
强调可复用的服务
,必然会对原有系统进行打散和重组,进一步加剧了这个挑战。
4.2.2 如何划分 IT 系统的边界,以合理的布局更好地应对变化
从上文的分析可以看出,边界划分其实从应用架构
视角出发,对功能
、运行
层面变化的应对设计,是应用架构
设计的重要部分。我们在进行应用架构
设计的过程中,融合了领域驱动设计
中的限界上下文
与统一语言
的概念,延续业务架构
部分中对于领域对象
的识别和子域
划分,结合组织与技术的要素,从多个方面充分考量对于应用
的建模。
限界上下文
(Boundary Context):是业务上下文
的边界,在该边界内,当我们去交流某个业务概念时,不会产生理解和认知上的歧义(二义性),限界上下文
是统一语言
的重要保证。统一语言
(Ubiquitous Language):是 Eric Evans在《领域驱动设计 - 处理软件核心中的复杂性》中使用的术语,用于构建由团队,开发人员,领域专家和其他参与者共享的语言,也称为"无处不在的语言"、"通用语言"、"泛在语言"。统一语言
是在限界上下文
中建模的,在其中标识表达了业务领域的术语和概念,并且不应该有歧义。
带着对于业务上下文
边界的理解,使用业务、技术都能理解的统一语言
,以两大阶段实现边界划分:
- 从
功能需求
层面出发,按“单一职责”原则划分逻辑边界
- 加入
非功能需求
,按架构
质量属性调整逻辑边界
并划分物理边界
这个设计过程可通过元模型
提供的应用层
、应用组
、应用
、应用组件
进行不同层次的边界划分建模。
4.2.2.1 应用组
建模
应用组
是一种大比例结构的逻辑边界
划分结构,其主要作用是:
应用组
作为一种粗粒度的划分,帮助我们快速找到进一步划分的切入点- 在
微服务
化的大背景下,物理边界
逐步碎片化,我们在与利益干系人
对话时,需要一个能够代表一组相关物理边界
的结构,以避免不必要的细节干扰
在结构上,应用组
包含了多个应用
(物理边界
)。应用组
常常对应到数字化产品
级别,例如 CRM 系统(客户关系管理系统,其下可能包括客户档案管理应用
、客户忠诚度管理应用
);在业界流行的按中心
划分的中台
/ 平台
架构
里,应用组
常常对应到某个中心
。
应用组
的建模依据主要来自于业务架构
的业务
、组织
两部分成果的输入。在从 0 到 1 的应用架构
设计场景里,这个步骤不求精确,主要是帮助我们建立划分的起点。例如:
汽车行业的经销商,会同时开展新车销售和售后服务两个不同的
业务
,在经销商内部一般也由不同的组织
负责。而维修保养和配件销售又是售后
服务
中的两个不同业务场景
。我们可依此快速建立一个两级的
应用组
,这个结构并不精确,但足够我们进行下一步工作。
4.2.2.2 应用组件
建模
应用组件
是一种细粒度的应用
逻辑边界
划分结构,是对功能、数据的封装。
向上,一个或多个应用组件
可组成一个应用
(物理边界
),向下,就是代码实现层面的结构设计了。因此,应用组件
是架构
层面运用“单一职责”原则的最小单元。
按职责类型分解,应用组件
可分为四种常见的参考类型:
类型 | 功能 | 数据 | 例子 | 变化原因 |
---|---|---|---|---|
流转类 |
支撑某个流程 或流程 中的一段活动 |
流程 的状态流转信息和决策证据 |
结账组件,其支撑的流程 是结账流程,管理的数据是订单 |
流程 编排变化 |
规格类 |
支撑某个业务 规则,给出专业意见 |
一般不管理数据的生命周期,只负责加工给出结果 | 验证:如发票是否逾期 筛选:三月内消费过的客户 * 计算:计价、导航路线建议 | 业务 规则的计算逻辑变化 |
视图类 |
支撑某个业务活动 所需的整合信息 |
一般不管理数据的生命周期,只负责加工给出结果 | 商品信息的整合展示 统计报表 | 视图组装逻辑变化 |
配置类 |
为前三类提供配置输入 | 基础的资源信息 | 商品目录设置内容管理 系统中的配置功能规则的开关 | 前三类对配置要求的变化 |
一般来说,我们建议从流转类
的应用组件
开始识别,再延伸至规格类
、视图类
,最后再识别配置类
。建模依据主要来自于业务架构
的业务流程
、业务对象
、业务规则
。
其过程可总结为三个子步骤:
子步骤一:功能和数据识别
逐层分解业务流程
,从活动
、任务
、步骤
中可以得到相对细粒度的业务需求,即 IT 系统需要提供的功能;将业务对象转化为不同类型的数据对象。
子步骤二:功能与数据关联
识别应用组件
按不同组件类型将功能与数据对象关联对应,得出应用组件
。在流转类
组件建模时,有两个关注点需要特别注意:
一是隐式业务边界的识别。在对业务流程
分析时,地点、角色
变化时,我们面对的业务干系人
和他们的工作环境不同,其关注点可能不同,这往往会成为不同的变化原因。通过识别这类隐式的业务边界,这可以帮助我们细分数据对象和应用组件
,例如:
线上订餐流程中,客户提交订单并完成付款后,订单会被派单至厨房备餐。即使在
业务架构
的产出中没有识别出客户订单和厨房备餐单据可能是不同的业务对象,也可以从地点和角色
的变化将订餐结账、备餐识别为不同的应用组件
。
二是数据对象变更一致性约束的识别。在流转类
应用组件
的建模过程中,应该尽可能识别业务规则
中对于数据对象变更的一致性约束,以元模型
中的不变量
建模。不变量
代表了哪些数据对象需要被同时改变,我们可以依此复查,是否将应用组件
拆分得太细,破坏了事务边界。
子步骤三:识别、调整各应用组件
之间的依赖关系
识别各组件
间的依赖关系,在这里尽可能避免两种依赖:
一是尽可能避免依赖容易变化的组件
。尽管可以定义契约,但容易变化的组件
容易打破先前定义的契约。
二是尽可能避免出现双向依赖。双向依赖往往对可适配性产生负面影响,可通过引入第三个组件或扩展点
(详见应用服务
与扩展点
)解耦。
4.2.2.3 应用
建模
有了应用组件
作为“原料”,应用架构
的物理边界
设计就有了输入,下一步的目标是识别是否存在架构
质量属性冲突,作为应用
建模的重要参考,调整逻辑边界
,并确定物理边界
。质量属性冲突包括:
- 该边界内是否存在变更频率冲突
我们倾向于将高频变更的应用组件
与其他应用组件
阻隔开。物理边界
意味着部署的独立性,不容易产生发布计划、部署所需资源上的冲突。如果一个功能扩展带来的变更,集中在某个应用
、甚至应用组件
内,其协作成本相对更低。
- 该边界内是否有特别的移植性要求
该要求指应用
迁移到不同组织、业务运作方式的能力
,或者换一个角度来说是应用
承接新业务模式
的能力,这恰巧是平台
所需要的关键能力。在实现某一个业务模式
时,必然存在该业务模式
的特定需求和可以支持多个业务模式
的公共需求。我们倾向于将特定需求和公共需求的实现隔离到不同的应用组件
、甚至应用
里。以便新业务模式
入住时,方便实现功能扩展以及实现部署要求。
- 该边界内是否有特别的弹性要求
该要求指应用
是否容易通过调整容量来应对流量变化。在这里应用
的粒度决定了容量调整的难度和成本。因为应用
的粒度太大,而流量变化只影响其中某个应用组件
,则扩容带来了不必要的成本浪费。
( 图 4.2-3 通过扩展点
将双向依赖转换为单向依赖 )
另一种情况是某个应用组件
不能调整容量或者非常困难,这主要是因为其依赖于某个无法扩展的技术组件
。例如,某应用组件
依赖硬件加密设备(技术组件
)对报文进行加密,扩容意味着需要采买硬件加密设备。因此,需要将这类应用组件
隔离开,使其他组件
更容易应对弹性要求。
- 该边界内是否有特别的性能要求
该要求与弹性要求类似,将不同性能要求(请求处理的快慢程度)的应用组件
分开,特别是对于特定问题,可能适合某个技术栈,但出于整体建设、运维成本考虑并适合大面积使用,我们倾向于将其设计为一个独立的应用
,与其他应用组件
隔离开,使得异构。典型的例子是,部分高性能场景适合用 C语言实现。
- 该边界内是否有特别的可用性要求
该要求与弹性要求类似,将不同可用性要求的应用组件
分开,降低保障可用性要求的建设、运维成本。例如,如果某个应用组件
支撑的功能尚处在业务
探索阶段,那么可以适当降低其可用性要求,这要求将其与承担核心功能的应用组件
隔开。或是当故障发生时,能否将故障隔离在局部范围,减少应用
失效造成的业务损失。
- 该边界内是否有特别的信息安全要求
例如,某应用组件
需要保管信用卡持卡人信息,为降低该信息被非授权访问的风险,我们倾向于将该应用组件
与其他应用组件
拆开,将其独立部署在一个加固的运行环境中。
- 该边界内是否有特别的合规要求
有时边界划分会受到法律、法规或行业规定的影响。例如某业务是需要公证的抽奖活动,按照当地行业要求,中奖人抽取的实现需要通过公证处认证。我们倾向于由已通过认证的外部应用服务来提供该职责,或是将该职责独立划分为一个应用
,减少认证需要花费的时间。
基于以上冲突的进行逻辑边界
调整,将由特别要求的应用组件
独立划分到各自的物理边界
,剩余的应用组件
原则上保留在一个物理边界
,以元模型
中的“应用
”表述该划分结果。
4.2.2.4 应用层
建模
除了应用组
之外,常见的一种大比例结构是分层
,因此我们也将应用层
作为一种元素加入进来。
我们认为分层
代表了企业对变化速率的认知,并为不同的变化速率匹配架构
设计目标和管理方法。并不是所有的 IT 系统都需要“最高配”的架构
属性,实现成本也是重要的约束条件。一个处在业务探索期的信息系统,其生命周期一般只有 6-12 个月,且变化剧烈。为其达成过高的架构属性显然是不具备投资合理性的。
另一方面,平台化架构
中作为支撑层的 IT 系统在架构
属性上需要更多重视和投入。我们常常看到企业仅仅在全景图纸上做了分层
,但缺少架构
设计、治理中的实际举措,功能上的变更往往会击穿多层,支撑层团队疲于奔命。例如 :
企业有多条
业务线
,各自有不同商品结构,原各设置一个前台团队负责其应用
的交付和运营。为降低成本,决定将各
业务线
的商品展示、搜索等需求集中起来,设立商品中心
作为平台支撑层的应用
/应用组
。这个初衷是好的,但如果
商品中心
仅仅是“复刻”各业务线
的商品结构,而未作相应设计的话,面对多条业务线
的多线需求,往往不堪重负,成为瓶颈。
因此商品中心
必须设计一个商品结构的元模型
,可通过运营人员组装的方式,为不同业务线
的商品结构建模。这样才能将前台各业务线
的商品展示、搜索需求变化就地消化。
因此,如果对分层
做出设计,那么在职责划分上就要做出应对,否则分层
容易成为空中楼阁。
4.2.2.5 应用服务
与扩展点
建模
元模型
中的应用服务
最主要的作用是显式地向对外定义一个契约。这在做应用组件
升级 / 替换、定义IT 服务级别等架构治理场景中会有帮助。应用服务
可用来对一组相关的应用组件
功能集合建模,例如:
在线上订餐流程中,用户需要 IT 系统支持提交订单、发起付款、订单状态查看、取消订单四个行为,可将它们建模为
应用服务
――订餐结账
应用服务
的来源可以是“自动化”的业务服务
,如果在业务架构
采用了能力
建模(见 3.2.3.4 能力
建模)也可以直接将其构建块转换过来:
能力组件
转换为应用服务
基础能力
转换为功能
另一方面,如果说应用服务
显式定义了应用组件
的入口,那么扩展点
则显式定义了应用组件
的出口。扩展点
有两个作用:
一是反转对不稳定应用组件
的依赖,降低其变化对自身的冲击,这在“应用组件
建模”一节中有提到。
二是增强可移植性质量属性,即不同的业务场景
下对于同一个应用组件
的逻辑存在差异化需求,对业务架构
的“变化点
”,根据当前应用
状态上下文中的业务身份
,针对性选择适合的逻辑实现。例如:
某公司有零售门店,销售零售商品,同时在店内还有餐厅,我们可以将客户结账识别为一个可共享服务。结账后,商品订单需要派单至仓库提货,而餐厅订单需要派单至厨房备餐,这需要使用“放行履约”这个
扩展点
,并找到两种业务模式的扩展实现
关系。
( 图 4.2-4 典型的扩展点
建模结果 )
总结来说,应用服务
和扩展点
是对边界概念的加强,帮助我们理解跨边界的交互。
4.2.2.6 边界划分
结果和依据的可视化
我们建议将边界划分
的结果及过程依据保存下来并可以开放给授权人员访问。这是因为我们常常见到这样的问题:“新的功能应该放在哪个应用
实现?”
这个问题背后的原因可能是应用
的边界划分
不清晰,职责模糊,或者是边界划分
的结果及依据丢失了。常见的现象是我们看到一张张应用架构
全景图,由若干个方框组成,代表一个应用
或应用组件
。由于缺少上下文
,仅凭方框内的名字很难判断应用
的职责范围,所以不好回答“新的功能应该放在哪个应用
实现”这样的问题。
解决这个问题的难点是如何简练、清晰地描述应用
的边界和职责。在全景图的基础上,为每个应用
/应用组件
增加职责描述是一个不错的起点,但仅用文字描述可能存在歧义。我们建议通过建立应用架构
与业务架构
、数据架构
的构建块
映射来解决这个问题。
( 图 4.2-5 典型的业务架构
- 应用架构
- 数据架构
的构建块
映射关系 )
通过构建块
映射关系(业务流程使用应用服务
,应用服务
由应用组件
提供,应用组件
操作数据对象),应用
/ 应用组件
在业务活动中的职责有了明确的表达,再配合文字来描述引导阅读和理解,效果更佳。我们推荐为每个应用组
/ 应用
/ 应用组件
建立自己的主页,将其与其他元素的映射关系作为内容显示地展示出来。
最后,应用架构
阶段更像是在为 IT 系统应该建设成什么样子提出要求,所以应用架构
设计应该是和技术实现方案解耦的(虽然技术的升级可能使得应用架构
的设计风格产生变化),从而将技术变化隔离在可控范围内。
( 图 4.2-6 典型的应用
/ 应用组件
画布 )