作者: Anders小明  

在牛津高阶词典(第7版)中,架构(architecture)一词的解释是:the design an structure of a computer system。这个解释实际上已经描述了架构的本质:架构是关于怎么做(构成系统)的,而非做什么的。更进一步,架构是由人来设计实施,因此架构实际上是一个文化(culture)——我们怎么认识或理解系统/产品的,并且我们准备怎么做,在做的过程中我们认为什么是好的,什么是好的等等。

任何系统都有架构,无论多小的系统都有。区别在于其架构是否是经过明确设计并表达。一个合理的架构无疑是经过精心设计和维护的,而进行架构设计,或者说定义/建立一个架构可以分为如下几个步骤。 

特别的,本文针对于企业应用架构,其他应用未必适用。

基线准备

如果建立第一版架构(即从零开始)可以跳过此步,但对于建立第n版(n>=2)架构,则需要进行基线准备。通常从上一个架构设计开始,去除不在必要的内容作为基线。

 

非功能性需求的收集、分析和细化

这步骤非常关键,本质上架构关注的是系统的非功能性需求,虽然不是系统的全部,但无疑是最重要的20%,而这也是不同公司/产品的架构差异性的根源。

一个完整的非功能性需求列表不仅仅来自业务部门(系统客户),还需要包括开发/研发管理层以及开发团队。实践中可以如下检查列表来帮助收集:

l         目标应用,企业应用和互联网应用就不太相同

l         目标环境,系统部署的硬件环境、网络环境等,更有云计算环境和传统服务器环境的差异。

l         常见技术指标

n         稳定性/可用性,主要是MTBFMTBR指标要求

n         性能,如Web应用下单次操作1/5/10原则,相关并发压力要求等

n         容量,主要是数据容量,此外有时还要考虑内存的限制

n         实时性,涉及到数据同步/复制/消息传播/异步操作

n         易用性,这个指标不容易衡量

l         系统/项目/产品自身,来自客户

l         管理指标,主要来自管理层

n         成熟度/培训招聘成本

n         产品化/定制化

n         组件化

n         领域化

n         标准性

n         平台化/小型中间件

n         集成性/兼容/迁移能力

涉及遗留系统,关于兼容需要明确的兼容方式和兼容模式。兼容方式包括:语义兼容/源代码(语言级/API级)兼容/运行时兼容(运行库/二进制);兼容模式:向前兼容/向后兼容。

n         1.4.6 容错性

