4.2 应用架构元模型 应用

4.2.1 平台化趋势对应用架构提出的新挑战

平台化趋势意味着企业 IT 系统的形态逐渐从扁平结构转向分层结构,即一部分应用提供可复用的能力,组成底部的平台,而其他应用建立在平台之上。

除了能力复用外,另一个提升 IT 支撑响应力的关键是,提升 IT 系统各组成部分的自治性,使得变更能够相对独立的、以小步快跑的方式发生。因为无论是创新也好,集中管控也好,虽然变化速率不同,但变化始终存在,既然变化不可避免,我们应将精力投入到应对变化上。

在我们的经验中,应用边界划分不合理会对应对变化产生明显的负面作用:

粒度过大 粒度过细
功能维度 多个团队在同一个物理边界内,变更计划和所需资源容易冲突,协作复杂 变更实现难度高,质量保障困难或耗时 * 若一个变更常常散布在多个物理边界内,集成、测试、部署负担重、耗时,且常常伴随着高成本的跨团队沟通协调
运行维度 受限于物理边界,无法将故障隔离在局部区域,因故障级联影响业务支撑 受限于物理边界,无法按需调整应用的容量,造成资源浪费 基础设施升级、变更工作量大,或对团队自动化运维能力要求高 平添大量网络通信的开销,反而降低整体性能

这些负面作用会拖慢 IT 支撑的响应力或稳定性,因此,“如何划分 IT 系统的边界,以合理的布局更好地应对变化”是需要解决的挑战。在平台化趋势之前就已经开始流行的微服务架构风格的催化下,这个挑战就已凸显,而平台化强调可复用的服务,必然会对原有系统进行打散和重组,进一步加剧了这个挑战。

4.2.2 如何划分 IT 系统的边界,以合理的布局更好地应对变化

从上文的分析可以看出,边界划分其实从应用架构视角出发,对功能运行层面变化的应对设计,是应用架构设计的重要部分。我们在进行应用架构设计的过程中,融合了领域驱动设计中的限界上下文统一语言的概念,延续业务架构部分中对于领域对象的识别和子域划分,结合组织与技术的要素,从多个方面充分考量对于应用的建模。

  • 限界上下文(Boundary Context):是 业务上下文的边界,在该边界内,当我们去交流某个业务概念时,不会产生理解和认知上的歧义(二义性),限界上下文统一语言的重要保证。
  • 统一语言(Ubiquitous Language):是 Eric Evans在《领域驱动设计 - 处理软件核心中的复杂性》中使用的术语,用于构建由团队,开发人员,领域专家和其他参与者共享的语言,也称为"无处不在的语言"、"通用语言"、"泛在语言"。统一语言是在限界上下文中建模的,在其中标识表达了业务领域的术语和概念,并且不应该有歧义。

带着对于业务上下文边界的理解,使用业务、技术都能理解的统一语言,以两大阶段实现边界划分:

  1. 功能需求层面出发,按“单一职责”原则划分逻辑边界
  2. 加入非功能需求,按架构质量属性调整逻辑边界并划分物理边界

这个设计过程可通过元模型提供的应用层应用组应用应用组件进行不同层次的边界划分建模。

4.2.2.1 应用组建模

应用组是一种大比例结构的逻辑边界划分结构,其主要作用是:

  • 应用组作为一种粗粒度的划分,帮助我们快速找到进一步划分的切入点
  • 微服务化的大背景下,物理边界逐步碎片化,我们在与利益干系人对话时,需要一个能够代表一组相关物理边界的结构,以避免不必要的细节干扰

在结构上,应用组包含了多个应用物理边界)。应用组常常对应到数字化产品级别,例如 CRM 系统(客户关系管理系统,其下可能包括客户档案管理应用客户忠诚度管理应用);在业界流行的按中心划分的中台 / 平台 架构里,应用组常常对应到某个中心

应用组的建模依据主要来自于业务架构业务组织两部分成果的输入。在从 0 到 1 的应用架构设计场景里,这个步骤不求精确,主要是帮助我们建立划分的起点。例如:

汽车行业的经销商,会同时开展新车销售和售后服务两个不同的业务,在经销商内部一般也由不同的组织负责。

而维修保养和配件销售又是售后服务中的两个不同业务场景

我们可依此快速建立一个两级的应用组,这个结构并不精确,但足够我们进行下一步工作。

4.2.2.2 应用组件建模

应用组件是一种细粒度的应用 逻辑边界划分结构,是对功能、数据的封装。

向上,一个或多个应用组件可组成一个应用物理边界),向下,就是代码实现层面的结构设计了。因此,应用组件架构层面运用“单一职责”原则的最小单元。

按职责类型分解,应用组件可分为四种常见的参考类型:

类型 功能 数据 例子 变化原因
流转类 支撑某个流程流程中的一段活动 流程的状态流转信息和决策证据 结账组件,其支撑的流程是结账流程,管理的数据是订单 流程编排变化
规格类 支撑某个业务规则,给出专业意见 一般不管理数据的生命周期,只负责加工给出结果 验证:如发票是否逾期 筛选:三月内消费过的客户 * 计算:计价、导航路线建议 业务规则的计算逻辑变化
视图类 支撑某个业务活动所需的整合信息 一般不管理数据的生命周期,只负责加工给出结果 商品信息的整合展示 统计报表 视图组装逻辑变化
配置类 为前三类提供配置输入 基础的资源信息 商品目录设置内容管理 系统中的配置功能规则的开关 前三类对配置要求的变化

