德国哲学家、数学家莱布尼兹一针见血地指出:“不讲分解技巧,分而治之就不大有用。无经验者对问题分解不当,反而会增加困难“。为了正确的进行分解,需要遵循一些分解原则:
对复杂的系统,特别是前人没有做过的新系统,通常难以一下子设计出合适的架构。在架构设计的初期,通常都要经历一个不断探索的阶段。
在架构设计过程中,架构分解是必不可少的的关键步骤。如何进行架构分解?从哪里入手开始进行分解?我们需要有一个架构分解的过程模型来指导分解过程,启发和探索架构分解的维度和线索,提高架构分解的效率。
架构分解过程模型如图 3 所示,是一个迭代的模型。通过这个迭代的分解,从无到有、从粗到细、从模糊到清晰,一步步精(细)化、丰富架构。迭代的过程也是一个否定之否定的过程,随着分解的逐步推进或系统的架构演化,后面的分解除了会识别出新的架构元素,也可能会对先前识别出的架构作出调整。
依次在 4 个域中进行架构分解,基本顺序是先业务后技术,通过多维度多层次的分解将关注点分离。
首先是从系统需求入手,寻找业务域中的分解维度,将架构从业务域层面进行大尺度(大粒度)的分解。在业务域中进行分解,通常采用的分解维度是根据业务主题,将系统分解为多个子系统,每个子系统聚焦于一个独立的业务主题,子系统间具有清晰的边界。例如对某电商系统,我们可以根据业务主题维度进行架构分解,初步划分出:会员子系统、交易(订单)子系统、产品子系统、搜索子系统、物流子系统、支付子系统等。
领域驱动设计(DDD)中的边界上下文(context boundary)是一种根据业务相关性进行大尺度分解的方法,它和基于业务主题的分解是类似的。
对业务域分解不应只局限于基于业务主题的分解,根据具体情况,还可能有其他的分解维度。一个通用的发现分解维度的方法是试着从领域模型和需求分析文档中寻找名词和形容词,将文档中的核心概念(名词和形容词)作为分解的候选分解维度或分解线索。
在业务域的分解中,我们要和业务(行业)专家密切交流,多研究业务架构、适当考虑企业战略,这样可在一定程度上保证架构分解的合理性。
对业务域功能域分解,一个通用的方法是试着通过动词来将子系统拆分为多个服务;另一个是根据资源类型(名词)来将系统拆分为服务,每个服务负责实现对应资源上的一组操作。例如根据资源类型(会员、商品等),对电商系统,可分解识别出会员查询服务和会员管理模块、商品服务等。
这两步的架构分解都是纯业务上的,不涉及技术,但要这两步分解出的架构元素要映射到技术域中去实现,或用来帮助架构师推导出技术域的对应架构元素。
在业务域和业务功能域中分解出来的架构元素,考虑到技术实现,在映射到技术域时,可能要对架构元素进行修改或作一些微调,业务域和业务功能域中分解出的架构元素通常会进一步分解为技术域中的多个架构元素。例如在业务功能域分解出的会员查询服务模块,在技术域中分解时,考虑到有多个不同类型的调用方会使用该服务,并且这些调用方需要的查询接口差异较大,调用频率等也不一样,那我们可能会对每个调用方拆分出独立的查询接口模块,这样也避免了胖接口,相关的 DAO 类也是在技术域中新产生的。
在从模块分解到类的过程中(假设有些模块要分解到类级别),需要进行静态和动态的分析以便识别出类元素。首先是根据业务域需求,建立领域模型,识别出领域(概念)类,再将领域类映射到技术域中的设计类(实体类),也就是领域类可帮助我们识别推导出部分设计类。再基于具体用例,进行鲁棒分析和序列图设计,考虑技术上的实现和采用的技术架构,例如采用一些技术框架和类库或工具类,如 ibatis 框架,就会识别出另一些设计类(边界类、控制类)或引入一些新的设计类,这些引入的类可能直接来自框架或类库,或是继承框架中的类(成为框架类的子类)。通常设计过程不会就此结束,考虑到开发维护和设计质量等因素,我们会运用一些设计原则(如高内聚低耦合、单一职责、信息专家等)、设计模式、重构模式等对设计进行进一步的优化,这时又会产生识别出一些设计类,通常在这一步会对我们的设计进行一些修改和调整,例如采用工厂方法设计模式,会引入工厂方法类,我们的序列图就要修改。这样我们最终完成了一个完整的设计。因为要考虑技术域,所以对整个分析设计来说,它是源于业务但要高于业务。
在技术域的分解中,对公共的技术需求应全盘考虑,抽象出底层的公共技术基础设施,例如定时任务在许多子系统中都存在,此时可能会规划一个定时任务框架和定时任务执行系统。也可能会采用一些成熟的框架和中间件技术,如消息中间件、ESB 等。
技术域的分解通常是比较复杂的,这一方面来源于问题域的本质复杂性,特别是各种非功能性需求的复杂性,需要架构师掌握应对这些需求的常见模式。另一方面也是由于 IT 新技术的日新月异,要求架构师对技术敏感,与时俱进。
要注意的是,当在技术域分解中碰到困难时,可以再回到业务域中去寻找答案和线索。例如为了解决某计费系统中的性能和可伸缩性问题,可在业务域中寻找名词和形容词,发现可以根据付费类型(预付费和后付费)将系统初步分拆为预付费系统和后付费系统。对网络通讯系统,可以根据请求消息中的某些属性对消息处理系统进行拆分或根据客户端类型等进行拆分。
涉众域分解的一个可能的维度是根据涉众类型,基于他们的关注点来进行架构分解,试着为某类涉众划分出对应的子系统或模块(架构元素),例如考虑到前台涉众和后台涉众的用户类型、关注点差别较大等因素,可能会将系统划分为前台系统和后台系统两大类。对第三方涉众(外部系统),考虑到接入认证授权、安全性和互操作性,可能会分解出网关子系统。
为何首先从业务域开始分解,其实很好理解,我们开发一个系统肯定是为了解决业务问题,是为业务服务的,不可能脱离业务去设计一个空洞的无目标的系统和架构。
从上面的描述可以看出,架构分解就是从多个维度多层次对系统进行分解,识别出架构元素,逐步精化、丰富系统架构的过程。图 4 形象地表示了架构分解的多维度立体拆分。
这 4 个域中除了分解过程模型一节中提及的一些分解维度,根据具体的系统,还可发掘出许多分解维度,如时间维度、物理空间维度、优先级维度、职责角色维度(不同的角色)、客户端维度、调用方维度(不同的调用方)、请求类型维度、数据维度、数据处理维度(OLAP、OLTP)等。
有几个要指出的问题是:
对非功能性分解维度,在具体的分解过程中,可以借助一些成熟的模式来实现架构元素的识别,在<<软件构架实践>>中,将在架构层面应对非功能需求特性的架构模式或架构策略称为战术,例如对可用性,常用的战术包括:冗余、错误检测。
在<< The Art of Scalability >>中,对可伸缩性,提出了一个伸缩立方模型(Scale Cube),如下图 5。
这是一个三维的立方模型,表示可在三个维度上实现可伸缩性:
这三个维度可以结合在一起使用,也可单独使用。
可以看出,前面提到的 eBay 可伸缩性实践应用了该模型。
部分非功能需求的常用战术如下表 1:
非功能需求类型 | 战术 |
---|---|
可用性 |
|
性能 |
|
可伸缩性 |
|
战术除了应用在非功能需求上,在架构层面应对功能性需求的架构模式、架构策略和其他技术手段也可称为战术。例如分层模式、AOP(面向切面编程)技术等都是战术。
分解维度和战术的关系,就是战略和战术的关系,分解维度指明分解的位置和目标所在,战术是实现该分解的手段。例如在森林里伐木,分解维度指出砍哪颗树,战术指出是用斧头砍还是锯子锯。没有战略,就不知道目标和方向,成为无头苍蝇;没有战术,战略就成空想,不能落地实现。对软件系统中的横切关注点,在 AOP 技术出现之前,知道要进行分离,但一直没发现实现分离的完美战术,直到 AOP 技术出现后,才较为完美的实现了横切关注点分离,可见战术和机制也很重要。
对简单的系统或有经验的类似系统,也可直接应用成熟的战术,不需在架构分解上过多投入。
多维度多层次分解到什么粒度才停止?这个没有统一的标准,通常要能进行并行开发,能指导后续的详细设计。需要根据具体的产品或项目来定,有的到模块级别就行,对关键的部分,可以到类级别。
架构分解的时机通常就是架构改造演化的时机。当架构出现腐化和臭味,已经难以满足关键涉众的关键需求,例如用户的响应速度越来越慢已经接近临界值,并且根据预见,响应速度还有可能继续较低;开发人员越来越难以维护,这个时候可以考虑进行架构演化,对架构进行改造。当然如果能提前预见系统的问题,经过慎重评估后,在问题发生之前,提前一段时间进行架构演化也是可以的。
要注意的问题是不要过度分解,过早分解,这样做除了增加成本,还可能带来风险。例如很多系统在建设初期,考虑到规模较小和快速上线,通常都是一个整体的系统,不会进行大的架构分解,以后随着需求和规模的逐渐增加,会逐步进行架构改造和架构分解。
在 IEEE1471-2000 规范中对视图和视点的定义如下:
视点可理解为观察系统的一个角度,每个系统有多个视点,每个视点都有一个涉众;该类涉众从某个角度观察系统,所看到的系统的部分信息就是该视点对应的视图,系统有多个视图。
视图和视点通常用在架构文档中,作为描述架构的重要手段,在架构分解过程中,可用来作为发现架构分解维度的一种输入,帮助进行架构分解。
在 RUP 中定义了“4+1“视图,其中的开发视图就是开发人员从开发视点出发,用来为开发人员提供切实的指导。
除此之外,在企业架构 TOGAF 框架和 RM-ODP 也定义了视点和视图来建模和描述各种类型的架构。
对复杂的软件系统,其架构设计是一项复杂的系统工程,架构分解作为架构设计中的关键步骤,在软件行业中还没有成熟的系统的架构分解方法论来指导架构分解。本文对此问题做了初步的探讨,提出了架构分解的过程模型和架构分解多维度模型,用来帮助架构师逐步进行架构分解,识别出其中的架构元素。对架构分解,关键在于找到合适的架构分解维度和分解战术。