包括速错能力和消除易错机制(error-prone mechanism

n         1.4.7 升级性

以上列表略显草根性,实际过程中也可以从架构评估角度反向进行非功能性需求收集,可以参考《Attribute Based Architectural Evaluation》。

一次性完整地收集非功能性需求并不是件容易的事,因此在架构发布后也要不停的进行改进。

 

架构定义

完成非功能性需求并明确后,就可以进行架构定义了。架构定义可以分为三个部分:设计、选型以及构建和评估。

 

架构设计

这个阶段相对务虚,但却是整个架构定义的基础,决定了所有的后续工作。主要包括如下三个工作内容:

l         确定架构手段,包括架构的原则、规范、模式、工具、框架/平台和语言,以及这些手段的适用范围,哪些问题应用工具来解决,而另一些问题采用哪个框架/平台完成,还有一些通过原则或规范处理。

l         确定组织分工和流程,不同的工作通过组织内不同角色完成。

l         确定结构化范围,区分系统内和系统外,并非所有非功能性需求都是通过系统的手段解决,适当采用系统外手段甚至更简单和准确。

 

技术选型/预研

纸面上的架构其约束性和可操作性非常低,为了让架构从三万英尺的高空落地有两种办法:流程和平台。其中,流程是由组件分工完成,而平台构建通常不会从零开始,实践中会尽可能利用已有成果:商业产品和开源产品。因此技术选型以及预研工作则显得非常重要。

进行技术选型需要注意两个关键点:

u       评估单项技术的有用性(技术功能)和可用性(非功能性需求,即使用成本)

有用性是指相应的技术功能点是否解决架构所面临的功能性和非功能性需求;

可用性是指是否满足整体的非功能性需求,如性能、容量和稳定性。以及管理层关注指标(使用成本),如技术成熟度、标准性、培训招聘成本以及产品的生命周期,以及License费用等。

u       保持全局视角

关注全局,木桶理论的再次应用,避免某项技术存在的缺陷影响整体。

主要的选型内容如下:

l         语言,不同语言所能提供的开发能力是不同。而且开发语言直接影响到后续技术的选型以及人员的招聘。

l         框架/平台,提供运行环境和集成环境。

l         工具,古话说:磨刀不误砍柴工。但要注意避免工具中心论,正确认识工具的用于——工具是帮助我们解决一些脏活累活的,除此外无它。在整个架构中,工具的作用是大大低于语言和框架/平台。

除去技术选型外,对于一些不确定的内容,还需开展预研工作,验证其可行性或者进行性能测试。

 

架构构建和评估

如前所述为了使架构落地,在技术选型后完成后进行架构构建,包括了定制化设计和开发,并进行质量保证。

架构构建的结果通常分为三个层次:

l         集成环境,提供一个开发的脚手架,这个是最低层次。

l         编程模型,提供一个统一的编程模型,包含了自定义框架和类库,并对底层技术提供了一定封装和隐藏。当前的趋势是:提供一个POJO一致性的编程模型。

l         运行平台,提供了一个运行平台,(勉强)可以算做一个中间件产品。

 

架构构建过程中应注意如下内容:

l         应用区分平台系统和应用开发接口

应用开发接口是给后续产品开发使用,接口一旦设计发布应当保持问题性和兼容性;而平台系统对后续系统开发不可见,避免兼容设计成本,有利后续升级和变化。

l         简单的API,强大的功能,类似于高级语言

l         可以扩展的SPI,另一种形式的API

l         消除易错机制(error-prone mechanism),避免当错误使用后的修正成本太高

l         适应变化和二八原则,避免在需求变化时后调整的成本过高

l         隔离具体技术,保持未来的迁移性和可升级性

l         提供调用接口和模型应具备一定抽象性

l         分离关注点,纵向的层次化抽象,以及横向的模块与切面

l         提供申明式定义(如XML),由反向解析映射到具体技术,关注于做什么而非怎么做。

 

架构完成构建后,进入架构评估。

架构评估是确保架构有效性的重要步骤,需要针对所收集到的非功能性需求——工作上形成一个闭环,确保工作的有效性——因为架构涉及系统中最重要的20%,应该尽早验证,而不是简单地希望一切都好。

架构评估包括两个工作:进行验证和协助。

可以根据非功能性需求列表来制定验证点,这里列举下主要的验证点:

l         技术点验证

l         性能压力验证

l         稳定性验证

更正规的评估方法可以参考《Attribute Based Architectural Evaluation》。

 

协助是架构评估的另一项工作。架构不是几个人关在一个房间里整出来的与世隔绝的东西。需要项目/系统/产品的等相关利益者理解它。这项工作不应是发布几份文档宣称架构如此如此(见后续《架构发布》),它应当在架构评估时进行(虽然可以在架构构建时进行,但是由于此时架构并未成形,此时的效果有限)。

 

 

架构发布

当架构构建完成并通过评估,架构就可以正式发布了。

框架/平台和工具

毫无疑问,框架/平台和工具是架构发布主要内容之一。

文档

除去框架框架/平台和工具,还有其他重要的内容需要发布,文档无疑必须的。但文档也存在尴尬的情况,已知的工程实践中已经发布了太多无用的文档、过期的文档。

应努力保证所发布文档的必要性和有效性,建议文档如下:

l         架构介绍,可以参考RUP4+1视图,部署视图、运行视图、开发视图等

l         快速入门

l         开发指南

l         服务配置和使用介绍

示例代码

完整可用的代码,运行脚本、注释。完整丰富的示例代码在很多时候比文档更直接,尤其在展示细节问题上。

培训和指导

很多时候,培训和指导被忽略了。相对于文档和示例代码,培训和指导更有互动性,可以更深入讨论,并可以深入到架构设计背后的故事。

 

架构改进

如前所述,通常无法一次收集完整地非功能性需求;而随着时间发展,更新更细节的非功能性需求会不断的涌现和被发现;还有一部分之前已识别但被暂时搁置的非功能性需求开始变得重要。因此架构需要不断发展,而此时的改进通常是以小步快跑的方式进行。

 

下一个周期

不能期望10年前的架构能够满足今天的需求(它可能依然可以工作)。架构发布后到一定阶段,已经无法通过小的改进满足新的要求,重新进行架构设计成为一个必然。而当前的架构设计可以转为下一次设计的基线。

 

 

常见的问题

l         试图创建一个私有的编程模型标准

很少有人这么干,不过有时还遇到这样的做法。通常在封装一些商业或开源产品,美名其曰——隔离实现,这是一个危险的做法,其实质是创建一个私有编程模型标准,如果业界没有纸上标准或实际标准,基于某个产品实现所建立的私有标准无法真正的迁移到别的产品实现;如果有,那就根本不需要建立私有标准。

另有一种封装,其目的是为了简化商业或开源产品,这种封装不打算屏蔽底层的实现——它只是让工作更简单。

如果一定要创建一个编程模型的话,应该是POJO

l         不那么正确的二八原理

二八原理通常很有效,然而它有缺陷——他是基于统计的,这意味着是事后应对。如果没有已有实践经验,那么在一开始很难做出正确判断。

而一旦做出错误的决策导致的问题,很可能出现“玻璃裂纹”现象——不断的扩散并破坏架构设计——直到玻璃碎掉。

更槽糕的是,很多时候所谓的二八划分,基于的是感觉而非统计。

l         过分关注在技术模型上

虽然架构针对的非功能性需求,关注在技术模型没有问题,但是实际上更应关注的是信息模型。而在多数情况下,信息模型是以层的形式来表示。

这里面最典型的是所谓的N层(n-tier)模型,实际上,N层(n-tier)模型就是一个技术模型,描述的一个分布式系统结构。

而真正的N层(n-layer)设计却被忽视,分层Layer模式才是一个架构模式(见POSA vol1),ISO-7层网络协议是一个典型示例。