找回密码
 立即注册

QQ登录

只需一步,快速开始

WantSong

高级会员

65

主题

78

帖子

1113

积分

高级会员

积分
1113

活字格认证

WantSong
高级会员   /  发表于:2009-12-14 10:23  /   查看:5709  /  回复:0
作者:温昱  来源:《程序员》
  一个词(比如“电脑”),可能并不代表一件单独的东西,而是代表了一类事物。这个一般性的表述就是我们通常所说的“概念”。
  也许读者期待一个干净利落的软件架构概念,但这不是现实。对此,Martin Fowler给出的评价是,“软件业的人乐于做这样的事——找一些词汇,并把它们引申到大量微妙而又相互矛盾的含义。一个最大的受害者就是‘架构’这个词。……很多人都试图给‘架构’下定义,而这些定义本身却很难统一。”
  软件架构概念:组成派
  关于软件架构的概念,有太多版本,这对我们的实践也造成了很多麻烦。笔者认为,可以将这些概念大致分为两大流派:组成派和决策派。
  Mary Shaw在《软件体系结构:一门初露端倪学科的展望》中,为“软件架构”给出了精致利索的定义:
  软件系统的架构将系统描述为计算组件及组件之间的交互(The architecture of a software system defines that system in terms of computational components and interactions among those components.)。
  必须说明,上述定义中的“组件”是广泛意义上的元素之意,并不是指和CORBA、DCOM、EJB等相关的专有的组件概念;“计算组件”也是泛指,其实计算组件可以进一步细分为处理组件、数据组件、连接组件等。总之,“组件”可以指子系统、框架、模块、类等不同粒度的软件单元,它们可以担负不同的计算职责。
  上述定义是“组成派”软件架构概念的典型代表,有如下两个显著特点:
  ? 关注架构实践中的客体——软件,以软件本身为描述对象;
  ? 分析了软件的组成,即软件由承担不同计算任务的组件组成,这些组件通过相互交互完成更高层次的计算目的。
  软件架构概念:决策派
  下面来看看RUP(Rational Unified Process,Rational统一过程)为软件架构下的定义:
  软件架构包含了关于以下问题的重要决策:
  ? 软件系统的组织;
  ? 选择组成系统的结构元素和它们之间的接口,以及当这些元素相互协作时所体现的行为;
  ? 如何组合这些元素,使它们逐渐合成为更大的子系统;
  ? 用于指导这个系统组织的架构风格:这些元素以及它们的接口、协作和组合。
  软件架构并不仅仅注重软件本身的结构和行为,还注重其他特性:使用、功能性、性能、弹性、重用、可理解性、经济和技术的限制及权衡、以及美学等。
  上述定义看似冗长,其实核心思想非常明确:软件架构是在一些重要方面所做出的决策的集合。
  该定义是“决策派”软件架构概念的典型代表,有如下两个显著特点:
  ? 关注架构实践中的主体——人,以人的决策为描述对象;
  ? 归纳了架构决策的类型,指出架构决策不仅包括关于软件系统的组织、元素、子系统、架构风格等的几类决策,还包括关于众多非功能需求的决策。
  深入解析:找准软件架构的位置
  既然窗帘是用来遮光的,为什么非要用一整块布呢?于是百叶窗发明了。
  既然建模有助于认清复杂问题,为什么非守着软件架构的“文字定义”方式不放呢?于是我们开始了下面“模型驱动”的思辨过程。
  从Shaw的架构概念开始
  “软件系统的架构将系统描述为计算组件及组件之间的交互”,Shaw的这个定义从“软件组成”角度解析了软件架构的要素:组件、以及组件之间的交互。通过UML类图,我们可以将这个关系表达得更加清晰,参见图1。如图所示,组件和组件之间可以有交互关系,图中的“交互”采用了关联类的语法。
      
        图1    软件架构的要素:组件、以及组件之间的交互
  Shaw的架构定义高度抽象地将软件架构概括为“组件+交互”,我们有必要举例说明之——就以大家熟悉的MVC为例吧(如图2所示):

  采用MVC架构的软件会包含了这样三种组件:Model、View、Controller。
  同时,为了达到一定的目的,这三种组件必须通过交互来协作,比如:View创建Controller,之后Controller根据用户交互调用Model的相应服务,而Model会将自身的改变通知View,View会读取Model的信息以更新自身。

       
           图2    MVC架构作为“组件+交互”的例子
  通过此例可以看出,“组件+交互”可以将MVC等“具体架构设计决策”高屋建瓴地抽象表达出来。
  组件是如何组成粒度更大的整体的
  我们考察软件架构,还必须思考“组件是如何组成粒度更大的整体的”这一问题。
  在具体的架构实践中,一个软件系统往往首先分解为几个子系统,子系统又继续分解……。如图3所示,它刻画了这样的软件分解场景:一个系统,由3个子系统组成;每个子系统,又由组成它的多个类来实现。子系统可以分配到开发组,每个类可以分配到具体的工程师实现。
  
           图3    一个软件分解场景
  由此可见,构成软件的组件具有不同的粒度等级。对于面向对象的软件开发而言,经常有如下组件:

  粒度最小的组件通常是“类”
  几个类紧密协作形成“模块”
  完成相对独立的功能的多个模块构成了“子系统”
  多个子系统相互配合才能满足一个完整应用的需求,从而构成了软件“系统”
  一个大型企业往往使用多套系统,多套系统通过互操作形成“集成系统”
  类、模块、子系统、系统、集成系统,都是组件的具体形态,只不过粒度不同罢了。软件系统越复杂,不同粒度的分解层次就越多;比如,有的组织会引入“分系统”的概念,形成“系统-分系统-子系统-模块”的分级体系。
  不同实践者眼中的组件粒度
  另外,在真实的软件实践中,还有一个问题不可忽略:粒度的相对性。也就是说,同一个软件单元,在不同场景下我们会以不同的粒度看待它。
  我们举个具体的例子:一个VB编程者可以把ActiveX控件拖过来就用,完全把它当成原子级的软件单元;而对于开发方,这个ActiveX控件(比如报表控件、音频编辑控件)就是一个蛮复杂的“系统”,从需求分析到架构设计再到编码测试,所花费的时间一点儿也不比其他软件项目少。
  这就好比,对于除菌皂“研制人员”而言,肥皂和细菌都是复杂体:“研制人员”需要分析细菌的结构,设计肥皂的成分。另一方面,对于用除菌皂“洗手的人”而言,它们并不关心肥皂和细菌的内部。
  由此看来,是复杂事物还是简单事物,要视对谁而言来定。在某个实践者眼中的最基本的组件,对另一个实践者而言有可能位于相当高的抽象层次上。对此,Rechtin就曾指出,“所有系统都有子系统,而所有系统都是更大系统的子系统”。此话再明确不过地揭示了一点:实践的不同场景使得软件组成单元具有递归性。
  借助Composite模式刻画真实的软件
  综上所述,真实的软件其实是“由组件递归组合而成”:
  ? 组件的粒度可以很小,也可以很大;任何粒度的组件都可以组合成粒度更大的整体。即所谓的粒度多样性问题。
  ? 组件粒度的界定,必须在具体的实践上下文中才有意义;你的大粒度组件,对我而言可能是原子组件。即所谓的粒度相对性问题。
  而图3没有全面反映出上述本质,而仅仅刻画了一种“组件合成”的具体场景。仅举几例:
  ? 的确,面向对象方法大行其道,但这不意味着结构化方法开发的软件没有架构。而该图没有反映出除类以外的其他“小粒度组件”。
  ? 如果一个系统比较复杂,那么其子系统的规模也会比较大;这时,架构师直接将子系统分解为类,是否合理呢?依我看来,在大粒度的子系统和小粒度的类之间,引入中等粒度的“模块”概念比较合理——模块由多个类组成,完成相对独立的功能,而子系统由多个模块组成。
  由此,我们不能不联想到Composite模式。Composite模式用于表示“部分-整体”的层次结构,可以用来描述软件的递归组合的本质。图4运用Composite模式来刻画更加真实的软件。
  
    图4    借助Composite模式刻画真实的软件
  本图借助UML类图的语法,表达了一般意义上的“组件合成”场景:组件分为原子组件和复合组件两种;在特定的实践上下文中,原子组件是不可再分的;复合组件是由其他组件(既可以是原子组件,又可以是复合组件)组合而成的;无论是原子组件还是复合组件,它们之间可以通过交互来完成更复杂的功能。
  为“软件架构”找准位置
  是时候为“软件架构”找准位置了。答案看上去惊人地简单,如图5所示。
  
       图5    为“软件架构”找准位置
  毋庸置疑,今天的软件系统一般都比较复杂,是分而治之和团队开发的产物,因此它是一种由许多软件单元组成的“复合组件”。软件架构包含了关于软件系统的重要决策,这些决策涉及到如何将软件系统分解成不同的部分、各部分之间的静态结构关系和动态交互关系。
  上图可以用一句话概括:“作为复合整体的软件系统才有架构,架构规定了系统如何设计的重要决策。”张友生博士就曾指出:“自从软件系统首次被分成许多模块,模块之间有相互作用,组合起来有整体的属性,就具有了体系结构。”非常精辟。
  从图中还看出,软件架构并不是所有的组件内部的设计都不关心,而是仅仅不关心“在架构设计阶段没有必要进一步分解”的软件单元的内部细节;另外也不是要将所有设计决策事无巨细地落实,而是重点关注“重要决策”。
  软件架构设计的决策范围,应该着重放在“影响全局”的设计上,而不是关注所有设计细节。对此,Len Bass等人在《软件架构实践》一书中已经明确指出过:
  架构中包含了关于各元素应如何彼此相关的信息。也就是说,架构必须省略各元素中与交互无关的某些信息。因此,架构首先是对系统的抽象,该抽象去除了不影响它们如何使用、其他元素如何使用、以及如何与其他元素关联或交互的细节。在几乎所有的现代系统中,各元素是通过接口实现交互的,而这些接口又将各元素的细节划分为公有和私有两大类。根据这种划分,架构属于公有部分,而私有部分——即仅与内部具体实现有关的细节——是不属于架构的。
  由此可见,软件系统架构关注的是涉及元素之间如何交互的大局,而必须将局部性的细节忽略。其实,关注大局、把握整体,不仅仅是软件系统架构学科的主题,还是所有系统科学所研究的对象,钱学森就说过:“什么叫系统,系统就是有许多部分组成的整体,所以系统的概念就是要强调整体,强调整体是由相互关联、相互制约的各个部分所组成的。”
  补充:任何复杂整体都有架构?
  其实,任何作为复合整体的复杂事物都可能有架构,比如一本书、一栋建筑物。那本“永不褪色的经典”《如何阅读一本书》中就说:“每一本书的封面之下都有一套自己的骨架(Every book has a skeleton hidden between its boards.)。”
  软件也不例外,任何作为复合整体的软件单元都可以有架构,如图6所示。这听起来似乎有些理论化,所以仅作为“为软件架构找准位置”的补充,但在有些时候,这一观点对我们的软件实践非常有帮助。
  
        图6    任何复杂整体都有架构
  虽然我们最常听到的说法是“软件系统的架构”,但其实未必是完整的软件系统才有架构。在实际的软件实践中,分系统、子系统、甚至组件都需要进行架构设计。仅举几例:

  航空航天领域的系统往往极为复杂,这样一来,总的系统需要配备系统架构师,子系统有时也会分别单独配备架构师。

  著名的用友华表Cell 组件是标准的报表处理ActiveX组件,它提供几百个编程接口。虽然在用户看来它只是“开盒即用”的ActiveX组件,但这样一个提供强大的制表能力、拥有丰富的单元格类型的报表解决方案,当然需要精心的架构设计。
  小结
  至今,软件架构的概念依然没有统一,这对我们的实践造成了不少麻烦。但我们不能“揣着手儿”等待——将软件架构的概念总体上分为组成派和决策派,有利于我们理解软件架构概念的精髓。
  本文还通过“用案例说话”的方式说明了两个架构概念流派虽然角度不同、但却相辅相成。我们既应从“架构=组件+交互”的观点中获益,又应运用“架构=重要决策集”的实践经验,这一点对于软件业界的实践者(而不仅仅是理论研究者)尤其重要。
  现象是多样的,本质是不变的。软件架构概念是多样的,而软件架构的本质是不变的。本文经过对软件组件分解、交互、合成的深入解析,最终完成对软件架构的“定位”,从而更深入地理解软件架构的概念。

  关于作者
  温昱。资深咨询师,CSAI特聘高级顾问,《软件架构设计》作者,松耦合空间(www.ou-he.com)网站创办人。十年系统规划、架构设计和研发管理经验,软件架构思想的传播者和积极推动者。

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部