架构的概念
在软件行业,架构的概念一直没有一个完整、统一的定义,软件架构的概念分为主要量大派别:组成派和决策派。组成派认为软件架构是:软件系统的架构将系统描述为计算组件及组件之间的交互,“组件”是广泛意义上的元素,并不是指具体的技术组件。组成派的定义关注架构实践中的客体——软件,以及软件本身为描述对象;另外分析了软件的组成,即软件由承担不同计算任务的组成组件,这些组件通过相互交互完成更高层次的计算。而决策派认为,软件架构保护了软件设计过程中一些列问题的重要决策,软件架构并不仅仅关注软件本身的结构和行为,还注重其他特性:使用、功能、性能、弹性、重用、可理解性、经济、和计算限制、权衡、以及美学等。决策派的定义更关注架构实践中的主体——人,以人的决策为描述对象,并且归纳了架构决策的类型,指出架构决策不仅包括关于软件系统的组织、元素、子系统和架构风格等几类决策,还包括关于众多非功能需求的决策。
说的更通俗一点,组成派关注架构的结果,而决策派关注架构的过程。而笔者认为,架构的是一个演进的过程,没有一成不变的架构,也没有一蹴而就的架构,架构需要根据业务的发展而进行相应的调整,所以我们应该更加关注架构演进的过程和原因,以及在当时背景下的做出的权衡和妥协。没有完美的架构,架构也没有一个标准的解决方案,因为面对不同的业务需求,面对不同的客观因素,有不同的架构设计方案,也就是有不同的设计决策。组成派和决策派的架构概念并不矛盾,它们只不过是所站的角度不同罢了:在具体的软件架构实际中,总是同时体现这两“派”的架构概念。
架构决策是分层次依次展开的,决策制定的顺序往往是先制定技术无关的决策,后制定技术相关的决策,后者在前者的指导下进行。架构师一定要考虑更多的实际开发中要涉及到的技术问题,从而不断细化架构方案,这样才能为开发人员提供更多的指导和限制,也才能真正降低后续开发中的重大技术风险。所以,架构师的架构方案不是高来高去的,而是需要能够落地的,并且在落地的过程中遇到的技术细节问题,架构师是需要参与解决的。这样架构师才能与开发人员无缝对接,架构方案才能指导开发人员进行开发。
子系统、框架和架构
好的架构必须使每个关注点相互分离。把变化点错落有致地封装到软件系统的不同部分(笔者感悟:封装的思想在软件工程中,无处不在啊!),为此,必须进行关注点分离。通过关注点的分离来达到“系统中的一部分发生了变化,不会影响其他部分”的目标。可以通过如下的一下手段:
1、 通过职责划分来分离关注点。面向对象设计的关键所在,就是职责的识别和分配。无论是对象、模块,还是子系统,它们所承担的职责都应该具有高内聚性,否则对象之间的松耦合性就失去了基础,成为空谈。所以我们一直在提“高内聚、低耦合”,高内聚才是低耦合的基础。而我们经常使用的设计模式和架构模式为特定上下文中重复出现的问题提供了通用的职责划分方案,也是问题解决方案。
2、 利用软件系统各部分的通用性的不同进行关注点分离。不同的通用程度意味着变化的可能性不同。这一点与面向对象设计里面的重用发布等价原则异曲同工。
3、 先考虑大粒度的子系统,而暂时忽略子系统是如何通过更小粒度的模块和类组成的。避免陷入过多的细节当中,所谓“忘却是一种能力”,就是指架构师必须有在更高层面思考的能力。
根据职责分离关注点、根据通用性分离关注点、根据不同粒度级别分离关注点是3种位于不同“维度”的思维方式,我们可以综合运用这些手段。
无论是架构模式还是设计模式,重点关注的都是如何提供一个“协作模型”,这个协作模型通过明确协作中不同的角色锁担任的职责,达到“为特定上下文的问题提供解决方案”的目的。
框架技术有助于把通用关注点和专用关注点分离开来,结果是带来了更好的易修改性和可重用性。
作为架构师,必须思考“软件单元是如何组成粒度更大的整体的”这一问题。类、模块、子系统、系统、集成系统,都是软件单元的具体形态,只不过粒度不同罢了。软件系统越复杂,不同粒度的分解层次就越多。这里所谓的系统,是指由多个元素组成的逻辑实体,它完成一组特定的目标或负担一定的职责。系统可以仅包含软件,也可以仅包含硬件,或者两者都包含。子系统是特殊的系统,只不过在特定的上下文中,这个系统作为更大系统的一部分出现。系统需要架构设计,而子系统如果足够复杂,则也需要架构设计。而不同类型的软件系统需要不同的软件架构设计,一个系统的不同子系统也应当有不同的软件架构。
当然,一个系统的粒度是具有相对性的,同一个软件单元,在不同场景下,我们会以不同的粒度看待它。所有的系统都有子系统,而所有系统都是更大系统的子系统。实践不同场景使得软件组成单元具有递归性。懂得了细节是相对而言的这一点,软件架构师才能够游刃有余地根据情况忽略应该被忽略的细节,抓住设计大局。
框架的概念,框架是一种半成品。是可以通过某种回调机制进行扩展的软件系统或子系统的半成品。框架从某种程度上来说,是为了软件重用。而软件重用本身又有一对内在的矛盾,即重用几率和重用价值,重用几率大小和重用带来的价值大小之间的矛盾。软件单元的粒度越大,可重用的几率就越小,但其重用所带来的价值就越大,相反,软件单元的粒度越小,可重用几率就越大,但其重用所带来的价值就越小。框架的智慧就在于此:为了追求重用所带来的价值最大化,将容易变化的的部分封装成扩展点,并辅以回调机制将它们纳入框架的控制范围之内。
对软件架构的误解,其中一个最为普遍的就是,将架构(Acrchitecture)和框架(Framework)混为一谈。框架是软件,而架构不是软件。框架是一种特殊的软件,它并不能提供完整的解决方案(准确说,是不提供业务应用的完整解决方案,而框架本身也是为解决某一类问题而出现的),而是为构建解决方案(这里的解决方案即是业务应用的解决方案)提供良好的基础,所以说,框架是半成品。框架中的服务可以被最终应用直接调用,而框架中的扩展点是供应用开发人员定制的“可变化点”。而软件架构不是软件,而是关于软件如何设计的重要决策。软件架构决策涉及到如何将软件系统分解成不同的部分、各部分之间的静态结构关系和动态交互关系等。这些架构决策将体现在最终开发出的软件系统中。引入软件框架之后,整个开发过程变成了分两步走,而架构决策往往会体现在框架之中。软件架构是比具体代码高一个抽象层次的概念。架构势必被代码所体现和遵循,但任何一段具体的代码都代表不了架构(这里说的有点绝对,某一段具体的代码,代表不了整个架构,有时却可以代表某一个架构决策)。框架技术和架构技术的出现,都是为了解决软件系统日益复杂所带来的困难而采取“分而治之”的思想。先大局后局部,就出现了架构;先通用后专用,就出现了框架。架构是问题的抽象解决方案,它关注大局而忽略细节;框架是通用半成品,还必须根据具体需求进一步定制开发才能变成应用系统。当然,框架也有架构,而且很重要。框架和架构既有区别又有联系,前者是复合组件特例,后者是复合组件的大局设计。软件架构需要落地,需要了解细节,但也没有必要将所有设计决策事无巨细地落实,而是重点关注“重要决策”。软件架构设计的决策范围,应该着重放在“影响全局”的设计上,而不是所关注所有设计细节。
对面向对象开发而言,类库和框架有很多共同之处,但它们确确实实又是不同的。类库是类的集合,这些类之间可能是相互独立的。与类库相比,框架和类库有着相似的形式,即框架也往往是类的集合,但不同之处在于,框架中的各个类不是孤立的,而框架中的业务逻辑代码是将不同的类“连”在一起,在它们之间建立协作关系。框架通过封装处理流程的控制逻辑,使它对开发者透明,来简化开发工作。这种封装也是框架和类库的区别之一。
框架可以分为应用框架、中间件框架和基础设施框架三大类,形成了“应用软件——中间件——基础设施”的宏观格局。框架也可以分为技术框架和业务框架。技术框架又称为水平框架,业务框架有称为垂直框架。框架的整个开发过程,包括四个主要阶段,即分析、设计、实现和稳定阶段。和应用开发一样,框架开发首先要确定框架的范围和目标。对特定领域框架层和跨领域框架层都要识别出通用点和扩展点,其次,为框架设计架构,将它用作实现阶段的蓝图。在设计阶段,也可以创建应用程序框架原型,然后在其上构建一个样本应用,并洞察框架设计中潜在的可改进之处。框架开发的稳定阶段还应提供相应的框架文档。面向对象技术的发展极大提够了框架的能力,并推动了框架技术被普遍接受。面向对象框架的组成部分包括具体类、抽象类和接口。抽象方法是面向对象支持“多态”的关键,面向对象框架借助抽象方法实现逆向控制。许多面向对象框架在利用抽象方法支持扩展的同时,还会借助“配置驱动”来降低使用框架的难度。框架也需要架构设计,但反过来,可以通过架构框架化,达到“架构重用”的目的。
软件架构的作用
软件架构对后期的软件维护,乃至改动力度比较大的软件升级都起着重要作用。因为软件架构给出了软件系统的一个全局的视角。对软件系统不断的修改会使系统架构慢慢变得混乱,因为业务的发展,是会慢慢腐蚀现有的系统架构的,所以架构需要根据业务的发展进行演进。
软件架构设计为什么这么难?因为它是跨越现实世界与计算机世界之间鸿沟的一座桥。从面向业务的需求,到最终的面向技术的软件系统,要跨越很大的鸿沟。软件架构设计就是要完成从面向业务到面向技术的转换,在鸿沟上驾起一座桥梁。软件架构包含了结构、协作和技术等方面的重要决策,为系统化的开发活动建立了基础。
架构的作用包括如下几个方面:
1、 上承业务目标:担负着完成业务目标而进行大局规划的职责。
2、 下接技术决策:软件架构师将面向业务的需求转化为面向技术的软件架构设计方案,为后面的技术开发工作提供了切实的指导和限制。
3、 控制复杂性:先进行架构设计,后进行详细设计和编码实现,运用了“基于问题深度分而治之”的理念,利用控制复杂性。
4、 组织开发:软件架构为开展系统化的团队开发奠定了基础,它规定了软件系统的各元素如何彼此相关的设计决策,从而可以把不同模块分配给不同小组分头并发进行,而软件架构设计方案在这些小组中间扮演了“桥梁”和“合作契约”的作用。
5、 利用迭代开发和增量交互
6、 提高质量:清晰的软件架构将各个模块的职责划分得有条不絮,每个模块都有清晰的接口,这相当于间接降低了开发难度。
软件架构会“磨损”——随着对软件系统不断地修改,软件架构将变得混乱。
所谓软件架构重构,是指对软件架构进行比较大的修改和调整,使它适应新需求及开发和维护的需要。软件架构重构属于“再工程”的一种情况,一般会经历逆向工程、重新规划、正向工程三个步骤。只有充分理解原有架构的设计思路,才能评估它在现在需求情况的“利”和“弊”,把合理的设计保留下来,把不妥的设计修改掉。
软件架构视图
方法指导过程,过程包含步骤。
所谓软件架构就是关于如何构建软件的一些最重要的设计的决策,这些决策往往是围绕将系统分为哪些部分、各部分之间如何交互展开的。不同的涉众看待软件架构的视角是不同的。软件架构是抽象的概念,所以在软件架构概念与实践之间,似乎存在某种“鸿沟”——即缺失某种概念,而这种概念可以“链接”软件架构的概念和实际的开发实际的需要,为不同涉众理解和交流架构提供更专一的视角。为了在软件架构纯概念和实践之间搭起一座桥梁,可以引入软件架构视图的概念。软件架构师应当时时牢记:为用户而设计,不仅满足用户要求的功能,也要达到用户期望的质量。架构师也必须为客户而设计,适合的才是最好的。架构师还应该为开发人员而设计,关注软件的“开发期质量属性”(可扩展性、可移植性、易理解性和易测试性等非功能需求,都是属于软件开发期质量属性),为开发人员而设计。软件越来越复杂,单兵作战已经不再是普遍的软件开发方式,取而代之的是团队开发,而团队开发又反过来使软件开发更加复杂,因为现在不仅仅要面临技术复杂性的问题了,还有管理复杂性的问题。软件架构从大局着手,就技术方面的重大问题做出决策,构造一个由粗粒度模块组成的解决方案,从而可以把不同模块分配给不同小组分头开发。另一方面,软件架构设计方案规定了各模块之间如何交互的机制和接口,在开发小组之间起到“沟通桥梁”和“合作契约”的作用。配置管理员应该能够从软件架构方案中了解到开发出来的软件以什么样的目录结构存在,以及编译过后的软件目标模块放到哪个目录等决定,并以此作为制定配置管理基本方案的基础。所以,架构师应该为项目相关不同的角色而设计。软件架构师必须做到内外兼修、各层并重。只有这样,软件架构才能和它“包含了关于如何构建软件的一些最重要的设计决策”的“地位”相符。
一个软件架构视图是对与从某一视角或某一点上看到的系统所作出的简化描述,描述中涵盖了系统的某一特定方面,而省略了与此方面无关的实体。软件架构的每个视图分别关注不同的方面,针对不同的目标和用户。软件架构师应当提供不同的软件架构视图,以便交流和传递设计思想。每个软件架构视图关注软件架构不同的方面,使问题得以清晰和简化,利于软件架构师完成架构设计的工作。项目不同角色观察软件架构的视角各不相同,每个视角涉及的需求和技术也不尽相同,所以将软件架构视图用作软件归档的手段是顺利成章的:但更为重要的是,软件架构视图可以被相对独立地分析和设计,这就使得软件架构师可以暂时撇开其他问题、专注于特定问题进行深入的分析和设计。
最常用的两种架构视图:逻辑架构视图和物理架构视图。当观察和描述事物大局的时候,逻辑架构和物理架构是最常用的角度。软件逻辑架构设计的三大核心任务:识别功能块;规划功能块的接口;明确功能块之间的使用关系和使用机制。软件的逻辑架构是架构设计思维的重要方法。用例技术已经成为捕获功能需求的事实标准,所以逻辑架构的设计往往是从用例分析开始的。基于用例的分析方法使逻辑架构的设计变得比较有序——通过对每个关键用例的分析,从逻辑上将用例实现为一组功能块的特定组合,最后综合这些用例分析成果,得到整个软件系统的逻辑架构。物理架构可以反映出软件系统运行时的组织情况。“物理元素”就进程、线程以及作为类的运行时实例的对象等,而进程调度、线程同步、进程或线程通信等则进一步反映物理架构的动态行为。物理层和分别有关,通过将一个整体的软件系统划分为不同的物理层次,可以把它部署到分别在不同位置的多台计算机上,从而为远程访问和负载均衡等问题提供了手段。物理层是大粒度的物理单元,它最终是由粒度更小的组件、模块和进程等单元组成。逻辑架构和物理架构是软件架构设计的重要方面。逻辑架构致力于将软件系统分解成不同的逻辑单元,并规定这些逻辑单元之间的交互接口和交互机制。物理架构则更重视软件系统运行时的动态结构,以及组成软件系统的目标程序如何部署到硬件上。逻辑架构中关于职责划分的决策,体现为层、子系统和模块等的划分决定,从静态视角为详细设计和编程实现提供切实的指导;有了分解就必然产生协作,逻辑架构还规定了不同逻辑单元之间的交互接口和交互机制,而编程工作必须实现这些接口和机制。所谓交互机制,就是指不同软件单元之间的交互手段。交互机制可以是本地方法调用、基于RMI的远程方法调用、异步消息等。至于物理架构,它关注的是软件系统在计算机中运行期间的情况。软件的物理架构关注“目标程序及其依赖的运行库和系统软件”最终如何安装或部署到物理机器,以及如何部署机器和网络来配合软件系统的可靠性、可伸缩性等需求。物理层作为组成软件系统的物理单元,最终又要映射到具体的硬件,这也是物理架构设计要考虑的,对于分布式软件系统的设计而言尤其不可或缺。
不同的视图支持不同的目标和用途。
软件架构师有许多工作要做:
1、要满足性能、持续可用性等方面的需求,架构师必须深入研究软件系统运行期间的情况、制定相应的设计决策,这些需求被称为软件的“运行期质量属性”;
2、而要满足可扩展性、可重用性等方面的需求,则要求架构师深入研究软件系统开发期间的情况,制定相应的设计决策,这些需求被称为软件“开发期质量属性”;
3、约束是一类特殊的需求,带有一定强制性,架构师制定的架构决策必须满足这些限制;
4、为了满足功能需求,架构师必须规划组成软件系统的所有模块,为他们分配不同职责,使这些模块可以通过协作完成功能需求。
架构师必须明确区分功能需求、约束、运行期质量属性和开发期质量属性等不同种类的需求。
架构设计的5视图方法包括:逻辑架构、开发架构、运行架构、物理架构、数据架构。逻辑架构关注功能,它们可能是逻辑层、功能模块和类等。开发架构关注程序包,不仅包括要编写的源程序,还包括可以直接使用的第三方SDK和现成框架、类库,以及开发的系统将运行于其上的系统软件或中间件。运行架构关注进程、线程、对象等运行时概念,以及相关的并发、同步、通信等问题。物理架构关注“目标程序及其依赖的运行库和系统软件”最终如何安装和部署到物理机器上,以及如何部署机器和网络来配合软件系统的可靠性、可伸缩性等要求。数据架构关注持久化数据的存储方案,不仅包括实体及实体关系的数据存储格式,还可能包括数据传递、数据复制和数据同步等策略。
逻辑架构的设计着重考虑功能需求,系统应当向用户提供什么样的服务。逻辑架构的关注点主要是行为或职责的划分。逻辑架构的静态方面关注抽象职责的划分,其动态方面关注承担不同职责的逻辑单元之间的交互。开发机构的设计着重考虑开发周期质量属性,例如可用性、可扩展性、易理解性和易测试性等。开发架构的关注点是在软件开发环境中软件模块的实际组织方式。运行架构的设计着重考虑运行期质量属性,例如性能、可伸缩性、持续可用性和安全性等。运行架构的关注点是系统的并发与同步等问题,这势必涉及到进程和线程等技术。运行架构的静态方面关注软件的运行时单元结构,其动态方面则关注运行时单元之间的交互机制。物理架构的设计着重考虑“安装和部署需求”,另外物理架构还应关注相关的可靠性、可伸缩性、持续可用性、性能和安全性等方面。数据架构的设计着重考虑“数据需求”。数据架构的关注点是持久化数据的组织、数据传输、数据复制和数据同步等策略。
五种架构视图,反映的是同一个软件系统的不同设计方面,它们最终合在一起才是完整的架构设计方案,所以不同的架构视图之间势必有相互支撑的关系。所谓保持架构视图之间的同步,就是保证不同视图之间是相互解释而不是相互矛盾的。如果需要,可以引入新的架构视图,从而更加突出和明确地制定和表达特定方面的架构决策。另外,约束是必须遵守和考虑到的,每个架构设计视图都应该注意这一点。五种不同的元素撑起了不同的思维空间,从而使每个架构视图重点覆盖不同种类的需求。
概念架构和实际架构
实际的软件架构设计过程是,一般应先进行概念性架构的设计,把最关键的设计要素和交互机制确定下来,然后再考虑具体技术的运用,设计出实际架构。概念性架构是对系统设计的最初构想。概念性架构没有严格的定义,而且也不应该过于严格的定义。概念性架构包括一些高层次的设计选择,对未来软件系统的质量和功能都起着关键影响。复杂系统的设计往往不能一蹴而就,而概念性架构就是最初的架构设计成果。
经典的分层架构的层指逻辑层(Layer),而现在的分布式应用的分层架构是指物理层(Tier)。逻辑层是一种功能和职责的组织单元,而物理层要求功能和责任的高聚合性,只不过往往是通过多个逻辑层映射到一个物理层这种方式实现的。
虽然概念性架构都跳不出“架构=组件+交互”的基本定义,但它们描述架构的具体方式还是差异很大的:有的重视逻辑层,有的重视物理层,有的通过隐喻表明机制,有的看上去似乎就是一些设计元素的组合。不同的概念性架构图中,“连接”所代表的含义千差万别:有的是依赖方向,有的是控制方向,有的是数据流向。由于概念架构的高度抽象性,使得同属一类的许多软件产品的概念性架构是趋同的。概念性架构非常相似,实际架构却可能有很大的差异。概念性架构往往和具体技术的运用、具体平台的选择无关,而实际架构非常关心这些问题。实际的架构设计方案应该兼顾不同的架构设计视图。概念性架构所包含的高层设计决策终究不会跳出如下多种架构视图的范围——逻辑架构、物理架构、开发架构、数据架构和运行架构。而实际架构必须设计到可以指导开发的程度。但务实地来讲,概念性架构经常从逻辑架构和物理架构的角度制定高层设计决策。
概念性架构是不可直接实现的。概念性架构和实际架构的一些区别,主要涉及到开发人员最关心的点:
1、接口如何定义;
2、子系统如何划分;
3、各子系统或模块之间的如何进行交互;
共同点:概念性架构和实际架构都满足软件架构的概念——无论是“架构=组件+交互”,还是“架构=重要的决策集”。
分层架构往往是我们架构思维的开始,在“分层”的基础上如何深入,细化设计,如何调整往往是架构设计的关键。
概念性架构往往和具体技术的运用和具体平台的选择无关,而实际架构则非常关系这些问题,概念性架构并不规定要采用OO技术,但设计实际架构时往往要考虑如何充分利用OO技术来实现概念性架构。从概念性架构到实际架构,先设计概念性架构,构思关键问题的解决策略;再进行实际架构设计,以保证为开发提供足够的指导和限制。
成功的架构设计
好的架构应当具有如下品质:
1、良好的模块化。每个模块职责明晰,模块之间松耦合,模块内部高聚合并合理地实现了信息隐藏。
2、适应功能需求的变化,适应技术的变化。应该保持应用相关模块和领域通用模块的分离,技术平台相关模块和独立于具体技术的模块相分离,从而达到“隔离变化”的效果。
3、对系统的动态运行有良好的规划。
4、对数据的良好规划。
5、明确、灵活的部署规则。
软件架构师的工作成功要为整个软件开发团队的工作提供足够的指导和限制,使他们能够沿着正确的方向进行下去。软件架构师开展架构设计工作,都是以《软件需求规格说明书》为最主要的设计依据的,都是先勾画出概念性架构,再结合具体技术平台制定实际架构。
非功能需求来自何处?一部分非功能需求来自用户。用户要功能,用户也要质量。为用户而设计,不仅要满足用户要求的功能,也要达到用户期望的质量。一部分非功能需求来自开发者和升级维护人员。软件的可扩展性、可重用性、可移植性、易理解性和易测试性等非功能需求,都属于“软件开发期质量属性”之列。还有一部分非功能需求来自客户组织。非功能需求对架构设计非常重要。非功能需求是最重要的“架构决策因素”之一。非功能需求大致分为质量属性和约束两大类。约束性需求,它们要么是架构设计中必须遵循的限制,要么转化为质量属性需求或者功能需求。架构设计过程中必须重视非功能需求。功能很重要,当架构师不能仅盯着功能需求,若忽视了非功能需求,则可能导致架构设计的失败。
架构师必须具备“忘却”的能力,避免涉及太多的具体的技术细节。软件架构必须为开发人员提供足够的指导和限制。软件架构师需要掌握趋于系统化的方法。对待复杂性的办法就是分而治之,和分而治之相伴相生的“综合考虑”也是不可或缺的。
软件架构设计强调的是整体,而整体性的设计决策必须基于对需求的全面认识。全面认识需求,是生产出高质量软件所必须的“第一项修炼”。要全面认识需求,我们必须从不同级别来考察需求:组织级、用户级、开发级,还要对每个级别考虑不同类型的需求:功能需求、质量属性、约束。全面认识需求还有一层含义,那就是应当在深思熟虑之后作出适合的需求权衡和取舍。一方面,众多质量属性需求之间往往会有冲突,我们必须权衡。另一方面,如果通过复杂设计所支持的变化根本不会发生,那么这种过度设计就造成了资源的浪费并增加了开发的难度。
让关键需求决定架构。功能需求数量众多,应该控制架构设计时需要详细分析的用例个数;另一方面,不同质量属性之间往往具有相互制约性,于是我们自然应该权衡哪一部分质量属性是架构设计的重大目标。需求来自与实践需要,而实践是发展的,所以“确定的需求”只是相对的。我们一般在项目的业务目标以核心需求达成共识之后就开始架构设计,关键需求决定架构的策略非常适合。
应对软件架构设计方案进行验证,而不仅仅是评审。应真正地通过编码将架构实现;应实际对架构原型进行测试,测试的重点是运行时质量属性;要认真评估架构原型的实现过程,以对软件架构的开发期质量属性给出评价。有两种验证技术可以采用:原型技术和框架技术。
架构设计不能遗漏至关重要的非功能需求;架构设计必须驯服数量巨大且频繁变化的需求。架构设计涉及不同方面的设计决策,软件架构师应当采用基于多视图的架构设计方法。架构设计的成果应及早验证,如果盲目假设架构方案是可行的,直到后期才发现问题,就会造成大规模返工乃至项目失败,因此软件架构师应注意尽早验证架构。
我们不认为Coding和Designing是对立的。
把设计搞得玄而又玄的结果是,很多影响全局的设计决策本应由架构设计来完成的,却统统“漏”到了后边,最终到了大规模并行开发阶段才发现。这样一来,造成了“程序员碰头临时决定”的情况大量出现,软件质量必然下降,甚至还会导致项目失败。软件架构是团队开发的基础,软件架构必须设计到“能为开发人员提供足够的指导和限制”的程度。《人月神话》指出“软件的复杂度是根本属性,不是次要因素”。采用面向对象方法的“最重要的原因”是它可以帮助我们解决更复杂的问题,而不是更好的可重用性。面对一个复杂的问题,我们如何分而治之?可以按照问题的深度进行分而治之或者按照问题的广度进行分而治之。接口和现实分离,就是“按问题的深度分而治之”一个很好的例子。将展现层、业务层和数据层分派给不同小组承担,属于“按问题广度分而治之”的例子。
随着软件的规模和复杂度增加,算法和数据结构以外的设计问题就会出现:设计和制定系统整体结构将成为新的一类问题,这就是软件架构层次的设计。将设计分为架构设计和详细设计,是对“按问题深度分而治之”思想的运用:所谓架构设计,就是关于如何构建软件的一些最重要的设计决策,这些决策往往是围绕将系统分为哪些部分,各个部分之间如何交互展开的。而详细设计针对每个部分的内部进行设计。软件架构设计应当解决的是全局性的、涉及不同“局部”之间交互的设计问题,而不同“局部”的设计由后续的详细设计负责。在软件架构所提供的“合作契约”的指导下,众多局部问题被很好地“按问题广度分而治之”了。这种先确定软件架构,而后基于软件架构进行并行开发的做法,综合利用了上诉两种分而治之的方法,利用控制复杂性,提高开发效率。
面对“技术复杂性”和“管理复杂性”这样的双重困难,以架构为中心的开发方法是有效的途径:一方面,软件架构从大局着手,就技术方面的重大问题作出决策,构造一个具有一定抽象层次的解决方案,而不是将所有细节统统展开,从而有效地控制了“技术复杂性”。另一方面,因为“架构中包含了关于各元素应如何彼此相关的信息”,从而可以把不同的模块分配给不同小组分头开发,而软件架构设计方案在这些小组中扮演“桥梁”和“合作契约”的作用。正因为软件架构是大规模开发的基础,所以架构中应包含软件系统的各元素如何彼此相关的设计决策;也正是因为软件架构包含了软件系统如何组织等关键决策,才能使得它能够成为大规模开发的基础。由此可见,软件架构为开展系统化的团队开发奠定了基础,为解决“管理复杂性”提供了有力的支持。
架构设计对软件的不同部分的设计程度并不是整齐划一的。由于项目的不同、开发团队情况的不同,软件架构的设计程度会有不同;软件架构应当为开发人员提供足够的指导和限制。
所谓“高来高去式架构设计”,是指不能为开发人员提够足够的指导和限制的那种架构设计方案。高来高去式的架构设计大致有如下三种表现:1、缺失重要架构视图。为不同的系统进行架构设计时,对不同的架构视图的重视程度并不相同。“缺失重要架构视图”的一种表现是,认为软件架构设计完全是用例驱动的,片面强调用例描述的功能需求。此时,架构设计对非功能需求关注不够,既没有深入设计软件的运行架构,也没有深入设计软件的开发架构。2、浅尝即止、不够深入。架构方案过于笼统,基本还停留再概念性架构的层面,没有提够明确的技术蓝图。概念性架构对开发人员的指导和限制是不够的。架构设计阶段遗漏了全局性的设计决策,到了大规模开发实现阶段,这些设计决策往往被具体开发人员从局部视角考虑并确定下来。3、名不副实的分层架构。通过分层将软件系统模块化之后,就迫不及待地喊出“分层架构”的口号,对各层之间交互接口和交互机制的设计严重不足。仅仅用分层来进行职责划分,而没有规划层次之间的交互接口和交互机制的情况。缺失交互接口和交互机制的分层架构中,其实“层”已经退化成笼统意义的“职责模块”了。
高来高去式的架构本身没有错,它们往往属于概念性架构的范畴,它往往是循序渐进地进行软件架构设计的良好起点。但是,如果停留在高来高去的架构设计上止步不前,并以之作为最终的架构设计方案,就会为后期开发埋下重大风险。
软件架构设计过程
一般来说,软件开发过程包括5个阶段:概念化阶段、分析阶段、架构阶段、架构设计阶段、并行开发和测试阶段、验收与交付阶段。
概念阶段要解决项目的起源问题,主要针对项目目标、主要特性、功能范围和成功要素等进行构思并达成一致。分析阶段的目的是明确需求,并以《软件需求规格说明书》的形式记录下来。架构设计阶段要在较高的抽象层次上制定解决方案,即设计软件架构。并行开发和测试阶段动用的资源是最多的,在此阶段中,我们以软件架构为基础,进行系统化的开发和测试。
架构设计的开展非常依赖其上游活动,这些上游活动包括需求分析和领域建模。领域建模的目的是透过问题领域的重重现象,捕捉其背后最为稳固的领域概念及这些概念之间的关系。在项目前期,所建立的领域模型将为所有团队成员之间、团队成员和客户之间的交流提够共同认可的语言核心。随着项目的进展,领域模型不断被精化,最终成为整个软件的问题领域层,该层决定了软件系统能力的范围。从项目前期伊始,软件架构师就应该是领域建模活动的领导者。
完成了上游活动,接下来要进行概念性架构设计。软件系统的规模越大、复杂度越高,进行概念性架构设计的好处就越明显。概念性架构的第一步是分析关键用例的用例规约,接下来明确架构模式,确定交付机制,形成初步的概念性架构。概念性架构所关注的关键设计要素、交互机制、高层设计决策多与具体技术无关,而最终的软件架构设计方案必须和具体技术结合,为开发人员提供足够的指导和限制。
尽量使架构设计策略作为软件架构设计过程的“一等公民”,这样才能更有效地指导软件架构师进行架构设计。
另外提一下领域模型建设。后面还会详细提到。领域模型凝聚了领域专家知识。问题领域可能很复杂,领域模型揭示了纷繁复杂的问题背后的结构。领域模型和软件需求不同:领域模型是对问题领域“做透视”,从而揭示其内在结构;而软件需求是对问题领域“拍照片”,从而捕捉其外在功能。领域模型相对是稳定的,而软件需求是变化的,一个优秀的领域模型可以“容纳”一定程度的需求变化。领域模型是团队交流的基础,是所有团队成员所用语言的核心。
软件需求式委托方希望软件系统达到的目标。软件需求不仅包括功能需求,还包括质量属性和约束性属性。软件架构强调的是整体,而整体性的设计决策必须基于对需求的全面认识。另外,软件架构应该是稳定的。概念性架构是架构设计的初步成果。概念性架构也会确定软件系统所采用的架构模式。对软件架构起关键作用的质量属性需求将在“质量属性分析”活动中进行。架构设计不断深入的过程,也是领域模型不断精化的过程。随着用例分析的进行,不断有类的职责被确定,作为类的方法被添加进来。最终的软件架构设计方案必须和具体技术结合,从而为开发人员提够足够的指导和限制。在设计软件的逻辑架构过程中,领域模型将进一步精化,并成为软件逻辑架构的重要组成部分。
|