61阅读

架构之美-架构之美中文版-01

发布时间:2018-03-01 所属栏目:大一中架构

一 : 架构之美中文版-01

当然,这种选择通常不是这么死板。但是,随着系统的规模、复杂度和开发人员数目的增长,这些早期决定以及它们的记录方式将产生越来越大的影响。

我们希望你现在已经理解,如果你的系统要满足其品质要求,架构决定是很重要的,你需要注意架构,有意识地做出这些决定,而不只是“让架构自动出现”。

如果系统非常大,情况会怎样?我们之所以运用“分而治之”这样的架构原则,一个原因就是为了降低复杂性,让工作能够并发进行。这让我们能够创建越来越大的系统。架构本身是否能够分解为多个部分,这些部分是否能由不同的人并行开发?考虑到计算机的架构,Gerrit Blaauw和Fred Brooks断定:

……如果,在采取了所有让任务能够由单人处理的方法之后,架构任务仍然巨大而复杂,不能由一人来完成,那么产品肯定是太复杂了,以致不实用且不应构建。换言之,单个用户必须能够理解计算机的架构。如果计划的架构不能由一个人设计,那它也不能被一个人理解。(1997)

你是否需要理解架构的所有方面,才能使用它?架构会分离关注点,所以在大多数情况下,利用架构来构建或维护系统的开发人员或测试人员,不需要一下面对全部的架构,而是只要面对必要的部分,就能完成指定的功能。这让我们能够创建超出个人可以理解的、更大的系统。但是,在我们完全忽略IBM System/360(最长寿的计算机架构之一)创造者的建议之前,让我们先来看看他们为什么这样说。

Fred Brooks说,概念完整性是架构最重要的特征:“最好是让系统……反映一组设计思想,而不是让系统包含许多好的思想,而这些思想却彼此独立而不协调”(1995)。正是这种概念完整性,让开发者在知道了系统的一部分之后,能够迅速理解系统的另一部分。概念完整性来自于处理问题的一致性,如分解的判据、设计模式的应用和数据模式。这让开发者运用在系统中的一部分工作的经验,来开发和维护系统的其他部分。同样的规

架构概述21

架构之美 架构之美中文版-01

则应用于整个系统各处。[www.61k.com]当我们转向“众系统之系统”时,在集成了这些系统的架构中也必须保持概念完整性。例如,可以选择发布/订阅消息总线这样的架构风格,然后将这种风格统一地应用于“众系统之系统”的系统集成中。

架构团队的挑战在于,在创建架构时保持同一种思考方式和同一种哲学。让团队保持尽可能小,让他们在充分沟通、高度协作的环境工作,让一两个“首席架构师”担任仁慈的独裁者,最终做出所有决定。这种架构模式常见于成功的团队,不论是公司开发还是开源开发,由此而得到的概念完整性是美丽架构的一种特性。

好的架构师通常来自于更好的架构师提供的现场指导(Waldo 2006)。原因之一可能是有一些关注点几乎在所有项目中都会出现。我们已经提到过一些,但这里有一份更完整的清单。每个关注点都以问题的方式表述,架构师在项目过程中可能需要考虑它。当然,具体系统会有其他关键的关注点。

功能性(Functionality)

产品向它的用户提供哪些功能?

可变性(Changeability)

软件将来可能需要哪些改变?哪些改变不太可能发生,不需要特别容易进行这些改变?性能(Performance)

产品将达到怎样的性能?

容量(Capacity)

多少用户将并发使用该系统?该系统将为用户保存多少数据?

生态系统(Ecosystem)

在部署的生态环境中,该系统将与其他系统进行哪些交互?

模块化(Modularity)

如何将编写软件的任务分解为工作指派(模块),特别是这些模块可以独立地开发,并能够准确而容易地满足彼此的需要?

可构建性(Buildability)

如何将软件构建为一组组件,并能够独立实现和验证这些组件?哪些组件应该复用其他的产品,哪些应该从外部供应商处获得?

产品化(Producibility)

22第1章

架构之美 架构之美中文版-01

如果产品将以几种变体的形式存在,如何开发一个产品线,并利用这些变体的共性?产品线中的产品以怎样的步骤开发(Weiss和Lai 1999)?在创建一条软件产品线时,要进行哪些投资?开发产品线中不同变体的选择,预期会得到怎样的回报?特别是,是否可能先开发最小的有用产品,然后再添加(扩展)组件,在不改变以前编写的代码的情况下,开发产品线的其他成员?

安全性(Security)

产品是否需要用户认证,或者必须限制对数据的访问?数据的安全性如何得到保证?如何抵挡“拒绝服务”攻击或其他攻击?

最后,一个好的架构师会认识到,架构会影响组织机构。(www.61k.com)Conway指出,系统的结构会反映构建它的组织机构的结构(1968)。架构师可能会认识到,Conway法则可以反过来应用。换言之,一个好的架构可能对组织机构产生影响,让组织机构发生改变,从而更有效地从该架构构建出系统。

1.3 架构结构

那么,好的架构师如何来处理这些关注点?我们曾经提到过,需要将系统组织成一些结构,每种结构都定义了特定类型的组件之间的具体关系。架构师的主要关注点就是对系统进行组织,让每种结构有助于解答一个关注点所定义的问题。关键的结构决定将产品划分为组件,并定义了这些组件之间的关系(Bass、Clements和Kazman 2003; Booch、Rumbaugh和Jacobson 1999; IEEE 2000; Garlan和Perry 1995)。对于任何产品,都有许多结构需要设计。每种结构都必须单独设计,这样它就表现为一个独立的关注点。在接下来的几节中我们会讨论一些结构,你可以利用它们来考虑前面列表中的关注点。例如,“信息隐藏结构”展示了如何将系统组织成一些工作指派。这种结构也可以用作改变的路线图,展示了建议的改变,以及哪些模块支持这些改变。针对每种结构,我们描述了一些组件及其之间的关系,正是这些组件和关系确定了这种结构。对照前面的列表,我们认为下面的结构是最重要的。

