架构之美
译者:王海鹏
第一章 架构概述
1.1 简介
(1).架构:“建造的艺术或科学;特别是设计和建造人类使用的建筑时的艺术或实践,同时考虑到美学因素和实用因素。”
(2).我们谈到交响乐的“构架”,反过来,又将架构称为“凝固的音乐”。
(3).当代的架构师可以会说,待构建的对象或系统必须具有以下特征:
<1>.具备客户要求的功能;
<2>.能够在要求的工期内安全地构建;
<3>.性能足够好;
<4>.可靠的;
<5>.可用的,并且使用时不会造成伤害;
<6>.安全的;
<7>.成本是可以接受的;
<8>.符合法规标准;
<9>.将超越前人及其竞争者。
1.1.1 建筑师的角色
音乐作曲与软件架构
虽然人们常用建筑架构设计来类比软件架构,但音乐作曲可能是更好的类比。建筑师创建的是相对静止的结构(该架构必须考虑到人员和服务在建筑内的移动,以及承重结构)的静态描述(蓝图或其他图纸)。
在音乐作曲和软件设计中,作曲家(软件架构师)创建一段音乐的静态描述(架构描述和代码),这段音乐以后将演奏(执行)许多次。在音乐和软件中,设计都依靠许多组件的交互来得到期望的效果,结构依赖于演奏者、演奏环境,以及演奏者所做的诠释。
1.1.2 软件架构师的角色
软件架构师的职责:
<1>.建筑师可以回顾几千年的历史,看看过去的建筑师都做过些什么,他们可以参观并研究那些矗立了几百年的建筑,有时甚至有上千年历史的建筑,而它们仍在使用。在软件业,我们只有几十年的历史,并且我们的设计常常是不公开的。
此外,建筑师拥有并利用标准来描述他们制作的图纸和规格说明,这让现在的建筑师能够从记录下来的架构历史中受益。
<2>.建筑是有形的产品,在建筑师制作的规划和工人修造的建筑之间存在着明显的区别。
1.1.3 软件架构的含义
一个程序或计算系统的软件架构是系统的一种结构或一组结构,它包含软件元素,这些元素的外部可见的属性,以及元素之间的关系。“外部可见”的属性是其他元素对该元素可以做出的假定,诸如它提供的服务、执行时的特征、错误处理、共享资源的使用等。
1.1.4 架构与设计
架构是系统设计的一部分,它突出了某些细节,并通过抽象省略掉另一些细节。所以架构是设计的一个子集。关注实现系统组件的开发者可能不会特别关心所有组件如何装配在一起,而是主要关注少数组件的设计和开发,包括他们必须遵守的架构约束和可以应用的规则。因此,开发者和架构师面对的是系统设计的不同方面。
1.2 创建软件架构
(1).软件架构师的首要关注点不是系统的功能。
(2).一个“基于WEB的应用”,你首先问页面布局和导航树,还是问下面这些问题:
<1>.谁提供应该主机托管?托管的环境有什么技术限制吗?
<2>.你想运行在Windows服务器上还是在LAMP栈上?
<3>.你想支持多少并发用户?
<4>.应用需要怎样的安全性?有需要保护的数据吗?应用将运行在公网上还是私有的内部网上?
<5>.你能为这些答案排列优先级吗?例如,用户数是否比响应时间更重要? 根据我们对这些问题和一些其他问题的回答,你就可以画出系统架构的草图。
(3).品质关注点指明了功能必须以何种方式交付,才能被系统的利益相关人所接受,系统的结果包含这些人的既定利益。
成功架构师的两项关键实践:让利益相关人参与以及同时关注功能和品质。作为一名架构师,你首先问我们想从系统中得到什么,有怎样的优先级。在实际项目中,你会找出其他的利益相关人。典型的利益相关人和他们的关注点包括:
<1>.投资人,他们想知道项目是否能够在给定的资源和进度约束下完成。
<2>.架构师、开发人员和测试人员,他们首先考虑的是最初的构建和以后的维护与演进。
<3>.项目经理,他们需要组织团队,制定迭代计划。
<4>.市场人员,他们想通过品质特点实现与竞争者的差异化。
<5>.企业用户,包括最终用户、系统管理员,以及安装、部署、准备、配置人员。
<6>.技术支出人员,他们关注帮助平台电话呼入的数目和复杂性。 每个系统都有自己的品质关注点。有些关注点可能定义得很好,如性能、安全、可伸缩性等。但是,另一些同样主要的关注点却可能没有详细规定,如可变性、可维护性和可用性等。
(4).架构师的第一项任务,就是与利益相关人协作,理解这些品质关注点和约束,并为他们排列优先级。为什么不从功能需求开始?因为通常有许多种可能的系统分解方式。架构师通常必须进行架构层面的系统重构。
(5).架构团队的挑战在于,在创建架构时保持同一种思考方式和同一种哲学。让团队保持尽可能小,让他们在充分沟通、高度协作的环境工作,让一两个“首席架构师”担任仁慈的独裁者,最终做出所有决定。这种架构模式常见于成功的团队,不论是公司开发还是开源开发,由此得到的概念完整性是美丽架构的一种特性。
(6).每个关注点都以问题的方式表述,架构师在项目过程中可能需要考虑它。当然,具体系统会有其他关键的关注点:
<1>.功能性(Functionality) 产品向它的用户提供哪些功能?
<2>.可变性(Changeability) 软件将来可能需要哪些变化?哪些变化不可能发生,不需要特别容易进行这些改变?
<3>.性能(Performance) 产品将达到怎样的性能?
<4>.容量(Capacity) 多少用户将并发使用该系统?该系统将为用户保存多少数据?
<5>.生态系统(Ecosystem) 在部署的生态环境中,该系统将与其他系统进行那些交互?
<6>.模块化(Modularity) 如何将编写软件的任务分解为工作指派(模块),特别是这些模块可以独立的开发,并能够准确而容易的满足彼此的需要?
<7>.可构建性(Buildability) 如何将软件构建为一组组件,并能够独立实现和验证这些组件?那些组件应该复用其他的产品,那些应该从外部供应商处得到?
<8>.产品化(Producibility) 如果产品将以几种变体的形式存在,如何开发一个产品线,并利用这些变体的共性?产品线中的产品以怎样懂得步骤开发?在创建一条软件产品线时,要进行哪些投资?开发产品线中不同变体的选择,预期会得到怎样的回报?特别是,是否可能先开发最小的有用产品,然后再添加(扩展)组件,在不改变以前编写的代码的情况下,开发产品线的其他成员?
<9>.安全性(Security) 产品是否需要用户认证,或者必须限制对数据的访问?数据的安全性如何得到保证?如何抵挡“拒绝服务”攻击或其他攻击?
最后,一个好的架构师会认识到,架构会影响组织机构。
1.3 架构结构
一个好的架构师如何处理这些关注点?我们曾经提到过,需要将系统组织成一些结构,每种结构都定义了特定类型的组件之间的具体关系。架构师的主要关注点就是对系统进行组织,让每种结构有助于解答一个关注点所定义的问题。关键的结构决定将产品划分为组件,并定义了这些组件之间的关系。
1.3.1 信息隐藏结构
<1>.组件与关系:主要组件是一些“信息隐藏模块”,每个模块都是针对一组开发人员的工作指派,每个模块都包含了一种设计决定。如果一项决定可以改变,同时又不影响任何其他模块,我们就说这项设计就是一个模块的秘密。模块间最基本的关系是“整体-部分”关系。
<2>.“整体-部分”结构是层次状的。在这个层次结构的叶节点上的模块不包含可识别的子模块。“包含”结构也是层次状的,因为每个程序都只包含在一个模块之中。“依赖”关系不一定是层次状的,因为两个模块可能互相依赖,要么是这届互相依赖,要么是通过一个较长的“依赖”关系形成的环。请注意“依赖”不应该与后面小节中定义的“使用”混淆。
<3>.信息隐藏结构是面向对象设计方法的基础。如果一个信息隐藏模块设计为一个类,这个类的公有方法就属于该模块的接口。 满足的关注点:信息隐藏结构的设计应该能满足可变性、模块化和可构建性的要求。
1.3.2 使用结构
<1>.组件与关系:信息隐藏模块包含一个或多个程序。当且仅当两个程序共享一个秘密时,它们才属于同一个模块。“使用结构”的组件是一些可以单独调用的程序。只有在相同绑定时间操作的程序之间,我们才考虑形成一种使用结构。首先只考虑运行时操作的程序可能最容易。以后,我们也可以考虑那些编译时或载入时操作的程序之间的使用关系。
<2>.通常大型的软件系统包含太多的程序,这让程序间使用关系的描述不容易理解。在这种情况下,使用关系可以用于程序的组合,如模块、类或包。这样的组合描述丧失了重要的信息,但有助于展示“全局”。
<3>.在某些项目中,系统的使用关系开始并没有完全确定,要到系统实现时才能确定,因为开发者会在实现过程中决定他们使用哪些程序。但是系统的架构师可能在设计时创建一种“允许使用”关系,约束开发者的选择。定义良好的使用结构将创建系统的适当子集,可以用于驱动迭代式或增量式的开发模式。 满足的关注点:产品化和生态系统。
1.3.3 进程结构
(1).组件与关系:信息隐藏模块结构和使用结构是静态的结构,存在于设计时和编码时。现在转向运行时结构,参与进行结构的组件是进程。进程是运行时的事件序列,由程序控制。每个程序都作为一个或多个进行的一部分执行。一个事件序列的执行独立于另一个进程中的事件序列,除非这两个进程彼此同步。
(2).进程是几种不同关系中的组件:
<1>.进程提供工作 一个进程可能会创建工作,该项工作必须由其他进程完成,这种结构在确定系统是否死锁时是很重要的。
<2>.进程取得资源 在动态分配资源的系统中,一个进程可能控制由另一个进程使用的资源,后者必须请求并归还这些资源。
<3>.进程共享资源 两个进程可能共享资源,如打印机、内存或端口等。如果两个进程共享一项资源,就需要通过同步来防止使用冲突。每一种资源可能有不同的关系。
<4>.进程包含在模块中 每个进程由一个程序控制,正如前面提到的,每个程序包含在一个模块中。
因此,我们可以认为进程包含在模块之中。 满足的关注点:性能和容量。
1.3.4 访问结构
系统中的数据可能划分成具有属性的段,如果程序对段中的任何数据拥有访问权,就对该段中的所有数据有了访问权。请注意,为了简化描述,我们应该让段的规模最大化,具体做法是添加一个条件,即如果两个段被同一组程序访问,这两个段就应该合并。 数据访问结构包含两种类型的组件:程序和段。
这种关系被命名“有权访问”,它是程序和数据段之间的关系。如果这种结构让程序访问的权限最小,并且严格执行,我们就认为系统更安全。
满足的关注点:安全性。
1.4 好的架构
(1).我们曾提到,架构师玩的是折中的游戏。对于一组给定的功能需求和品质需求,没有唯一的正确架构和唯一的“正确答案”。我们从经验中得知,应该对架构进行评估,确定它是否满足其需求,然后再投入资金来构建、测试和部署这个系统。
(2).架构评估的两种方式。
<1>.第一种评估方式是确定架构的属性,通常通过建模或模拟系统的一个或多个方面。如性能建模来评估吞吐量和伸缩性,通过失效树模型来评估可靠性和可访问性。其他类型的模型包括复杂性和耦合指标,用于评估可变性和可维护性。
<2>.第二种评估方式,也是最广泛使用的方式,就是通过对架构师提出质询来评估该架构。有许多结构化的质询方法。如:软件架构复查委员会(Software Architecture Review Board,SARB)
(3).质询方法
<1>.质询方法的另一种变体是架构折中分析方法(Architecture Trade-off Analysis Method,ATAM),它寻找架构不能满足品质关注点的风险。ATAM使用了场景分析,每种场景都描述了特定的利益相关人对系统的品质关注点。架构师然后解释该架构如何支持每一种场景。
<2>.主动复审是另一种质询方法,它改变了复审过程的开始方式,要求架构师向复审者提供架构师认为重要而需要回答的问题。然后,复查者利用已有的架构文档和描述来回答这些问题。(可以试试查找“Software Architecture Review Checklist(软件架构复审检查清单)”)。
1.5 美丽的架构
(1).所有前面的方法都有助于我们判断一个架构是否“足够好”---也就是说,是否有可能知道开发者和测试者构建一个系统,并满足系统的利益相关人的功能和质量关注点。“软件架构名人堂”进行“软件产品线名人堂”的条件包括获得商业上的成功、影响其他产品线的架构(其他产品线可能“借用、复制、窃取”这个架构)、拥有足够的文档从而让其他人“不必通过道听途说”就能够理解该架构。
(2).“架构名人堂”或“美丽架构艺术馆”
<1>.架构的实用性。好的架构应该每天被许多人使用。
<2>.架构的可构建性。具有定义良好的使用结构的架构,支持增量式构建,构建的过程是透明的、可见的。
<3>.架构的持久性。好的架构要经得起时间考验,可以预期到变更的需要,允许期望的修改能够容易而有效的进行。
<4>.架构的客户满意度。好的架构要让开发人员、测试人员、使用该软件的客户由衷的高兴。
<5>.架构的概念完整性。架构概念完整性是一项跨越所有领域的特征,一致的架构学习起来更容易、更快,代码更干净,测试集更小。