1. 引言
软件架构是软件工程学中一个正高速发展的子研究和实践领域.
软件架构是程序或计算系统的结构,包括软件组件、那些组件的外部可见的属性,以及那些组件之间的关系.
软件架构对于系统非常重要的原因
A. 起到与涉众交流的作用
B. 是系统初步的设计决定
C. 是系统一个灵活的抽象
软件架构提供了一个通用的语言来表达不同的涉众对系统的担忧,
如果没有这样的一种语言,就会使系统非常难于理解和领会,
以至于不能尽早决定系统的质量和可用性.
软件架构是软件系统构建,修改和分析的技术蓝图.
2. 架构是涉众交流的工具
2.1 架构结构
架构结构是一种描述和规约.这些描述和规约被多个涉众使用和遵守.
架构师设计完成系统的整体架构结构,而专业专家则精炼和实现各自负责的视图.
架构结构通常包括视图:
功能视图(logical view)
代码视图(code view)
开发视图(structural view)
并发视图(process/thread view)
物理视图(deployment view)
2.1.1 功能视图
功能视图是系统功能和功能间关系的抽象.
功能视图的组件包括:功能,系统的关键抽象,领域元素.
功能视图组件的关系是依赖和数据流.
功能视图的用户是领域工程师,项目流程设计者和最终的用户.
2.1.2 代码视图
代码视图是程序员看得到的东西.
代码视图的组件是一些类,对象,过程,函数,以及由这些元素抽象/组合而成的子系统,层和模块.
代码视图组件的关系是方法调用以及诸如is-a-module-of 的包含关系.
代码视图的用户是程序员,设计者,当然也有可能或者某人既是程序员又是设计者.
2.1.3 开发视图
开发视图是程序开发者可见的另一个视图,但该视图与代码视图完全不同.
开发视图是不同程序员和程序维护人员生成,修改,管理的原代码打包结构化的视图.
开发视图的组件是文件,目录,其他形式的组件也是可能的,比如将原代码存储在数据库中.
开发视图文件和目录之间的关系是包含关系.
开发视图的用户除了是程序员和程序维护人员外还有项目经理和配置管理员.
2.1.4 并发视图
并发视图考虑哪些进程和线程需要创建,以及它们之间如何进行交互和共享资源.
并发视图的组件是进程和线程.
并发视图组件的关系是数据流,事件和同步机制.
并发视图的用户是那些需要考虑系统如何部署,担心系统性能和可行性,以及系统集成和系统测试的人员.
2.1.5 物理视图
物理视图描述了系统如何部署硬件资源.
物理视图的组件是计算机,传感器,触发器,存储器等等.
物理视图组件的关系典型的情况是网络或者其他通信设备(如卫星或总线).
物理视图的用户是硬件和系统工程师,他们负责系统的发布,安装和更新(甚至实时更新).
2.2 场景
场景是用户如何使用系统和修改系统的简单描述.
场景往往分为两类:
* 用例:系统每个功能面的流程描述.
* 变例:系统修改方案的描述
场景被用于:
* 理解和验证一个架构: 通常情况是架构师,设计师,程序员通过一起运行某个场景来完成架构的理解和验证
* 架构交流: 特别是对于在项目中还没有主要职责的人员
* 结合视图: 视图很少孤立存在,视图通常相互映射.场景有助于视图映射过程的实现.
* 理解架构的局限性: 当一个架构很难满足和适应某个场景时,我们可以更好的理解架构的局限性.
例如:系统的维护人员可能通过假定有这样一个场景(用不同供应商的设备替换系统某一个中间层或某一个通信基础设备)
来理解系统代码视图和并发视图上的变化.一个系统工程师可能建议这样场景(一半的处理器或服务器停机的情况或
网络中断的情况)来理解这些错误对系统性能和可行性的影响.
再例如:
这里有一些汽车嵌入式控制系统的用例.
A.可以通过服务程序来改变汽车性能和控制参数
B.当发动机不工作的时候,不用诊断发动机机油压力故障
C.使用过程中优先采用预设汽油参数
这些是对系统预期的一些用例.此外,涉众也需要一系列变例.
这些变例描述了工具特征和能力在将来的变更.
A.改变设备和硬件配置,包括内存扩充或使用需求变更.
B.改变处理器上进程分配,时序和优先级.
C.移值用户界面到WinCE
2.3 架构描述语言
许多架构描述语言(ADL)在理论上和实践中都已经生成和完善.
但是每一个语言都着重于架构描述和分析的不同方面.这也带来新的问题,因为架构描述
语言的多样性,必须引入架构描述语言之间的信息交换机制.
ACME就是这样一个用于架构交换语言.通过它,不同的架构描述语言可以互相交换信息.
没有一个架构描述语言在所有领域被广泛接受.
UML语言已经被广泛采用作为面向对象的设计,现在UML通过扩展,也可以用来描述架构结构.
UML正在成为事实上的架构描述标准,至少交互问题被稍微解决,很容易理解,并且已经在设计领域被广泛的使用.
但不管怎么说UML不是什么灵丹妙药.UML最初是用来作为面向对象设计和分析的语言,而不是作为架构语言出现的.
就其本身而言,UML并没有把架构作为最重要概念.UML并不支持从架构抽象到任何层次的设计重构.
此外,很多机构裁减UML来表示他们的架构,UML作为一个很复杂的语言,可以被不同的架构师以不同的方式使用.
最后,UML是一个相对抽象的语言,因此很难通过它非专业人士交流.尽管有这样那样的问题,UML还是受到了
大多数架构师的关注和实践.
3. 系统初步的设计决定
软件架构是系统初步设计决定的集合.
这些设计决定,如系统是由什么组成的将对未来的系统的产生的巨大影响.
这些设计决定,也对系统的实现作限制,如所有进程通过TCP/IP进行通信.
这些设计决定将影响系统资源如何分配和仲裁.
架构结构和人员组织结构有很强的对应关系.为什么会这样?
这是因为架构结构定义了系统功能和一系列相关考虑的分组.
例如并发视图提供了在做性能计划,建模,调式阶段人员分组的必要性.
并发视图也提供了一个项目组怎样考虑系统出错检测和管理的必要性.
代码和开发视图通过模块,子系统或层次定义了系统的结构.这些视图都会影响人员组织结构.
一个模块,子系统,层代表了高度聚合的一组功能,这组功能内部高度耦合,但对外低耦合.
康威定律(Conway's law)指出这些模块,子系统,层必须与人员组织结构一致,
不然就会存在与人员组织结构不符合的信息流.例如:
数据库组的成员对他们内部的接口和代码必须很熟悉.但是他们只需要看用户界面组或通信组的公有接口.
考虑人员的分组的时候必须考虑软件关注点的分离.要不然,由于开发项目组要了解整个系统,他们的压力会很大.
正因为如此,人员组织结构必须与架构结构一致.
架构的初步设计决定必须以最基础的组件为中心:如何通信,如何传递和共享数据,如何初始化,如何关闭,
自检测,出错报告等等.如果实现了上述活动一个计算结构(也叫做框架结构framework)在一开始就被建立,
将会得到很多好处.这样在系统生命周期的一开始就可以存在一个可以工作的版本.
这个最早的版本可能只能做启动然后做一些只能表示其正在工作的事情,但它使所有子系统的
基础组件一起工作了.许多子系统这个时候可以是一个个只从文件读数据并输出相同值的桩程序.
当系统开发的时候,这些桩程序被完全功能版本的子系统替代.这也就意味着,系统一直是在稳定的增长.
有一个系统早期的工作版本从道义上来说也是非常棒的,因为这增加了客户的信心,并能很好的控制和估计
系统进度,也意味着集成和测试可以开始,而不会存在项目后期"大爆炸"的风险.
3.1 架构风格
Shaw和Garlan收集了架构风格.他们列出一个架构风格需要包括:
* 独立的组件:通信进程,显式调用,隐式调用.
* 数据流: 批处理序列,管道和过滤器
* 数据中心: 数据仓库,黑板.
* 虚拟机: 解释器,基于规则的系统
* 调用/返回: 主要程序和子进程,面向对象的,分层的.
此外,Buschmann也提出.没有完全并通用的架构风格.复杂的系统可以一次使用多种风格,
架构风格互相交叠,并可以互相包含.但是每一个架构风格必须至少包含:
* 一系列组件类型(如:数据仓库,进程,对象)
* 一系列连接器类型/交互机制(子进程调用,事件,管道)
* 这些组件的布局
* 一系列布局和表现上的约束(如:数据仓库不允许改变存储值,管道是非循环的)
* 一个非正式关于架构风格花费和收益的描述.
最近,基于属性的架构风格的概念通过绑定架构风格,并作显示框架分析,添加分析复用和设计复用功能.
3.2 软件架构用于开发流程
在另一种方式下,软件架构是一个关键的初步设计决定的容器,
软件架构是一个可复用的模型并可以开发流程的基础.一个软件架构是一个组织花费巨大获得的资源.
这些花费可以并且应该被复用.事实上,当其它形式的复用由于历史原因很少能货得成功,基于架构的开发流程
正在证明是这是一个对于大多数组织能取得商业成功的关键.
当建立一条开发流程的时候,新的软件工程的挑战是其遇到了以前单一产品开发没有发生的问题.
因为需要作大量的工作来决定哪些是核心资源哪些是边缘的,创造和管理这些核心资源成为了开发流程成功的关键,并且是一个巨大的挑战.
另一个在建立开发流程时候面临的巨大挑战是如何使用核心资源进行开发.
特别是,新的产品会频繁的需要新的功能,并且必须决定是否或者如何使这些新功能封装进核心资源里.
对于开发流程来说,架构的挑战有双重的:其一是在开发流程实体上管理和实现质量属性,其二是保持统一架构的前提下
管理功能的变化.架构的第一个挑战,例如:建立一个小的,便宜,低性能,单一处理器版本的产品还是建立一个使用相同架构的大的,昂贵的,
高性能,多处理器的版本.并且管理这个功能变化的基础设施自身不能占有太多的系统的处理器资源.第二个挑战要求架构师能
够在不改变系统下层模块前提下能够较大适应功能的变化.
尽管这些问题没有办法解决,但大量的研究和工业实践经验表明,基于架构的软件开发流程是有效率和节约成本的。
4. 软件架构设计和分析
如果我们接受架构是一个组织和一个系统成功的关键,并且我们接受我们应该对架构进行仔细的设计和文档化并以此作为工程蓝图.,
那样我们就应该意识到我们需要分析我们的设计成果.我们做这些事情有以下一些理由:
* 保证我们的设计决定是充分满足质量要求的.
* 来预测最终系统的质量属性
* 来保证系统符合涉众的要求
* 来确信我们的提交设计决定是节约成本并能使组织收益最大化.
简单说,我们对这个软件系统花了这么多的时间和金钱,架构必须是有预测能力的.
这是任何成熟的工程理论的特点:可预测性.
我们怎样获得可预测性?其它工程理论如何获得可预测性? 答案是他们通过设计复用和分析复用获得可预测性.
软件架构层次上的设计复用有两种形式:面向对象的设计模式和架构风格.就像上面描述的,基于属性的架构风格已经
通过架构式样和分析框架增加了分析复用和设计复用.
4.1 基于架构的设计
基于架构的设计能够作为一个真正的工程过程,而不仅仅是一种特殊的过程.
作为这一点上的第一次尝试,
<基于架构设计的方法(Architecture based Design Method)>提出了一种通过一系列分解和提炼来转换客户需求到系统架构或开发流程的方法.
这个ABD(Architecture based Design)方法开始的时候,跟几乎所有拥有功能和质量需求的软件项目做的方法一样.
接着这种方法递归分解架构设计以满足这些需求.每一个递归分解架构的时候,它总是会添加一些功能需求的设计元素.
同时通过将功能需求的架构式样组合在一起并在架构中实现来满足质量的需求.
架构设计,演化到现在,主要集中在三个方面架构视图:功能视图,并发视图 和物理视图.
每一个视图的建立都要求架构师提出相关设计问题并作回答.这些问题通常以场景的样子出现,
这些场景首先与产生进程的那些需求关联.ABD方法可以被看作ATAM设计阶段的实现,ATAM将在接下来提到.
4.2 基于架构的分析
即使架构设计已经做完,仍然需要分析这个架构设计以确定架构师对架构的提案能真正保证系统的需要的质量能得以实现.
许多架构分析方法已经被提出,如SAAM,ATAM 以及SAA.这些技术都是基于场景的.他们都必须是基于场景的,因为如果没有场景
就不能精确的对质量属性的目标进行特征描述.软件工程社区并不关注什么是可修改性,或可行性或安全性,或交互性.
因此我们将这些缺失用场景替换,场景可以通过一个上下文来实现特定的质量属性,这个上下文包括一个触发输入,
一个特定环境以及一个响应.
这些架构分析方法通过生成一系列的场景分析并"测试"系统架构,另外通过将这些场景应用到架构里使得人们
可以用标准测试用例作为输入,像测试真实系统一样测试和基准这些场景,并且测试的上下文是标准的操作环境,
最后评估生成的响应.架构权衡分析方法(ATAM),同过以下步骤实现这些活动:
* 引入
<1>.提出ATAM: 将方法描述给所有涉众的(通常客户代码,架构师或架构团队,用户代表,维护人员,系统管理员,经理,测试人员,系统集成人员等等)
<2>.提出业务驱动: 客户代表描述了业务目标,因此业务驱动是主要的架构驱动
<3>.提出架构:架构师描述推荐架构,关注于如何应付业务驱动
* 调查和分析
<4>.将架构对应到业务目标:架构师以及项目核心成员如经理,市场/客户代表详细描述系统质量属性如何对应到架构.
<5>.生成质量属性实用集树:系统的"实用集"(性能,可行性,安全性,可修改性等等)质量因素是可以被抽出,或者子化,
或者规定其到场景层次,也可以设定他们的优先级.
<6>.分析架构方法: 对于在第5步生成的质量属性实用集中,那些被识别为高优先级的场景,
代表场景架构方法被抽出,分析和实现(例如:一个满足性能目标的架构方法会被要求做性能分析).
这一步骤中指出了架构的风险,敏感点以及权衡点.
* 测试
<7>.头脑风暴并对排定场景优先级:
从整个涉众团体的大量场景中抽出那些最要的场景.这些场景通过整个涉众团体的一个投票过程来决定优先级.
<8>.分析架构方法:这一步重复了上面的第6步,但在这里只有在第7步中优先级高的场景才被分析作为测试用例用以分析
到现在为止决定的架构方法.这些测试场景可能揭开已经文档化的额外的架构风险,敏感点和权衡点.
* 结束
<9>.得到结果: 基于ATAM中收集的信息(架构风格,场景,指定属性问题,实用集树,风险,敏感点,权衡点),ATAM组提交这些
分析结果给相关关注这些信息和提出缓解策略的涉众.
这个方法的完美细节可以在很多地方找到。重点是利用这种技术分析和验证架构设计决定的结果,在这些设计决定还没有被
提交到代码和花费巨大的变更中去.这些技术显然是不昂贵并且在以在开发周期任何时候使用的。
4.3 分析架构设计决定对业务的影响
软件系统开发的收益和花费是可以在系统已经开发满足的业务上进行评估.同时,这些评估的结果
大部分情况下是由它的架构设计决定的.架构因此不仅仅是制定设计的关键产物
还是实行花费收益分析的关键产物.这个分析中的一个重要部分是估计不确定性花费和收益时确定级别.
大量的研究已经开始慎重思考如何将业务上的考虑与软件分析和采用经济学方法(比如投资理论和选择现金理论) 联系在一起.
虽然这类分析仍然还处在初级阶段,但是一些学习方法和情况已经存在了。
5. 架构反向工程
这篇文章中已经讨论了建立,文档化,以及分析架构.如果这些技术是成功的,这个架构和它的组件将会是一个
组织在很多年里的一个重要资产.这就意味着架构维护成为一个问题,这将是一个时刻存在且比第一次建立架构更有压力事情.
为什么是这样的?
如果一个架构设计的时候有很多属性(高性能,高可靠性),是否这个系统的属性是从架构来的?
答案是:有可能.为什么没有一个明确的回答? 这是因为,通常,没有办法保证被设计的架构就是最后真正
实装的架构.正因为如此.在成熟架构的开发过程中保持架构的一致性是非常重要的。
做到一致性意味着你既要不能让架构的实现偏离架构手册,同时你也要能从你实际已经实现的东西里抽出一个
架构;也就是对系统的架构结构从已经代码实现的一些原子操作作反转工程(过程调用,方法调用,类定义,进程间通信,等等)
还有其他许多的理由表明为什么你有需要对一个软件架构作反转工程.
一个架构文档可能并不存在,或已经丢失,或者长时间不用:
* 架构可能从来没有文档化过,理解架构需要的专业知识只存在那些已经离开组织的人员头脑中.
* 新产品没有架构文档存在
* 程序员可能通过绕过架构的抽象设计层,巧妙或不巧妙的毁坏了架构.
正是有这些原因,非常有必要对一个架构描述从已存在的代码和工程文件作反转.反转工程没有自动
的过程.这是一个以架构师(或者是某个至少能从系统知识或文档中推测架构结构的人员)和反转工程工具集中的交互对话的形式出现的解释过程.
现在存在许多类似的工具集,如ManSART,Dali,Philips工具集,以及Software Bookshelf. 所有的
这些工具集有四个主要功能:从代码中抽出原始架构,将抽出的信息存储到数据仓库里,将仓库里的内容可视化给用户.
操纵仓库内容并通过将一些从原子抽象信息对应过来的规则作用到架构抽象来反映架构的抽象.
6. 软件架构的未来
软件工程正快速成为一个受关注的软件工程的子理论.许多商业组织都建立自己的架构组织对公司其它部门
做内部咨询,生成架构规约,文档,分析,和维护.这篇文章只是对架构的简单描述.
需要更多参考需要阅读其架构方面的资料.
领域包括动态系统架构,反射架构,架构迁移,以及其它
热点研究和实践.无论如何有一件事情是确定的,只要人类需要建立
大型,复杂,软件密集系统,那么软件架构将必然是这些系统成功的关键