1.3.1 信息隐藏结构

组件与关系:主要组件是一些“信息隐藏模块”,每个模块都是针对一组开发人员的工作指派,每个模块都包含了一种设计决定。如果一项决定可以改变,同时又不影响任何其他模块,我们就说这项设计决定是一个模块的秘密(Hoffman和Weiss 2000,第7章和

第16章)。模块间最基本的关系是“整体-部分”关系。如果“信息隐藏模块A”的秘密是“信息隐藏模块B”的秘密的一部分,那么A就是B的一部分。请注意,必须能够在改变A的秘密的同时,不改变B的其他部分。否则,根据我们的定义,A就不是B的一个子模块。例如,许多架构都有一些虚拟设备模块,它们的秘密是如何与特定的物理设备通

架构概述23

架构之美 架构之美中文版-01

信。[www.61k.com)如果虚拟设备分成不同类型,那么每种类型可能构成该虚拟设备模块的一个子模块,其中每种虚拟设备类型的秘密将是如何与这种类型的设备进行通信。

每个模块都是一份工作指派,包含了一组要写的程序。根据不同的语言、平台、环境,“程序”可以是能在计算机上执行的方法、过程、函数、子程序、脚本、宏或其他指令序列。第二种信息隐藏模块结构是基于程序和模块之间的“包含”关系。如果模块M的一部分工作指派是要编写程序P,那么M就包含P。请注意,每个程序都包含在一个模块中,因为每个程序必然是某些开发人员的工作指派的一部分。

这些程序中的一些可以通过模块的接口来访问,而另一些则是内部的。模块也可能通过接口发生关系。A模块的接口是一组假定,这些假定包括该模块之外的程序可以对该模块做出的假定,也包括该模块中的程序对其他模块的程序和数据结构所做的假定。如果改变B的接口就要求A也发生改变,那么我们就说A“依赖”B的接口。

“整体-部分”结构是层次状的。在这个层次结构的叶节点上的模块不包含可识别的子模块。“包含”结构也是层次状的,因为每个程序都只包含在一个模块之中。“依赖”关系不一定是层次状的,因为两个模块可能互相依赖,要么是直接互相依赖,要么是通过一个较长的“依赖”关系形成的环。请注意,“依赖”不应该与后面小节中定义的“使用”混淆起来。

信息隐藏结构是面向对象设计方法的基础。如果一个信息隐藏模块设计为一个类,这个类的公有方法就属于该模块的接口。

满足的关注点:信息隐藏结构的设计应该能满足可变性、模块化和可构建性的要求。

1.3.2 使用结构

组件与关系:根据前面我们的定义,信息隐藏模块包含一个或多个程序(在上一小节中定义)。当且仅当两个程序共享一个秘密时,它们才属于同一个模块。“使用结构”(UsesStructure)的组件是一些可以单独调用的程序。请注意,程序可以相互调用,或被硬件调用(例如,被一个中断例程调用),调用也可能来自于不同命名空间的程序,如操作系统例程或远程过程。而且,调用发生的时间可以是任何时候,从编译时到运行时。

只有在相同绑定时间操作的程序之间,我们才考虑形成一种使用结构。首先只考虑运行时操作的程序可能最容易。以后,我们也可以考虑那些编译时或载入时操作的程序之间的使用关系。

如果程序B必须存在并满足其规格说明,程序A才能满足其规格说明,我们就说A使用了B。换言之,B必须存在且操作正常,A才能操作正常。使用关系有时候也称为“要求存在正确的版本”。进一步的解释和例子,参见(Hoffman和Weiss2000)的第14章。24第1章

架构之美 架构之美中文版-01

使用结构确定了我们可以构建并测试怎样的工作子集。[www.61k.com]在软件系统的使用结构中,期望的属性是它定义了一种层次结构,这意味着其中不出现环。如果在使用关系中出现环,那么环中所有程序都必须存在且正常工作,才能让其他的程序正常工作。由于也许不能够创建完全没有环的使用关系,架构师可能将使用环中的所有程序作为单一的程序,以这种方法来创建子集。子集必须要么包含全部程序,要么都不包含。

如果在使用关系中没有环,软件采用的就是一种层次结构。在最底层,即第0层,是所有不使用其他程序的程序。第n层包含了所有的程序,它们使用了第n-1层或以下层的程序。这些层常常描绘为一系列的层次,每个层次表示了使用关系中的一个或几个层。在使用结构中对相邻的层分组,有助于简化表示,并允许在关系中出现小环的情况。进行这种分组有一个指导原则,即一个层次中的程序应该比它上一个层次中的程序执行速度快9倍,执行频率高9倍(Courtois1977)。

具有层次使用结构的系统可以同时构造一层或几层。这些层次有时候称为“抽象层”,但这是一种错误的名称。因为这些组件是独立的程序,而不是完整的模块,它们不一定抽象(隐藏)了什么东西。

通常大型的软件系统包含太多的程序,这让程序间使用关系的描述不太容易理解。在这种情况下,使用关系可以用于程序的组合,如模块、类或包。这样的组合描述丧失了重要的信息,但有助于展示“全局”。例如,你有时候可以在信息隐藏模块之间建立使用关系,但是除非一个模块中所有的程序都属于实际使用层次的同一层,否则就会丧失重要的信息。