一般来说,我们建议从流转类应用组件开始识别,再延伸至规格类视图类,最后再识别配置类。建模依据主要来自于业务架构业务流程业务对象业务规则

其过程可总结为三个子步骤:

子步骤一:功能和数据识别

逐层分解业务流程,从活动任务步骤中可以得到相对细粒度的业务需求,即 IT 系统需要提供的功能;将业务对象转化为不同类型的数据对象。

子步骤二:功能与数据关联

识别应用组件按不同组件类型将功能与数据对象关联对应,得出应用组件。在流转类组件建模时,有两个关注点需要特别注意:

一是隐式业务边界的识别。在对业务流程分析时,地点、角色变化时,我们面对的业务干系人和他们的工作环境不同,其关注点可能不同,这往往会成为不同的变化原因。通过识别这类隐式的业务边界,这可以帮助我们细分数据对象和应用组件,例如:

线上订餐流程中,客户提交订单并完成付款后,订单会被派单至厨房备餐。即使在业务架构的产出中没有识别出客户订单和厨房备餐单据可能是不同的业务对象,也可以从地点和角色的变化将订餐结账、备餐识别为不同的应用组件

二是数据对象变更一致性约束的识别。在流转类 应用组件的建模过程中,应该尽可能识别业务规则中对于数据对象变更的一致性约束,以元模型中的不变量建模。不变量代表了哪些数据对象需要被同时改变,我们可以依此复查,是否将应用组件拆分得太细,破坏了事务边界。

子步骤三:识别、调整各应用组件之间的依赖关系

识别各组件间的依赖关系,在这里尽可能避免两种依赖:

一是尽可能避免依赖容易变化的组件。尽管可以定义契约,但容易变化的组件容易打破先前定义的契约。

二是尽可能避免出现双向依赖。双向依赖往往对可适配性产生负面影响,可通过引入第三个组件或扩展点(详见应用服务扩展点)解耦。

4.2.2.3 应用建模

有了应用组件作为“原料”,应用架构物理边界设计就有了输入,下一步的目标是识别是否存在架构质量属性冲突,作为应用建模的重要参考,调整逻辑边界,并确定物理边界。质量属性冲突包括:

  • 该边界内是否存在变更频率冲突

我们倾向于将高频变更的应用组件与其他应用组件阻隔开。物理边界意味着部署的独立性,不容易产生发布计划、部署所需资源上的冲突。如果一个功能扩展带来的变更,集中在某个应用、甚至应用组件内,其协作成本相对更低。

  • 该边界内是否有特别的移植性要求

该要求指应用迁移到不同组织、业务运作方式的能力,或者换一个角度来说是应用承接新业务模式的能力,这恰巧是平台所需要的关键能力。在实现某一个业务模式时,必然存在该业务模式的特定需求和可以支持多个业务模式的公共需求。我们倾向于将特定需求和公共需求的实现隔离到不同的应用组件、甚至应用里。以便新业务模式入住时,方便实现功能扩展以及实现部署要求。

  • 该边界内是否有特别的弹性要求

该要求指应用是否容易通过调整容量来应对流量变化。在这里应用的粒度决定了容量调整的难度和成本。因为应用的粒度太大,而流量变化只影响其中某个应用组件,则扩容带来了不必要的成本浪费。

图 4.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-4 典型的扩展点建模结果 )

总结来说,应用服务扩展点是对边界概念的加强,帮助我们理解跨边界的交互。

4.2.2.6 边界划分结果和依据的可视化

我们建议将边界划分的结果及过程依据保存下来并可以开放给授权人员访问。这是因为我们常常见到这样的问题:“新的功能应该放在哪个应用实现?”

这个问题背后的原因可能是应用边界划分不清晰,职责模糊,或者是边界划分的结果及依据丢失了。常见的现象是我们看到一张张应用架构全景图,由若干个方框组成,代表一个应用应用组件。由于缺少上下文,仅凭方框内的名字很难判断应用的职责范围,所以不好回答“新的功能应该放在哪个应用实现”这样的问题。

解决这个问题的难点是如何简练、清晰地描述应用的边界和职责。在全景图的基础上,为每个应用 /应用组件增加职责描述是一个不错的起点,但仅用文字描述可能存在歧义。我们建议通过建立应用架构业务架构数据架构构建块映射来解决这个问题。

典型的`业务架构` - `应用架构` - `数据架构`的`构建块`映射关系

( 图 4.2-5 典型的业务架构 - 应用架构 - 数据架构构建块映射关系 )

通过构建块映射关系(业务流程使用应用服务应用服务应用组件提供,应用组件操作数据对象),应用 / 应用组件在业务活动中的职责有了明确的表达,再配合文字来描述引导阅读和理解,效果更佳。我们推荐为每个应用组 / 应用 / 应用组件建立自己的主页,将其与其他元素的映射关系作为内容显示地展示出来。

最后,应用架构阶段更像是在为 IT 系统应该建设成什么样子提出要求,所以应用架构设计应该是和技术实现方案解耦的(虽然技术的升级可能使得应用架构的设计风格产生变化),从而将技术变化隔离在可控范围内。

图 4.2-6 典型的`应用` / `应用组件`画布

( 图 4.2-6 典型的应用 / 应用组件画布 )

results matching ""

    No results matching ""