在某些项目中,系统的使用关系开始并没有完全确定,要到系统实现时才能确定,因为开发者会在实现过程中决定他们使用哪些程序。但是,系统的架构师可能在设计时创建一种“允许使用”关系,约束开发者的选择。今后,我们不会区分“使用”和“允许使用”。定义良好的使用结构将创建系统的适当子集,可以用于驱动迭代式或增量式的开发循环。满足的关注点:产品化和生态系统。

1.3.3 进程结构

组件与关系:信息隐藏模块结构和使用结构是静态的结构,存在于设计时和编码时。我们现在转向运行时结构。参与进程结构的组件是进程。进程是运行时的事件序列,由程序控制(Dijkstra 1968)。每个程序都作为一个或多个进程的一部分执行。一个进程中的事件序列的执行独立于另一进程中的事件序列,除非这两个进程彼此同步,例如一个进程等待来自另一个进程的信号或消息。进程由支持系统分配资源,包括内存和处理器时间。系统可能包含固定数量的进程,也可能在运行时创建和销毁进程。请注意,在

架构概述25

架构之美 架构之美中文版-01

Linux和Windows操作系统中实现的线程也符合这个进程定义。[www.61k.com)进程是几种不同关系中的组件。下面是一些例子。

进程提供工作

一个进程可能会创建工作,该项工作必须由其他进程完成。这种结构在确定系统是否死锁时是很重要的。

61阅读/ www.61k.net

满足的关注点:性能和容量。

进程取得资源

在动态分配资源的系统中,一个进程可能控制由另一个进程使用的资源,后者必须请求并归还这些资源。因为发起请求的进程可能从几个控制器那里请求资源,所以每项资源可能都有一个不同的控制进程。

满足的关注点:性能和容量。

进程共享资源

两个进程可能共享资源,如打印机、内存或端口等。如果两个进程共享一项资源,就需要通过同步来防止使用冲突。每一种资源可能有不同的关系。

满足的关注点:性能和容量。

进程包含在模块中

每个进程由一个程序控制,正如前面提到的,每个程序包含在一个模块之中。因此,我们可以认为进程包含在模块之中。

满足的关注点:性能和容量。

1.3.4 访问结构

系统中的数据可能划分成具有属性的段,如果程序对段中的任何数据拥有访问权,就对该段中的所有数据拥有了访问权。请注意,为了简化描述,我们应该让段的规模最大化,具体做法是添加一个条件,即如果两个段被同一组程序访问,这两个段就应该合并。数据访问结构包含两种类型的组件:程序和段。这种关系被命名“有权访问”,它是程序和数据段之间的关系。如果这种结构让程序访问的权限最小化,并且严格执行,我们就认为系统更安全。

满足的关注点:安全性。

1.3.5 结构小结

表1-1总结了前面的软件结构,包括它们的定义和它们满足的关注点。

26第1章

架构之美 架构之美中文版-01

表1-1:结构小结

结构

信息隐藏组件信息隐藏模块关系整体-部分

包含

使用

提供工作

取得资源

共享资源

包含在模块中

……

有权访问关注点可变性模块化可构建性产品化生态系统性能可变性容量使用进程程序进程(任务、线程)数据访问程序和数据段安全性

生态系统

1.4 好的架构

我们曾提到,架构师玩的是折中的游戏。[www.61k.com]对于一组给定的功能需求和品质需求,没有唯一的正确架构和唯一的“正确答案”。我们从经验中得知,应该对架构进行评估,确定它是否满足其需求,然后再投入资金来构建、测试和部署这个系统。评估试图回答前面小节中讨论的一个或多个一般关注点问题,或回答特定系统的具体关注问题。

架构评估有两种常见的方式(Clements、Kazman和Klein 2002)。第一种评估方式是确定架构的属性,通常通过建模或模拟系统的一个或多个方面。例如,通过性能建模来评估吞吐量和伸缩性,通过失效树模型来评估可靠性和可访问性。其他类型的模型包括复杂性和耦合指标,用于评估可变性和可维护性。

第二种评估方式,也是最广泛使用的方式,就是通过对架构师提出质询来评估该架构。有许多结构化的质询方法。例如,贝尔实验室提出的软件架构复查委员会(SoftwareArchitecture Review Board,SARB)过程利用了组织机构之内的专家,以及他们在电信和相关应用中的深厚领域经验(Maranzano等2005)。

质询方法的另一种变体是架构折中分析方法(Architecture Trade-off Analysis Method,ATAM)(Clements、Kazman和Klein 2002),它寻找架构不能满足品质关注点的风险。ATAM使用了场景分析,每种场景都描述了特定的利益相关人对系统的品质关注点。架构师然后解释该架构如何支持每一种场景。

主动复审是另一种质询方法,它改变了复审过程的开始方式,要求架构师向复审者提供架构师认为重要而需要回答的问题(Hoffman和Weiss 2000,第17章)。然后,复查者利

架构概述27

架构之美 架构之美中文版-01

用已有的架构文档和描述来回答这些问题。(www.61k.com)最后,在网络上查找“software architecturereview checklist(软件架构复审检查清单)”,可以得到几十份检查清单,其中某些清单非常通用,另一些则是针对具体的应用领域或技术框架。

1.5 美丽的架构

所有前面的方法都有助于我们判断一个架构是否“足够好”—也就是说,是否有可能指导开发者和测试者构建一个系统,并满足系统的利益相关人的功能和质量关注点。在我们每天使用的系统中存在着许多好的架构。

但是,超越足够好的架构是怎样的呢?如果有一个“软件架构名人堂”,那会怎样?哪些架构会陈列在这个艺术馆的墙上?这个想法可能没有你想象的那么遥远—在软件产品线领域,这样的“名人堂”的确存在。(注1)进入“软件产品线名人堂”的条件包括获得商业上的成功、影响其他产品线的架构(其他产品线可能“借用、复制、窃取”这个架构)、拥有足够的文档从而让其他人“不必通过道听途说”就能够理解该架构。我们将为更一般的“架构名人堂”或“美丽架构艺术馆”的候选者设立怎样的条件呢?首先我们应该认识到,这是一个软件系统的艺术馆,而不是其他艺术馆,我们的系统构建的目的是为了使用。所以,我们也许从一开始就应该关注该架构的实用性:它应该每天被许多人使用。

但是,在使用架构之前,它必须先构建,所以我们应该关注该架构的可构建性。我们会寻找那些具有定义良好的使用结构的架构,它们支持增量式构建,这样,通过每次构建迭代我们都能得到一个有用的、可测试的系统。我们也会寻找那些具有定义良好的模块接口、本来就很好测试的架构,这样,构建的过程就是透明的、可见的。

接来下,我们想寻找那些展示了持久性的架构—也就是说,那些经过了时间考验的架构。我们生活在一个技术环境以从未有过的加速度变化的年代。美丽的架构应该预期到变更的需要,允许期望的修改能够容易而有效地进行。我们想寻找那些避免了“衰老地平线”(Klein 2005)的架构,超过了这条“衰老地平线”,维护将变得代价极大,以至于不可能进行。

最后,我们还想寻找这样一些架构,它们的特征让使用、构建、测试这些架构的开发人员和测试人员,以及由它而形成的系统的用户感到由衷的高兴。为什么开发人员会高兴?因为它让他们的工作变得容易,而且更有可能得到一个高品质的系统。为什么测试人员会高兴?作为测试过程的一部分,他们必须尝试模拟用户的行为。如果他们高兴,28第1

架构之美 架构之美中文版-01

架构之美 架构之美中文版-01

可能用户也会感到高兴。[www.61k.com]如果厨师对他的烹调的菜品感到不高兴,那么品尝这些菜品的顾客也可能会感到不高兴。

不同的系统和应用领域为这些架构提供了许多机会,展示它们特有的令人高兴的特征,但概念完整性是一项跨越所有领域的特征,并且总是让人感到高兴。一致的架构学习起来更容易、更快,当知道了一点之后,你就可以开始预测其余的部分。不需要记住并处理特殊的情况,代码更干净,测试集更小。一致的架构不会为做同一件事情提供两种(或更多)方法,不会让用户浪费时间进行选择。正如Ludwig Mies van der Rohe所说的,好的设计,“少即是多”。爱因斯坦可能会说,美丽的架构就是尽可能简单,但不要过于简单。有了这些判别条件,我们推荐第一批进入“美丽架构艺术馆”的候选者。

第一个是A-7E舰载飞行处理器(Onboard Flight Processor,OFP)的架构,它由海军研究实验室(Naval Research Laboratory,NRL)在20世纪70年代后期开发,在(Bass、Clements和Kazman 2003)有介绍。尽管这个系统从未实现量产,但它满足了所有其他的判别条件。这个架构对软件架构的实践曾经产生了巨大的影响,它展示在真实世界的系统中,将设计时的信息隐藏模块和使用结构与运行时的进程结构分离。因为美国政府资助并开发了这个架构,所以所有项目文档都提供给了公共领域。(注2)这个架构具有定义良好的使用结构,促进了系统的增量式构建。最后,信息隐藏模块结构为分解系统提供了清晰一致的准则,实现了很强的概念完整性。作为嵌入式系统软件架构的榜样,A-7E OFP当然属于我们的艺术馆。我们想放入艺术馆的另一个架构是朗讯5ESS电话交换机的软件架构(Carney等1985)。5ESS取得了全球范围的商业成功,为世界各国的网络提供了核心电话网络交换。它成为性能和可靠性的标准,每个单元每小时能处理超过100万次的连接,平均每年非计划宕机时间少于10秒钟(Alcatel-Lucent 1999)。该架构的一些统一概念,如管理电话连接的“半通话模型”,已经成为电话和网络协议领域的标准模式(Hanmer 2001)。除了保持必须处理的通话类型的数目为2n(其中n是通话协议的数目)之外,半通话模式还在操作系统的进程概念和电话的通话类型概念之间建立起了联系,从而提供了简单的设计原则,引入了漂亮的架构一致性。在过去的25年中,开发团队涉及多达3000个人,他们发展并增强该系统。基于它的商业成功、持久性和影响,5ESS架构是我们艺术馆的一件好藏品。还有一个我们想放入美丽架构艺术馆的系统,它就是万维网(World Wide Web,WWW)的架构。它由Tim Berners-Lee在CERN创建,在(Bass、Clements和Kazman 2003)中有介绍。万维网当然已经取得了商业上的成功,它转变了人们使用因特网的方式。即使创建了新的应用、引入了新的功能,它的架构仍然保持不变。该架构的整体简单性促成架构概述

架构之美 架构之美中文版-01

29

架构之美 架构之美中文版-01

了它的概念完整性,但有一些决定导致了该架构的完整性保持不变,如客户端和服务器端使用同一个库,创建分层架构以实现分离关注点等。[www.61k.com)核心万维网架构的持久性和它对新扩展、新功能持续支持的能力,使它当之无愧地进入了我们的艺术馆。

什么是建筑师?

夏天很热的一个日子里,一个外乡人沿着一条路在行走。他走着走着,来

到一个人跟前,此人正在路边敲碎石头。

“你在做什么?”他问那个人。

那个人抬头看着他;“我在敲碎石头。你以为我看起来像在干什么?现在

不要妨碍我,让我继续干活。”

这个外乡人继续沿着路走,不久他遇到了第二个在大太阳下敲碎石头的人。

这个人正努力工作,汗滴如雨。

“你在做什么?”外乡人问道。

这个人抬头看他,露出微笑。

“我在为谋生而工作,”他说,“但这个工作太辛苦了。也许你能给我一份更

好的工作?”

外乡人摇了摇头,继续前行。没多久,他遇到了第三个敲碎石头的人。太

阳正是最炙热的时候,这个人非常卖力,汗流如注。

“你在做什么?”外乡人问道。

这个人停了一下,喝了一口水,微笑着抬起他的手,指向天空。

“我在建一座大教堂。”他喘着气说。

外乡人看了他一会儿,说:“我们正打算开一家新公司。你来做我们的总建

筑师怎么样?”

我们的最后一个例子是UNIX系统,它展示了概念完整性,使用广泛,拥有巨大的影响力。管道和过滤器的设计是讨人喜欢的抽象,允许我们快速构建新的应用。

在描述架构、架构师的角色和创建架构时的考虑等方面,我们已经谈了很多,我们也简单介绍了一些美丽架构的例子。接下来我们邀请你阅读后续章节中详细的例子,这些例子来自于那些技艺精湛的架构师,本书介绍了他们创建并使用过的那些美丽架构。致谢

David Parnas在几篇论文中定义了我们描述的许多结构,其中包括他的“术语滥用”论文(Parnas 1974)。Jon Bentley为这本书提供了创作灵感,他和Deborah Hill、MarkKlein对早期的草稿提出了许多有价值的建议。

30第1章

架构之美 架构之美中文版-01

参考文献

Alcatel-Lucent. 1999. “Lucent’s record-breaking reliability continues to lead the industryaccording to latest quality report.”Alcatel-Lucent Press Releases. June 2. http://www.alcatel-lucent. com/ wps/ portal/ News Releases/ DetailLucent? LMSG_CABINET= Docs_and_ Resource_Ctr&LMSG _CONTENT_FILE=News_Releases_LU_1999/LU_News_Article_007318.xml (accessed May 15, 2008). Bass, L., P. Clements, and R. Kazman. 2003. Software Architecture in Practice, SecondEdition. Boston, MA: Addison-Wesley.

Blaauw, G., and F. Brooks. 1997. Computer Architecture: Concepts and Evolution. Boston,MA: Addison-Wesley.

Booch, G., J. Rumbaugh, and I. Jacobson. 1999. The UML Modeling Language User Guide.Boston, MA: Addison-Wesley.

Brooks, F. 1995. The Mythical Man-Month. Boston, MA: Addison-Wesley.

Carney, D. L., et al. 1985. “The 5ESS switching system: Architectural overview.”AT&TTechnical Journal, vol. 64, no. 6, p. 1339.

Clements, P., et al. 2003. Documenting Software Architectures: Views andBeyond. Boston,MA: Addison-Wesley.

Clements, P., R. Kazman, and M. Klein. 2002. Evaluating Software Architectures. Boston:Addison-Wesley.

Conway, M. 1968. “How do committees invent.”Datamation, vol. 14, no. 4.

Courtois, P. J. 1977. Decomposability: Queuing and Computer Systems. New York, NY:Academic Press.

Dijkstra, E. W. 1968. “Co-operating sequential processes.”Programming Languages. Ed.F. Genuys. New York, NY: Academic Press.

Garlan, D., and D. Perry. 1995. “Introduction to the special issue on software architecture.”IEEE Transactions on Software Engineering, vol. 21, no. 4.

Grinter, R. E. 1999. “Systems architecture: Product designing and social engineering.”Proceedings of ACM Conference on Work Activities Coordination and Collaboration(WACC '99). 11-18. San Francisco, CA.

Hanmer, R. 2001. “Call processing.”Pattern Languages of Programming(PLoP). Monticello, IL.http://hillside.net/plop/plop2001/accepted_submissions/PLoP2001/rhanmer0/PLoP2001_rhanmer0_1.pdf.

架构概述31

架构之美 架构之美中文版-01

Hoffman, D., and D. Weiss. 2000. Software Fundamentals: Collected Papers by David L.Parnas. Boston, MA: Addison-Wesley.

IEEE. 2000. “Recommended practice for architectural description of software intensivesystems.”Std 1471. Los Alamitos, CA: IEEE.

Klein, John. 2005. “How does the architect's role change as the software ages?”Proceedings of the 5th Working IEEE/IFIP Conference on Software Architecture (WICSA).Washington, DC: IEEE Computer Society.

Maranzano, J., et al. 2005. “Architecture reviews: Practice and experience.”IEEESoftware, March/April 2005.

Parnas, David L. 1974. “On a buzzword: Hierarchical structure.”Proceedings of IFIPCongress. Amsterdam, North Holland. [Reprinted as Chapter 9 in Hoffman and Weiss (2000).] Waldo, J. 2006. “On system design.”OOPLSA '06. October 22-26. Portland, OR.

Weiss, D., and C. T. R. Lai. 1999. Software Product Line Engineering. Boston, MA:Addison-Wesley.

32第1章

二 : 老司机带路 Tech Minds第二期 破解运维与架构之美

  运维乃IT之本。又拍云以“运维与架构之美”为主题的第二期Tech Minds日前在广州举办。Tech Minds,定位高端技术领导人私享会,邀请国内优秀互联网企业的CTO、技术VP、运维总监及有技术背景的CEO等技术领导者齐聚一堂,彼此交流与分享,共同打造一场围绕技术话题的交流与学习的全干货的社交聚会。作为10~15位嘉宾规模的小型“私享”会,Tech Minds不仅关注技术,同时关注管理,“老司机们”分享的经验教训一定能让你有所启发。本期Tech Minds讲师(老司机)为又拍云运维总监邵海杨及优维科技DevOps管理专家王津银,从架构设计和协同管理的角度诠释运维的经验启示。

  又拍云运维总监邵海杨率先分享了在云运维领域的多年心得,他表示,互联网运维主要要解决三大挑战:高并发、高可用性、快响应。

  从可用,到用好,再到好用

  互联网运维或云运维难免要经历几大阶段,第一个是机器从少变多,这个阶段遇到的挑战就是业内较火的自动化部署,也叫作高效运维,实现服务器轻松部署。第二个是监控的体量从小变大,如果只有几十台机器的时候,用一台电脑,单屏或多屏就可以完成,可是当面对3000台机器、几十万的监控项的时候,就需要用一些其他的工具,比如说又拍云正在用的小米的监控、分布式的zabbix, ELK大数据日志监控等等。第三点,性能要求由慢到快,随着负载增大,应用复杂,要想把服务器的潜力性能全部挖掘出来。这个阶段对运维人员的经验、开发的内功要求都会很高。

  根据又拍来自身的运维发展史,从“可用”,到“用好”,现在现在往“好用”的方向前进。“过度的优化就是毁灭”,邵海杨表示,运维的艺术一定是审时度势,在合适的时间,用合适的资源去完成合适的事情,做到弹性可控。

  如果在这个进化过程中,不把握好节奏和协调性,自动化部署时机器虽然增加了,但是监控不到位,这个时候就会失控,好事也会变成灾难,所以,除了有加速器还要有刹车机制。邵海杨总结道:“在运维的道路上,一是弹性可控,二是恰到好处,过度设计,过早优化取决于公司的综合条件。”

  运维的法宝,三位一体

  面对运维、监控、性能三个方面,邵海杨分享了三大法宝:运维自动化、监控常态化、性能可视化。

  

 

  首先是运维自动化。运维的自动化是基础,又拍云现在已经过了运维自动化这个阶段。我们会通过一些工具把工作做自动化、流程化。又拍云的4000多台机器,绝大多数都是自有采购的,会要求服务器厂商根据我们的需求做一些定制,如将又拍云自有的嵌入式系统烧进去,出厂时直接发往机房。因此,就算业务扩展非常忙的时候,都没有发生过几十台机器在公司上电,部署系统,打包发货的情况,服务器直接从产线发到机房,连上网络,就可以对服务器进行远程控制,甚至做系统整体升级。

  第二点是监控常态化。不同的阶段它其实有很好的一些工具会出现。比如早几年前没有ELK,只能靠Zabbix这样的工具,现在的zabbix监控,我们会根据不同的运营商分配不同的节点,构建分布式的监控系统。

  第三点性能可视化。性能可视化主要是提供一个延续的健康报表,争取内部资源。很多运维又苦又累,其实苦于没有过多的资金,也没有过多的人力,但在业务发展期,又需要运维保证设备负载稳定,这是一个非常矛盾又现实的问题,而专业术语老板听不懂,这样就更不容易获得资源支持。因此,可以提供一些数据报表,便于老板理解,从而争取资源。

  邵海杨认为好的运维架构师,绝对不会局限于运维这个专业领域,而是要像优秀的销售一样,能够说的漂亮,抓住老板和开发人员的焦点和共鸣之处,也要写的生动,利用数据可视化的工具,生成浅显易懂的图表,争取资源,敢赌敢拼的精神,运维往往是背锅侠和接盘侠的化身,但是如果能够抓住机会改变,就是成功逆袭.

  让机器像人一样有感知

  邵海杨从事运维管理多年,在Tech Minds上,邵海杨分享道:“运维的指导思想,就是让人像架构一样扩展。”运维人熟知web如何扩展,数据库如何读写分离,动静分离,层层缓存等等,其实在管理运维团队的时候,也是要像架构一样可扩展,从而避免失控。

  第一要做到与人无关,是人总会犯错,受情绪影响总会误操作,但是机器不会。所以尽量能用机器生成的方式就不要浪费人力,能够将变化的东西固化成一个流程。要做到不管是谁操作,无论操作了多少次,出来的结果仍然是一样的。

  第二个,就要与己无关。当做到“与人无关”的时候,还要做好培训和工具。这样的话即便某个人不在,至少有后备的人员在,相当于人员的backup。

  第三个,就是与状态无关。大家都知道web的扩展性最强,就是因为它是无状态的,可以通过前端加一个负载均衡做到水平扩容,所以,要把有状态的东西变成无状态,就要利用好消息队列和各种中间件如rabbitmq/kafka/redis等。

  第四个,与数量无关,部署要恒定。就像把操作系统固化以后,无论一天上多少个节点,每天部署多少次,都不受影响。

  最后,海杨的分享有没有get到你呢?关注Tech Minds,收获你的技术干货。

三 : 架构之路(二):性能

我们在上一篇博客中设定了架构的目标,只有一个,就是可维护性。(www.61k.com)完全没有提性能,这是故意的。

似乎程序员都是急性子,或许是被windows冗长的开机时间折磨够了,有可能是因为提升性能的效果是最显而易见的……总之,我发现,绝大部分程序员对性能的关注和热情是无与伦比的!

  • C#刚刚推出的时候,就有人摇头晃脑的说,“嗯,自动垃圾回收,性能不行吧?”
  • DataSet横空出世,马上有很多人写代码,在DataSet里插入几百万条数据,证明DataSet的性能问题
  • Linq当然更要被骂了,尼玛用反射?反射是什么,同学们知道么?性能大老虎呀!更不用说那些自动生成的sql了,有我手写的高效么?
  • ……

所以直到今天,我仍然看到很多程序员无怨无悔的用存储过程来构建他们的系统,一个存储过程可以有几千行!然后,他们很无辜的问,“业务层有什么用?究竟能干些什么呢?”

在带团队的时候,我最怕讲的就是性能有关的问题。你要是不谈性能呢,那代码有时候真心看不下去;你要是强调性能呢,不知道他会给你整出什么幺蛾子出来。其实这就是一个“度”的掌握,所以非常难以用语言予以表示清楚。所以无数次挫败之后,我只好咬牙切齿的说,“你的代码,只有一个评判标准,可维护性。性能的问题先不管!”这个答案似乎并不能服众——尤其是对有上进心的程序员而言。

所以,我先专篇讲性能,希望能帮助大家更清楚的认识这个问题。

一、性能不是不重要,而是他没有可维护性重要。要理解这一点,首先要理解可维护性的重要(请再读上一篇我花数周找bug的段子);然后要明白:解决性能问题,我们可以有很多代码以外行之有效的方法,而可维护性基本上就只能靠代码了;最后,还是要牢记:没有牺牲,就没有胜利!

二、所以,在绝大多数情况下,当性能和可维护性相冲突的时候,性能让位于可维护性。我们采用其他办法来弥补代码性能不够高的问题。

空洞的说教没有意义。我们还是举例来说明吧!

破坏可读性

前段时间我review代码的时候发现,这个程序员用Linq之后老是用First()而不是Single(),我就奇怪了,按业务逻辑,返回的值就应该是一个,难道可能会是多个,多个应报异常,不应该取First()就完事了呀?想了一会儿,问这个程序员,他的回答让我瞬间一种无力感,“First()性能更高呀!”以下为对话实录:

“你怎么知道First()性能更高呢?”我问。

“First()嘛,取了第一个合格的值就返回,就不会继续查下去了;Single()的话,就会一直查,查出所有数据,然后再取其中的一个。”

“你确定?你知道有一种东西叫做索引不?”

“啊?……”

然后我简单的告诉他,索引是一种树状结构,可以让查询更快等等。

“但我还是觉得应该用First()”,他想了一会儿,还是很坚定。

“为什么?”,我不明白了。

“就算有索引加快了查询速度,但用First()在加快了速度上更快呀!更快总是没错的吧?”

“……”,我真不知道该怎么说了,最后突然灵光一闪,“好吧,那你说说,微软为什么要搞一个Single()方法出来呢?就为了搞出来误导你们?让用First()的产生优越感,嘲笑用Single()的?”

他陷入了沉思。

评论里还在纠结Single()/First()的同学,请大声的吼三遍:可读性!可读性!!可读性!!!

发现同学们还在纠结这个细节。好吧,再解释一下:

1、你怎么知道数据库用的就是MSSQL呢?你怎么知道就是用的关系数据库呢?NoSQL不行么?所以,你怎么就知道Single()/First()具体是怎么执行的呢?比如我就要写个Linq实现,把所有的数据全取出来,然后再在内存里排序,最后取First呢?

2、这里我们考虑可读性,意思是:读代码时,看到Single()就能瞬间知道coder的意思是取唯一的一个;看到First()就知道coder的意思是要取第一个。和性能没关系,如果一定要纠缠性能,那好:你要确定唯一性,当然要做检查(包括不唯一时抛异常),这个性能损失是应该的呀;你要取第一个,当然要进行排序,排序也会有性能损失呀!

我刚入行的时候,还很是收藏了几篇文章,比如《高性能编程的十大准则》之类的,里面的内容大致就是,“总是使用StringBuilder,不要使用‘+’;总是使用……,不要使用……”。这类文章下面总是有一堆人叫好,“不错!”,“谢谢分享!”但慢慢的,我就对这些文章产生了怀疑(也应该感谢园子里的老赵,csdn里面的sp1234之类的大神);直到很后来,我才明白为什么这种说法是肤浅的;而只有通过上面的对话,我才能清晰的把我的理解说出来。

所有这些牺牲性能的简单封装,都是有其目的的;而其中一个很重要的目的,就是为了提高可读性。你为了性能,故意不使用这些现成的封装,通常,丧失的就是可读性。

想当然

继续上面这个例子。最开始的时候,这个程序员关于性能的考虑其实是想当然的。这种想当然的情形很多,大致有这几种:

  1. 自己的理解完全就是错的
  2. 自己的理解不能算错,但实际上底层已经对该问题做了优化
  3. 自己的理解没错,底层也没优化

第1、2种比较好理解,第3种为什么也说他“想当然”呢?因为没有和硬件环境相契合。

最简单的例子就是“缓存”。比如面试的时候,问你一个问题,“缓存能不能提高性能?”请注意,这是一个陷阱。答案应该是:“不一定”。几乎所有的人都认为,缓存可以迅速改善性能,是因为今天计算机的CPU和磁盘运行速度,远跟不上内存的发展。但即使如此,无节制的缓存,一样可以拖垮整个系统。

类似的例子还有很多。你沾沾自喜,我节约了一次磁盘读写的时候,你同时增加了CPU的负荷;你优化了算法,减少了CPU的运算,但其实增加了内存的压力……天下没有免费的午餐。同样的代码,随着数据的增加,硬件的改变,会呈现出截然不同的性能表现。

所以,开发过程中,很多的“优化”,其实只是你的想当然。与其这样想当然的优化,不如在拿到性能测试结果之后再有的放矢的进行优化。这时候,又回到了我们之前说的,是不是代码的可读性更重要?这样你才能迅速的找到该优化的瓶颈啊!否则,一堆乱七八糟看都看不懂的代码,你怎么去优化,你连该优化的点都找不到。

难以维护

另一个搞笑的例子是关于我自己的。创业家园项目里有一个功能:显示博客正文的同时提供一个上一页下一页的链接。惯常的做法就是直接在数据库里查就是了,但我总觉得不对,这样做两次查询有必要么?能不能优化?于是我想到了一个“绝妙”的点子:为什么不直接在博客里存储上一篇和下一篇的Id呢?这样我一次性数据往返就能取到所有数据了嘛!各位同学是不是觉得我这个主意很棒?

噩梦由此开始了。

首先,我们是想在发布博客的时候,设置他的上一篇和下一篇。但是,上一篇好设置,下一篇呢?还没有啊!怎么弄,就只好在博客发布的时候,设置他的前一篇,同时设置他前一篇的后一篇。

然后,我们新添加了一个功能,除了上一篇下一篇以外,还需要在当前博客所在分类中的上一篇和下一篇。怎么办?再加字段呗。所以,博客里就有了Previous, PreviousInCategory, Next, NextInCategory。这时候,就感觉到有点不妥,但还可以接受。

接着,出现了一个问题,上一篇下一篇博客被删除了,怎么办?这个过程,就相当于从一个双向链表里移出一个节点一样麻烦。头开始有点大了。

再接着,博客除了发布删除以外,还有各种其他状态,比如被屏蔽。而且被屏蔽之后,能否显示和当前用户又有关系。当前用户是普通用户,不能阅读;当前用户是作者自己,就能够阅读。怎么办?首先,屏蔽的时候,要设置上一篇下一篇;屏蔽取消的时候,还是要设置上一篇下一篇。然后,上一篇下一篇得根据当前用户不同变化的这个问题,基本上就傻眼了……

最后流着泪把辛辛苦苦折腾了好久的代码全改回来,就通过数据库查呗,多么清晰简洁的逻辑啊!性能问题?首先,这样做造成了性能问题么?然后,就算有问题,用一个缓存能解决不?

合理浪费堆硬件

说了这么多,不知道有没有引起同学们的反思。可能大家还是过不去心里那道坎:明明有一种性能更高的方法我们为什么不用?

因为浪费呗!

什么?你有没有搞错?我的代码,至少省了一块内存条!那是你还没从“穷学生”的角色里转换过来。你花一周的时间对代码进行了优化(就先不考虑你的优化带来的维护成本增加了),为老板省下了一块内存条的钱。你以为老板会拍着你的肩膀表扬你么?老板打不死你!

兄弟,账不是你那样算的。当你是学生的时候,你的时间成本是0;但你进入工作岗位,每一天都是要发工资的。

通过代码来调高性能,是一种无奈——对硬件性能不够的妥协(参考:80年代游戏开发者的辛苦困境。这样写性能就高,但为什么现在没有谁再这么写代码了?)。否则,绝大多数情况下,堆硬件比优化代码的效果好得多,而且便宜得多。硬件的成本按摩尔定律往下降,我们程序员的工资也能按摩尔定律减么?

明明window 10 比window 95更耗性能,为什么今天没人用window 95?为什么VS 2013要10G的空间我们都还屁颠屁颠的赶紧装上?为什么现在大家都用C#,没人用汇编?我们站在人类文明积累的今天,就应该理所当然的享受这一切成果。有打火机你不用,你要钻木取火。如果你是因为要学贝爷荒野求生装逼,可以理解;如果你说你是因为怕浪费天然气,我……我……我怎么说你呢?“给做打火机的一条活路,行不?”同样的,程序员大神同学,你就当做好事,给下面写底层做硬件的一条活路吧!你的代码都是010001000010000001010101……了,你让其他人怎么活啊?

最后,我突然想到的一个程序员为什么对性能如此敏感疯狂,对可维护性毫不在意的一个可能原因:

  • 性能很好理解,卡得要死和跑得飞快;可维护性很不好理解,至少得跑个两三年才能体现,那时候,谁知道爷在哪里偷着乐呢
  • 性能上不来,程序员只有羞愧的低着头,都是我的错;需求有变更,开口就骂,“哪个SB又要改……”;

大家觉得是不是这样的?所以,愿意把代码百炼成钢绕指柔的人少。想来,是一种莫名的悲哀和凄凉。

最后最后,有一些我能想到的名言警句供大家参详:

  • 过早的优化是万恶之源
  • 优化首先需要找到性能“瓶颈”。否则,任何人都可以随手一指,“这段代码需要优化”。
  • 可读性更强的代码总是更好优化
  • 硬件永远比软件便宜

忘了说我的项目了。目前主要集中在创业家园项目的开发上,正试图从svn转成git源代码控制。不太懂Git,说起来都是泪,懂的同学帮帮忙吧!

本文标题:架构之美-架构之美中文版-01
本文地址: http://www.61k.com/1149148.html

61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1