好的软件架构设计

开通VIP,畅享免费电子书等14项超值服

首页

好书

留言交流

下载APP

联系客服

2021.01.16

什么是软件架构

前言:软体设计师中有一些技术水平较高、经验较为丰富的人,他们需要承担软件系统的架构设计,也就是需要设计系统的元件如何划分、元件之间如何发生相互作用,以及系统中逻辑的、物理的、系统的重要决定的作出。在很多公司中,架构师不是一个专门的和正式的职务。通常在一个开发小组中,最有经验的程序员会负责一些架构方面的工作。在一个部门中,最有经验的项目经理会负责一些架构方面的工作。但是,越来越多的公司体认到架构工作的重要性。

什么是软件系统的架构(Architecture)?一般而言,架构有两个要素:

·它是一个软件系统从整体到部分的最高层次的划分。

一个系统通常是由元件组成的,而这些元件如何形成、相互之间如何发生作用,则是关于这个系统本身结构的重要信息。

详细地说,就是要包括架构元件(ArchitectureComponent)、联结器(Connector)、任务流(Task-flow)。所谓架构元素,也就是组成系统的核心"砖瓦",而联结器则描述这些元件之间通讯的路径、通讯的机制、通讯的预期结果,任务流则描述系统如何使用这些元件和联结器完成某一项需求。

·建造一个系统所作出的最高层次的、以后难以更改的,商业的和技术的决定。

在建造一个系统之前会有很多的重要决定需要事先作出,而一旦系统开始进行详细设计甚至建造,这些决定就很难更改甚至无法更改。显然,这样的决定必定是有关系统设计成败的最重要决定,必须经过非常慎重的研究和考察。

计算机软件的历史开始于五十年代,历史非常短暂,而相比之下建筑工程则从石器时代就开始了,人类在几千年的建筑设计实践中积累了大量的经验和教训。建筑设计基本上包含两点,一是建筑风格,二是建筑模式。独特的建筑风格和恰当选择的建筑模式,可以使一个独一无二。

下面的照片显示了中美洲古代玛雅建筑,Chichen-Itza大金字塔,九个巨大的石级堆垒而上,九十一级台阶(象征着四季的天数)夺路而出,塔顶的神殿耸入云天。所有的数字都如日历般严谨,风格雄浑。难以想象这是石器时代的建筑物。

图1、位于墨西哥Chichen-Itza(在玛雅语中chi意为嘴chen意为井)的古玛雅建筑。(摄影:作者)

软件与人类的关系是架构师必须面对的核心问题,也是自从软件进入历史舞台之后就出现的问题。与此类似地,自从有了建筑以来,建筑与人类的关系就一直是建筑设计师必须面对的核心问题。英国首相丘吉尔说,我们构造建筑物,然后建筑物构造我们(Weshapeourbuildings,andafterwardsourbuildingsshapeus)。英国下议院的会议厅较狭窄,无法使所有的下议院议员面向同一个方向入座,而必须分成两侧入座。丘吉尔认为,议员们入座的时候自然会选择与自己政见相同的人同时入座,而这就是英国政党制的起源。Party这个词的原意就是"方"、"面"。政党起源的关键就是建筑物对人的影响。

在软件设计界曾经有很多人认为功能是最为重要的,形式必须服从功能。与此类似地,在建筑学界,现代主义建筑流派的开创人之一LouisSullivan也认为形式应当服从于功能(Formsfollowsfunction)。

几乎所有的软件设计理念都可以在浩如烟海的建筑学历史中找到更为遥远的历史回响。最为著名的,当然就是模式理论和XP理论。

架构的目标是什么

正如同软件本身有其要达到的目标一样,架构设计要达到的目标是什么呢?一般而言,软件架构设计要达到如下的目标:

·可靠性(Reliable)。软件系统对于用户的商业经营和管理来说极为重要,因此软件系统必须非常可靠。

·安全行(Secure)。软件系统所承担的交易的商业价值极高,系统的安全性非常重要。

·可扩展性(Scalable)。软件必须能够在用户的使用率、用户的数目增加很快的情况下,保持合理的性能。只有这样,才能适应用户的市场扩展得可能性。

·可定制化(Customizable)。同样的一套软件,可以根据客户群的不同和市场需求的变化进行调整。

·可扩展性(Extensible)。在新技术出现的时候,一个软件系统应当允许导入新技术,从而对现有系统进行功能和性能的扩展

·可维护性(Maintainable)。软件系统的维护包括两方面,一是排除现有的错误,二是将新的软件需求反映到现有系统中去。一个易于维护的系统可以有效地降低技术支持的花费

·客户体验(CustomerExperience)。软件系统必须易于使用。

·市场时机(TimetoMarket)。软件用户要面临同业竞争,软件提供商也要面临同业竞争。以最快的速度争夺市场先机非常重要。

架构的种类

·逻辑架构、软件系统中元件之间的关系,比如用户界面,数据库,外部系统接口,商业逻辑元件,等等。

比如下面就是笔者亲身经历过的一个软件系统的逻辑架构图

图2、一个逻辑架构的例子

从上面这张图中可以看出,此系统被划分成三个逻辑层次,即表象层次,商业层次和数据持久层次。每一个层次都含有多个逻辑元件。比如WEB服务器层次中有HTML服务元件、Session服务元件、安全服务元件、系统管理元件等。

·物理架构、软件元件是怎样放到硬件上的。

比如下面这张物理架构图描述了一个分布于北京和上海的分布式系统的物理架构,图中所有的元件都是物理设备,包括网络分流器、代理服务器、WEB服务器、应用服务器、报表服务器、整合服务器、存储服务器、主机等等。

图3、一个物理架构的例子

·系统架构、系统的非功能性特征,如可扩展性、可靠性、强壮性、灵活性、性能等。

系统架构的设计要求架构师具备软件和硬件的功能和性能的过硬知识,这一工作无疑是架构设计工作中最为困难的工作。

此外,从每一个角度上看,都可以看到架构的两要素:元件划分和设计决定。

首先,一个软件系统中的元件首先是逻辑元件。这些逻辑元件如何放到硬件上,以及这些元件如何为整个系统的可扩展性、可靠性、强壮性、灵活性、性能等做出贡献,是非常重要的信息。

其次,进行软件设计需要做出的决定中,必然会包括逻辑结构、物理结构,以及它们如何影响到系统的所有非功能性特征。这些决定中会有很多是一旦作出,就很难更改的。

根据作者的经验,一个基于数据库的系统架构,有多少个数据表,就会有多少页的架构设计文档。比如一个中等的数据库应用系统通常含有一百个左右的数据表,这样的一个系统设计通常需要有一百页左右的架构设计文档。

架构师

软体设计师中有一些技术水平较高、经验较为丰富的人,他们需要承担软件系统的架构设计,也就是需要设计系统的元件如何划分、元件之间如何发生相互作用,以及系统中逻辑的、物理的、系统的重要决定的作出。

这样的人就是所谓的架构师(Architect)。在很多公司中,架构师不是一个专门的和正式的职务。通常在一个开发小组中,最有经验的程序员会负责一些架构方面的工作。在一个部门中,最有经验的项目经理会负责一些架构方面的工作。

但是,越来越多的公司体认到架构工作的重要性,并且在不同的组织层次上设置专门的架构师位置,由他们负责不同层次上的逻辑架构、物理架构、系统架构的设计、配置、维护等工作。

软件的架构设计

好的开始相当于成功一半

开始之初的架构设计决定着软件产品的生死存亡。“好的开始相当于成功一半”。

开始的架构设计也是最难的,需要调研同类产品的情况以及技术特征,了解当前世界上对这种产品所能提供的理论支持和技术平台支持。再结合自己项目的特点(需要透彻的系统分析),才能逐步形成自己项目的架构蓝图。

比如要开发网站引擎系统,就从Yahoo的个人主页生成工具到虚拟主机商提供的网站自动生成系统,以及IBMWebpherePortal的特点和局限从而从架构设计角度定立自己产品的位置。

好的设计肯定需要经过反复修改,从简单到复杂的循环测试是保证设计正确的一个好办法

由于在开始选择了正确的方向,后来项目的实现过程也验证了这种选择,但在一些架构设计的细部方面,还需要对方案进行修改,属于那种螺旋上升的方式,显然这是通过测试第一的思想和XP工程方法来实现的。

如果我们开始的架构设计在技术平台定位具有一定的世界先进水平,那么,项目开发实际有一半相当于做实验,是研发,存在相当的技术风险。

因此,一开始我们不可能将每个需求都实现,而是采取一种简单完成架构流程的办法,使用最简单的需求将整个架构都简单的完成一遍(加入人工干预),以检验各个技术环节是否能协调配合工作(非常优秀先进的两种技术有时无法在一起工作),同时也可以探知技术的深浅,掌握项目中的技术难易点。这个过程完成后,我们就对设计方案做出上面的重大修改,丰富完善了设计方案。

设计模式是支撑架构的重要组件

架构设计也类似一种工作流,它是动态的,这点不象建筑设计那样,一开始就能完全确定,架构设计伴随着整个项目的进行过程之中,有两种具体操作保证架构设计的正确完成,那就是设计模式(静态)和工程项目方法(RUP或XP动态的)。

设计模式是支撑架构的一种重要组件,这与建筑有很相象的地方,一个建筑物建立设计需要建筑架构设计,在具体施工中,有很多建筑方面的规则和模式。

架构设计是骨架,设计模式就是肉

这样,一个比较丰富的设计方案可以交由程序员进一步完成了,载辅助以适当的工程方法,这样就可保证项目的架构设计能正确快速的完成。

时刻牢记架构设计的目标

由于架构设计是在动态中完成的,因此在把握架构设计的目标上就很重要,因此在整个项目过程中,甚至每一步我们都必须牢记我们架构设计的总体目标,可以概括下面几点:

1.最大化的重用:这个重用包括组件重用和设计模式使用等多个方面。

比如,我们项目中有用户注册和用户权限系统验证,这其实是个通用课题,每个项目只是有其内容和一些细微的差别,如果我们之前有这方面成功研发经验,可以直接重用,如果没有,那么我们就要进行这个子项目的研发,在研发过程中,不能仅仅看到这个项目的需求,也要以架构的概念去完成这个可以称为组件的子项目。

2.尽可能的简单明了:我们解决问题的总方向是将复杂问题简单化,其实这也是中间件或多层体系技术的根本目标。但是在具体实施设计过程中,我们可能会将简单问题复杂化,特别是设计模式的运用上很容易范这个错误,因此如何尽可能的做到设计的简单明了是不容易的。

我认为落实到每个类的具体实现上要真正能体现系统事物的本质特征,因为事物的本质特征只有一个,你的代码越接近它,表示你的设计就是简单明了,越简单明了,你的系统就越可靠。更多情况是,一个类并不能反应事物本质,需要多个类的组合协调,那么能够正确使用合适的设计模式就称为重中之重。

我们看一个具备好的架构设计的系统代码时,基本看到的都是设计模式,宠物店(petstore)就是这样的例子。或者可以这样说,一个好的架构设计基本是由简单明了的多个设计模式完成的。

3.最灵活的拓展性:架构设计要具备灵活性拓展性,这样,用户可以在你的架构上进行二次开发或更加具体的开发。

要具备灵活的拓展性,就要站在理论的高度去进行架构设计,比如现在工作流概念逐步流行,因为我们具体很多实践项目中都有工作流的影子,工作流中有一个树形结构权限设定的概念就对很多领域比较通用。

树形结构是组织信息的基本形式,我们现在看到的网站或者ERP前台都是以树形菜单来组织功能的,那么我们在进行架构设计时,就可以将树形结构和功能分开设计,他们之间联系可以通过树形结构的节点link在一起,就象我们可以在圣诞树的树枝上挂各种小礼品一样,这些小礼品就是我们要实现的各种功能。

有了这个概念,通常比较难实现的用户级别权限控制也有了思路,将具体用户或组也是和树形结构的节点link在一起,这样就间接实现了用户对相应功能的权限控制,有了这样的基本设计方案的架构无疑具备很灵活的拓展性。

Part1层

层(layer)这个概念在计算机领域是非常了不得的一个概念。计算机本身就体现了一种层的概念:系统调用层、设备驱动层、操作系统层、CPU指令集。每个层都负责自己的职责。网络同样也是层的概念,最著名的TCP/IP的七层协议。

层到了软件领域也一样好用。为什么呢?我们看看使用层技术有什么好处:

●你使用层,但是不需要去了解层的实现细节。●可以使用另一种技术来改变基础的层,而不会影响上面的层的应用。●可以减少不同层之间的依赖。●容易制定出层标准。●底下的层可以用来建立顶上的层的多项服务。

当然,层也有弱点:

●层不可能封装所有的功能,一旦有功能变动,势必要波及所有的层。●效率降低。

当然,层最难的一个问题还是各个层都有些什么,以及要承担何种责任。

典型的三层结构

三层结构估计大家都很熟悉了。就是表示(presentation)层,领域(domain)层,以及基础架构(infrastructure)层。

表示层逻辑主要处理用户和软件的交互。现在最流行的莫过于视窗图形界面(wimp)和基于html的界面了。表示层的主要职责就是为用户提供信息,以及把用户的指令翻译。传送给业务层和基础架构层。

基础架构层逻辑包括处理和其他系统的通信,代表系统执行任务。例如数据库系统交互,和其他应用系统的交互等。大多数的信息系统,这个层的最大的逻辑就是存储持久数据。

还有一个就是领域层逻辑,有时也被叫做业务逻辑。它包括输入和存储数据的计算。验证表示层来的数据,根据表示层的指令指派一个基础架构层逻辑。

领域逻辑中,人们总是搞不清楚什么事领域逻辑,什么是其它逻辑。例如,一个销售系统中有这样一个逻辑:如果本月销售量比上个月增长10%,就要用红色标记。要实现这个功能,你可能会把逻辑放在表示层中,比较两个月的数字,如果超出10%,就标记为红色。

这样做,你就把领域逻辑放到了表示层中了。要分离这两个层,你应该现在领域层中提供一个方法,用来比较销售数字的增长。这个方法比较两个月的数字,并返回boolean类型。表示层则简单的调用该方法,如果返回true,则标记为红色。

例子

层技术不存在说永恒的技巧。如何使用都要看具体的情况才能够决定,下面我就列出了三个例子:

例子1:一个电子商务系统。要求能够同时处理大量用户的请求,用户的范围遍及全球,而且数字还在不断增长。但是领域逻辑很简单,无非是订单的处理,以及和库存系统的连接部分。这就要求我们1、表示层要友好,能够适应最广泛的用户,因此采用html技术;2、支持分布式的处理,以胜任同时几千的访问;3、考虑未来的升级。

例子2:一个租借系统。系统的用户少的多,但是领域逻辑很复杂。这就要求我们制作一个领域逻辑非常复杂的系统,另外,还要给他们的用户提供一个方便的输入界面。这样,wimp是一个不错的选择。

例子3:简单的系统。非常简单,用户少、逻辑少。但是也不是没有问题,简单意味着要快速交付,并且还要充分考虑日后的升级。因为需求在不断的增加之中。

何时分层

这样的三个例子,就要求我们不能够一概而论的解决问题,而是应该针对问题的具体情况制定具体的解决方法。这三个例子比较典型。

第二个例子中,可能需要严格的分成三个层次,而且可能还要加上另外的中介(mediating)层。例3则不需要,如果你要做的仅是查看数据,那仅需要几个server页面来放置所有的逻辑就可以了。

我一般会把表示层和领域层/基础架构层分开。除非领域层/基础架构层非常的简单,而我又可以使用工具来轻易的绑定这些层。这种两层架构的最好的例子就是在VB、PB的环境中,很容易就可以构建出一个基于SQL数据库的windows界面的系统。这样的表示层和基础架构层非常的一致,但是一旦验证和计算变得复杂起来,这种方式就存在先天缺陷了。

很多时候,领域层和基础架构层看起来非常类似,这时候,其实是可以把它们放在一起的。可是,当领域层的业务逻辑和基础架构层的组织方式开始不同的时候,你就需要分开二者。

更多的层模式

三层的架构是最为通用的,尤其是对IS系统。其它的架构也有,但是并不适用于任何情况。

第一种是Brownmodel[Brownetal]。它有五个层:表示层(Presentation),控制/中介层(Controller/Mediator),领域层(Domain),数据映射层(DataMapping),和数据源层(DataSource)。它其实就是在三层架构种增加了两个中间层。控制/中介层位于表示层和领域层之间,数据映射层位于领域层和基础架构层之间。

表示层和领域层的中介层,我们通常称之为表示-领域中介层,是一个常用的分层方法,通常针对一些非可视的控件。例如为特定的表示层组织信息格式,在不同的窗口间导航,处理交易边界,提供Server的facade接口(具体实现原理见设计模式)。最大的危险就是,一些领域逻辑被放到这个层里,影响到其它的表示层。

我常常发现把行为分配给表示层是有好处的。这可以简化问题。但表示层模型会比较复杂,所以,把这些行为放到非可视化的对象中,并提取出一个表示-领域中介层还是值得的。

BrownISA表示层表示层控制/中介层表示-领域中介层领域层领域层数据映射层数据库交互模式中的DatabaseMapper数据源层基础架构层

领域层和基础架构层之间的中介层属于本书中提到的DatabaseMapper模式,是三种领域层到数据连接的办法之一。和表示-领域中介层一眼,有时候有用,但不是所有时候都有用。

还有一个好的分层架构是J2EE的架构,这方面的讨论可以见『J2EE核心模式』一书。他的分层是客户层(Client),表示层(Presentation),业务层(Business),整合层(Integration),资源层(Resource)。差别如下图:

J2EE核心ISA客户层运行在客户机上的表示层表示层运行在服务器上的表示层业务层领域层整合层基础架构层资源层基础架构层通信的外部数据

微软的DNA架构定义了三个层:表示层(presentation),业务层(business),和数据存储层(dataaccess),这和我的架构相似,但是在数据的传递方式上还有很大的不同。在微软的DNA中,各层的操作都基于数据存储层传出的SQL查询结果集。这样的话,实际上是增加了表示层和业务层同数据存储层之间的耦合度。

DNA的记录集在层之间的动作类似于DataTransferObject。

Part2组织领域逻辑

要组织基于层的系统,首要的是如何组织领域逻辑。领域逻辑的组织有好几种模式。但其中最重要的莫过于两种方法:TransationScript和DomainModel。选定了其中的一种,其它的都容易决定。不过,这两者之间并没有一条明显的分界线。所以如何选取也是门大学问。一般来说,我们认为领域逻辑比较复杂的系统可以采用DomainModel。

TransationScript就是对表示层用户输入的处理程序。包括验证和计算,存储,调用其它系统的操作,把数据回传给表示层。用户的一个动作表示一个程序,这个程序可以是script,也可以是transation,也可以是几个子程序。在例子1中,检验,在购物车中增加一本书,显示递送状态,都可以是一个TransationScript。

DomainModel是要建立对应领域名词的模型,例如例1中的书、购物车等。检验、计算等处理都放到领域模型中。

TransationScript属于结构性思维,DomainModel属于OO思维。DomainModel比较难使用,一旦习惯,你能够组织更复杂的逻辑,你的思想会更OO。到时候,即使是小的系统,你也会自然的使用DomainModel了。

但如何抉择呢?如果逻辑复杂,那肯定用DomainModel:如果只需要存取数据库,那TransationScript会好一些。但是需求是在不断进化的,你很难保证以后的需求还会如此简单。如果你的团队不善于使用DomainModel,那你需要权衡一下投入产出比。另外,即使是TransationScript,也可以做到把逻辑和基础架构分开,你可以使用Gateway。

对例2,毫无疑问要使用DomainModel。对例1就需要权衡了。而对于例3,你很难说它将来会不会像例2那样,你现在可以使用TransationScript,但未来你可能要使用DomainModel。所以说,架构的决策是至关紧要的。

TableModule是另一个中庸模式。很多的GUI环境依托于SQL查询的返回结果。你可以建立内存中的对象,来把GUI和数据库分开来。为每个表写一个模块,因此每一行都需要关键字变量来识别每一个实例。

TableModule适用于很多的组件构建于一个通用关系型数据库之上,而且领域逻辑不太复杂的情况。MicrosoftCOM环境,以及它的带ADO.NET的.NET环境都适合使用这种模式。而对于Java,就不太适用了。

领域逻辑的一个问题是领域对象非常的臃肿。因为对象的行为太多了,类也就太大了。它必须是一个超集。这就要考虑哪些行为是通用的,哪些不是,可以由其它的类来处理,可能是UseCaseController,也可能是表示层。

还有一个问题,复制。他会导致复杂和不一致。这比臃肿的危害更大。所以,宁可臃肿,也不要复制。等到臃肿为害时再处理它吧。

选择一个地方运行领域逻辑

我们的精力集中在逻辑层上。领域逻辑要么运行在Client上,要么运行在Server上。

比较简单的做法是全部集中在Server上。这样你需要使用html的前端以及webserver。这样做的好处是升级和维护都非常的简单,你也不用考虑桌面平台和Server的同步问题,也不用考虑桌面平台的其它软件的兼容问题。

运行在Client适合于要求快速反应和没有联网的情况。在Server端的逻辑,用户的一个再小的请求,也需要信息从Client到Server绕一圈。反应的速度必然慢。再说,网络的覆盖程度也不是说达到了100%。

对于各个层来说,又是怎么样的呢?

基础架构层:一般都是在Server啦,不过有时候也会把数据复制到合适的高性能桌面机,但这是就要考虑同步的问题了。

表示层在何处运行取决于用户界面的设计。一个Windows界面只能在Client运行。而一个Web界面就是在Server运行。也有特别的例子,在桌面机上运行webserver的,例如XServer。但这种情况少的多。

在例1中,没有更多的选择了,只能选在Server端。因此你的每一个bit都会绕一个大圈子。为了提高效率,尽量使用一些纯html脚本。

人们选用Windows界面的原因主要就是需要执行一些非常复杂的任务,需要一个合适的应用程序,而webGUI则无法胜任。这就是例2的做法。不过,人们应该会渐渐适应webGUI,而webGUI的功能也会越来越强大。

剩下的是领域逻辑。你可以全部放在Server,也可以全部放在Client,或是两边都放。

在Client和Server端都具有逻辑并不是一个好的处理办法。但是对于那些仅有一些领域逻辑的情况是适用的。有一个小窍门,把那些和系统的其它部分没有联系的逻辑封装起来。

领域逻辑的接口

虽然XML有那么多的好处,不过一个OO的接口还是有它的价值的。hhtp的接口不明显,不容易看清楚数据是如何处理的。而OO的接口的方法带有变量和名字,容易看出处理的过程。当然,它无法通过防火墙,但可以提供安全和事务之类的控制。

Part3组织webServer

很多使用html方式的人,并不能真正理解这种方式的优点。我们有各种各样好用的工具,但是却搞到让程序难以维护。

在webserver上组织程序的方式大致可以分为两种:脚本和serverpage。

糟糕的是流数据是非常麻烦的,因此就导致了serverpage的产生,例如PHP,ASP,JSP。

serverpage的方式适合回应(response)的处理比较简单的情况。例如“显示歌曲的明细”,但是你的决策取决于输入的时候,就会比较杂乱。例如“通俗和摇滚的显示格式不同”。

脚步擅长于处理用户交互,serverpage擅长于处理格式化回应信息。所以很自然的就会采用脚本处理请求的交互,使用serverpage处理回应的格式化。这其实就是著名的MVC(ModelViewController)模式中的view/controller的处理。

webserver端的MVC工作流程示意图

应用ModelViewController模式首要的一点就是模型要和web服务完全分离开来。使用TransactionScript或DomainModel模式来封装处理流程。

接下来,我们就把剩余的模式归入两类模式中:属于Controller的模式,以及属于View的模式。

View模式

View这边有三种模式:TransformView,TemplateView和TwoStepView。TransformView和TemplateView的处理只有一步,将领域数据转换为html。TwoStepView要经过两步的处理,第一步把领域数据转换为逻辑表示形式,第二步把逻辑表示转换为html。

两步处理的好处是可以将逻辑集中于一处,如果只有一步,变化发生时,你就需要修改每一个屏幕。但这需要你有一个很好的逻辑屏幕结构。如果一个web应用有很多的前端用户时,两步处理就特别的好用。例如航空订票系统。使用不同的第二步处理,就可以获得不同的逻辑屏幕。

使用单步方法有两个可选的模式:TemplateView,TransformView。TemplateView其时就是把代码嵌入到html页面中,就像现在的serverpage技术,如ASP,PHP,JSP。这种模式灵活,强大,但显得杂乱无章。如果你能够把逻辑程序逻辑在页面结构之外进行很好的组织,这种模式还是有它的优点的。

TransformView使用翻译方式。例如XSLT。如果你的领域数据是用XML处理的,那这种模式就特别的好用。

Controller模式

Controller有两种模式。一般我们会根据动作来决定一项控制。动作可能是一个按钮或链接。所这种模式就是ActionController模式。

架构设计是一种权衡(trade-off)。一个问题总是有多种的解决方案。而我们要确定唯一的架构设计的解决方案,就意味着我们要在不同的矛盾体之间做出一个权衡。我们在设计的过程总是可以看到很多的矛盾体:开放和整合,一致性和特殊化,稳定性和延展性等等。任何一对矛盾体都源于我们对软件的不同期望。可是,要满足我们希望软件稳定运行的要求,就必然会影响我们对软件易于扩展的期望。我们希望软件简单明了,却增加了我们设计的复杂度。没有一个软件能够满足所有的要求,因为这些要求之间带有天生的互斥性。而我们评价架构设计的好坏的依据,就只能是根据不同要求的轻缓急,在其间做出权衡的合理性。

1.目标我们希望一个好的架构能够:

规则

为了达到上述的目的,我们通常需要对架构设计制定一些简单的规则:

功能分解

我们使用功能分解的规则,有助于提高重用性,因为我们每个类和方法的精度都提高了。这是符合大自然的原则的,我们研究自然的主要的一个方向就是将物质分解。我们的思路同样可以应用在软件开发上。除了重用性,功能分解还能实现透明的目标,因为我们使用了功能分解的规则之后,每个类都有自己的单独功能,这样,我们对一个类的研究就可以集中在这个类本身,而不用牵涉到过多的类。

根据实际情况决定不同类间的耦合度

设计不同的耦合度有利于实现透明和延展。对于类的客户(调用者)来说,他不需要知道过多的细节(实现),他只关心他感兴趣的(接口)。这样,目标类对客户来说就是一个黑盒子。如果接口是稳定的,那么,实现再怎么扩展,对客户来说也不会有很大的影响。以前那种牵一发而动全身的问题完全可以缓解甚至避免。

够用就好:我们在上一章中就谈过敏捷方法很看重刚好够用的问题,现在我们结合架构设计来看:在同样都能够满足需要的情况下,一项复杂的设计和一项简单的设计,哪一个更好。从敏捷的观点来看,一定是后者。因为目前的需求只有10项,而你的设计能够满足100项的需求,只能说这是种浪费。你在设计时完全没有考虑成本问题,不考虑成本问题,你就是对开发组织的不负责,对客户的不负责。

应用模式

抽象

架构的本质在于其抽象性。它包括两个方面的抽象:业务抽象和技术抽象。架构是现实世界的一个模型,所以我们首先需要对现实世界有一个很深的了解,然后我们还要能够熟练的应用技术来实现现实世界到模型的映射。因此,我们在对业务或技术理解不够深入的情况下,就很难设计出好的架构。当然,这时候我们发现一个问题:怎样才能算是理解足够深入呢。我认为这没有一个绝对的准则。

因此,虽然做不到最优的业务抽象,但是我们完全可以在特定目的下,特定范围内做到最优的业务抽象。比如说,我们工作流可能的变化是工组流路径的变化。我们就完全可以把工作流的路径做一个抽象,设计一个可以动态改变路径的工作流架构。

有些时候,我们虽然在技术上和业务上都有所欠缺,没有办法设计出好的架构。但是我们完全可以借鉴他人的经验,看看类似的问题别人是如何解决的。这就是我们前面提到的模式。我们不要把模式看成是一个硬性的解决方法,它只是一种解决问题的思路。MartinFowler曾说:"模式和业务组件的区别就在于模式会引发你的思考。

架构的一些误解

我们花了一些篇幅来介绍架构的一些知识。现在回到我们的另一个主题上来。对于一个敏捷开发过程,架构意味着什么,我们该如何面对架构。这里我们首先要澄清一些误解:

误解1:架构设计需要很强的技术能力。从某种程度来说,这句话并没有很大的错误。毕竟,你的能力越强,设计出优秀架构的几率也会上升。但是能力和架构设计之间并没有一个很强的联系。即使是普通的编程人员,他一样有能力设计出能实现目标的架构。

架构设计的过程模式

方法论

方法论的英文为Methodology,词典中的解释为:“Aseriesofrelatedmethodsortechniques”,我们可以把它定义为软件开发(针对软件开发)的一整套方法、过程、规则、实践、技术。关于方法论出现的问题,我很赞同AlistairCockburn的一句话,“方法论源于恐惧。”出于对项目的超期、成本失控等等因素的恐惧,项目经理们从以前的经验出发,制定出了一些控制、监测项目的方法、技巧。这就是方法论产生的原因。

在AgileSoftwareDevelopment一书中,作者提到了方法论的十三个要素,基本能够函盖方法论的各个方面:

角色(Roles)、个性(Personality)、技能(Skills)、团队(Teams)、技术(Techniques)、活动(Activities)、过程(Process)、工件(Workproducts)、里程碑(Milestones)、标准(Standards)、质量(Quality)、工具(Tools)、团队价值(TeamValues)。

它们之间的关系可以用一幅图来表示:

图1.方法论的十三个要素

很多的方法论,都涉及了上面列举的十三要素中的部分要素,因此,我们可以把方法论看作是一个抽象的、无穷的超集,而现实中的方法论都是指超集的一个有限的子集而已。它们之间的关系就好像有理数和1到100之间的整数的关系一样。不论是XP,还是UI设计经验之类,都属于方法论的一个子集,只是这两个子集之间有大小的差别而已。我们还应该看到,讨论一个完备的方法论是没有意义的,因此这种方法论铁定不存在,就好像你视图穷举出所有的有理数一样荒唐。因此,我们关于一个通用的方法论的说法也是无意义的。好的方法论,比如说XP、水晶系列,它们都有一个适合的范围,因为它们了解一点,自己并不是一个无所不能的方法论。

在现实中,我们其实不断的在接触方法论。比如说,为了控制项目的进度,项目经理要求所有的开发人员每周递交一份详细的进度报告,这就是一种方法、一种技巧。如果把开发过程中的这些技巧系统的组织起来,就能够成为一种方法论。你可能会说,那一种方法论的产生也太容易了吧。不,这样产生的方法论并没有太大的实用价值,没有实用价值的方法论根本就没有存在的必要。因此,一个成功的方法论是要能够为多个的项目所接受,并且能够成功实现软件的交付的方法论。

我和我的同事在实践中做了一些试验,希望能够把一些好的方法论应用于开发团队。试验的结果很无奈,方法论实施的效果并不理想,一开始我们认为是方法本身的原因,到后来,我们发现事情并不是这么简单。在试验的过程中,开发人员一致认同方法论的优势所在,但是在实施过程中,鲜有坚持的下来的。在AgileSoftwareDevelopment中,我发现作者遇到了和我们一样的问题。

AlistairCockburn在和大量的项目团队的访谈之后,写成了AgileSoftwareDevelopment一书。在访谈之前,他笃定自己将会发现高度精确的过程控制是成功的关键所在,结果他发现事实并非如此,他把他的发现归结为7条定律。而我在实际中的发现也包含在这七条定律中,总结起来就只有两点:沟通和反馈。

因此,一个软件项目的成功和你采用的开发方法论并没有直接的关系。

重量

我们根据把拥有大量artifact(RUP官方翻译为工件,意思是软件开发过程中的中间产物,如需求规约、设计模型等)和复杂控制的软件开发方法称为重型(HeavyWeight)方法,相对的,我们称artifact较少的方法为轻型(LightWeight)方法。在传统的观念中,我们认为重型方法要比轻型安全许多。因为我们之所以想出重型方法,就是由于在中大型的项目中,项目经理往往远离代码,他无法有效的了解目前的工程的进度、质量、成本等因素。为了克服未知的恐惧感,项目经理制定了大量的中间管理方法,希望能够控制整个项目,最典型的莫过于要求开发人员频繁的递交各种表示项目目前状态的报告。

在PlanningXP一书中有一段讨论轻重型方法论的精辟论述,它把重型方法论归结为一种防御性的姿态(defensiveposture),而把轻型方法论归结为一种渴望成功(Plantowin)的心态。如果你是采用了防御性姿态,那么你的工作就集中在防止和跟踪错误上,大量的工作流程的制定,是为了保证项目不犯错误,而不是项目成功。而这种方法也不可谓不好,但前提是如果整个团队能够满足前面所提到的两个条件的话,项目也肯定会成功,但是重型方法论的一个弊端就在于,大家都在防止错误,都在惧怕错误,因此人和人之间的关系是很微妙的,要达到充分的沟通也是很难的。最终,连对人的评价也变成是以避免错误的多寡作为考评的依据,而不是成就。我们在做试验的时候,一位项目经理开玩笑说,“方法论源自项目经理的恐惧,这没错。但最糟糕的是整个团队只有项目经理一个人恐惧,如果能够做到人人的恐惧,那大家也就没有什么好恐惧的了。”这句话提醒了我们,如果一个团队的精神就是力求成功,那么这支团队的心态就和其它的团队不同了,尤其是对待错误的心态上。根本就没有必要花费大量的精力来预防错误,错误犯了就犯了,即时改正就可以了。这其实就是渴望成功的心态。

方法论的艺术

管理,被称为科学和艺术的融合体,而管理的艺术性部分很大程度的体现在人的管理上。我说,方法学,一样是科学和艺术的融合体。这是有依据的,其实方法论和管理学是近亲关系,管理学中有一门分支是项目管理,而在软件组织中,项目管理是非常重要的,方法学就是一种针对软件开发的一种特定的项目管理(或是项目管理的一个子集)。

重型方法最大的一个问题就在于他不清楚或忽略了艺术这个层次,忽视了人的因素,把人做为一个计量单位,一种资源,一种线性元素。而人的要素在软件开发中是非常重要的,软件开发实际上是一种知识、智力的转移过程,最终形成的产品是一种知识产品,它的成本取决于开发者的知识价值,因此,人是最重要的因素。而人这个要素是很难衡量的,每个人都有不同的个性、想法、经验、经历,这么多复杂的因素加在一起,就导致了人的不可预见性。因此,我们强调管人的艺术。

最简单的例子是,在重型方法中,我们的基本假设是对人的不信任。项目经理要控制项目。但不信任就会产生很多的问题,比如士气不高,计划赶不上变化,创新能力低下,跳槽率升高等等。人都是希望被尊重的,技术人员更看重这一点,而很多公司也口口声声说自己多么多么以人为本,可是采用的却是以不信任人为前提的开发方法,言行不一。我们说敏捷方法的出发点是相互信任,做到这一点是很难的,但是一旦做到了,那这个团队就是非常具有竞争力的。因此,这就产生了一个问题,在没有做到完全的相互信任之前,我们到底相不相信他人呢,这就是我提到的艺术性的问题,什么时候你要相信人?什么时候你不相信人,这些都是需要权衡的问题,也都是表现你艺术性的问题。

敏捷方法

Individualsandinteractionsoverprocessesandtools.

Workingsoftwareovercomprehensivedocumentation.

Customercollaborationovercontractnegotiation.

Respondingtochangeoverfollowingaplan.

而我对敏捷的理解包括了几个方面:

较低的管理成本和高质量的产出。软件开发存在两个极端:一个是没有任何的管理成本,所有的工作都是为了软件的产出,但是这种方式却往往导致软件开发过程的混沌,产品的低质量,团队士气的低落。另一个是大量管理活动的加入,评审、变更管理,缺陷跟踪,虽然管理活动的加入能够在一定程度上提高开发过程的有序性,但是成本却因此提高,更糟糕的是,很容易导致团队的低效率,降低创新能力。因此,敏捷方法试图寻找一个平衡点,用低成本的管理活动带来最大的产出,即软件的高质量。

尊重人性。敏捷方法尊重人性,强调效率。软件开发可以说是一种脑力的投入,如果不能保证开发人员的自愿投入,产品就肯定要打折扣。事实多次的证明,一个愿意投入的开发人员和一个不愿意投入的开发人员效率相差在三倍以上,对组织的贡献更是在十倍以上。

沟通和反馈是一切的基础。我们已经讨论过沟通的重要程度,而即时的反馈是拥抱变化的前提条件。

客户是上帝。没有客户就没有一切,客户的重要性可以用一句话来形容,就是以合理的成本建造合适的软件(buildtherightsystemattherightcost)。

敏捷其实也有轻重之分,关键在于是否能够做到有效和灵活。因此,敏捷方法论提倡的一个思想是“刚好够(barelysufficient)”。不过这个“刚好够”可不是那么容易判断的。一支8个人的团队采用XP方法,随着方法的熟练使用,团队的能力在不断的增强,能够处理的问题越越来越复杂,也许他们能够处理采用重型方法的20个人团队能够处理的问题。可是如果团队的人数突然增加到12人,这支团队肯定就会出问题,他的表现可能还不如那支20个人的团队了。人数增加的时候,原先的方法肯定还做适当的调整,比如说,在原先的敏捷方法上增加一些重型方法的技巧。我们不能够要求一支6个人的团队和一支20个人的团队用同样的方法,前者可能采用轻一些的敏捷方法,后者可能采用重一些的敏捷方法,关键的问题在于,两支团队都把重点放在沟通、反馈、频繁交付软件这些关键的因素上,也就是做到有效和灵活。

架构设计

架构(Architecture)(也有被称为体系结构的)是软件设计中非常重要的一个环节。软件开发的过程中只要需求和架构确定之后,这个软件就基本上可以定型了。这就好比骨骼确定了,这个人的体形就不会有很大的变化。因此我选择了架构设计来讨论敏捷软件开发(需求我已经写过了)。我们在前面讨论过超集和子集的概念,因此我们接下去要讨论的架构设计也是一个很小的子集。方法论如果没有经历过多个项目的检验是不能称为成功的方法论的,我也并不认为我的架构设计就是一个好的方法论,但引玉还需抛砖,他的主要目的是为了传播一种思想。因此,我采用了模式语言(PLOP)做为写作架构设计的形式,主要的原因就是模式是一种很好的组织思想的方法。

从需求到架构

在需求阶段,我们可以得到一些代表需求调研成果的中间产物。比如说,CRC卡片、基本用例模型、用户素材、界面原型、界面原型流程图

团队设计是敏捷方法论中很重要的一项实践。我们这里说的团队,指的并不是复数的人。一群人就是一群人,并没有办法构成团队。要想成为团队,有很多的工作要做。我们之所以考虑以团队

架构设计中的方法学(5)——简单设计

在软件开发领域,最为常见的设计就是"CodeandFix"方式的设计,设计随着软件开过程而增长。或者,我们可以认为这种方式根本就不能算是设计,它抱着一种船到桥头自然直的态度,可是在设计不断改动之后,代码变得臃肿且难以理解,到处充满着重复的代码。这样的情形下,架构的设计也就无从谈起,软件就像是在风雨中的破屋,濒临倒塌。

针对于这种情形,新的设计方式又出现了,MartinFowler称这种方式为"PlannedDesign"。和建筑的设计类似,它强调在编码之前进行严格的设计。这也就是我们在团队设计中谈到的架构设计师的典型做法。设计师们通常不会去编程,理由是在土木工程中,你不可能看到一位设计师还要砌砖头。

"PlannedDesign"较之"CodeandFix"进步了许多,但是还是会存在很多问题。除了在团队设计中我们谈的问题之外,需求变更将会导致更大的麻烦。因此,我们理所当然的想到进行"弹性设计":弹性的设计能够满足需求的变更。而弹性的设计所付出的代价就是复杂的设计。

题外话:

这里我们谈论"PlannedDesign"引出的一些问题,并没有任何排斥这种方式的意思。"PlannedDesign"还是有很多可取之处的,但也有很多需要改进的地方。事实上,本文中我们讨论的架构设计方式,本质上也是属于"PlannedDesign"方式。和"PlannedDesign"相对应的方式是XP所主张的"EvolutionaryDesign"方式,但是这种方式还有待于实践的检验,并不能简单的说他就一定要比"PlannedDesign"先进或落后。但可以肯定的一点是:"EvolutionaryDesign"方式中有很多的思想和技巧是值得"PlannedDesign"借鉴的。

解决方法:

粗看之下,会有很多开发人员认为这是不切实际的口号。我能理解这种想法,其实,在我热衷于模式、可重用组件技术的时候,我对XP提倡的简单的口号嗤之以鼻。但在实际中,我的一些软件因为复杂设计导致开发成本上升的时候,我重新思考这个问题,发现简单的设计是有道理的。

降低开发的成本

不论是模式,可重用组件,或是框架技术,目的都是为了降低开发的成本。但是他们的方式是先进行大量的投入,然后再节省后续的开发成本。因此,架构设计方面的很多思路都是围绕着这种想法展开的,这可能也是导致开发人员普遍认为架构设计高不可攀的原因。XP的方式恰恰相反,在处理第一个问题的时候,不必要也不可能就设计出具有弹性、近乎完美的架构来。这项工作应该是随着开发的演进,慢慢成熟起来的。我不敢说这种方式肯定正确,但是如果我们把生物的结构视同为架构,这种方式不是很类似于自然界中生物的进化方式吗?

提升沟通的效率

我们在团队设计中已经谈过了团队设计的目标之一就是为了降低沟通的成本,以期让所有人都能够理解架构。但是如果架构如果过于复杂,将会重新导致沟通成本的上升,而且,这个成本并不会随着项目进行而降低,反而会因为上面我们提到的遇到新的问题导致沟通成本的持续上升。

简单的架构设计可以加快开发团队理解架构的速度。我们可以通过两种方式来理解简单的含义。首先,简单意味着问题的解不会非常的复杂,架构是解决需求的关键,无论需求再怎么复杂多变,总是可以找出简单稳定的部分,我们可以把这个简单稳定的部分做为基础,再根据需要进行改进扩展,以解决复杂的问题。在示例中,我们提到了measurementpattern,它就是按照这种想法来进行设计的。

考虑未来

我们之所以考虑未来,主要的原因就是需求的不稳定。因此,我们如果考虑未来可能发生的需求变化,就会不知觉的在架构设计中增加复杂的成分。这违背的简单的精神。但是,如果你

迭代是一种软件开发的生命周期模型,在设计中应用迭代设计,我们可以得到很多的好处。

在软件生命周期中,我们如何对待架构设计的发展?

架构设计往往发生在细节需求尚未完成的时候进行的。因此,随着项目的进行,需求还可能细化,可能变更。原先的架构肯定会有不足或错误的地方。那么,我们应该如何对待原先的设计呢?

我们在简单设计模式中简单提到了"PlannedDesign"和"EvolutionaryDesign"的区别。XP社团的人们推崇使用"EvolutionaryDesign"的方式,在外人看来,似乎拥护者们从来不需要架构的设计,他们采用的方式是一开始就进入代码的编写,然后用Refactoring来改进代码的质量,解决未经设计导致的代码质量低下的功能。

从一定程度上来说,这个观点并没有错,它强调了代码对软件的重要性,并通过一些技巧(如Refactoring)来解决缺乏设计的问题。但我并不认同"EvolutionaryDesign"的方式,在我看来,一定程度上的"PlannedDesign"是必须的,至少在中国的软件行业中,"PlannedDesign"还没有成为主要的设计方向。借用一句明言,"凡事预则立,不预则废",在软件设计初期,投入精力进行架构的设计是很有必要的,这个架构是你在后续的设计、编码过程中依赖的基础。但是,一开始我们提到的设计改进的问题依然存在,我们如何解决它呢?

在简单设计模式中,我们提到了设计改进的必要性,但是,如果没有一种方法去控制设计的改进的话,那么设计改进本身就是一场噩梦。因此,何时改进,怎么改进,如何控制,这都是我们需要面对的问题。

解决方法

为了实现不断的改进,我们将在开发流程中引入迭代的概念。迭代的概念在《需求的实践》中已经提到,这里我们假设读者已经有了基本的迭代的概念。

软件编码之前的工作大致可以分为这样一个工作流程:

上图中的流程隐含着一个信息的损失的过程。来自于用户的需求经过整理之后,开发人员就会从中去掉一些信息,同样的事情发生在后面的过程中,信息丢失或变形的情况不断的发生。这里发生了什么问题?应该说,需求信息的失真是非常普遍的,我们缺少的是一种有效的办法来抑止失真,换句话说,就是缺少反馈。

如果把眼睛蒙上,那我们肯定没有办法走出一条很长的直线。我们走路的时候都是针对目标不断的调整自己的方向的。同样的,漫长的软件开发过程如果没有一种反馈机制来调整方向,那最后的软件真是难以想象。

迭代(Iterate)设计,或者我们称之为增量(Incremental)设计的思想和XP提倡的EvolutionaryDesign有异曲同工之妙。我们可以从XP、Crystal、RUP、ClearRoom等方法学中对比、体会迭代设计的精妙之处:每一次的迭代都是在上一次迭代的基础上进行的,迭代将致力于重用、修改、增强目前的架构,以使架构越来越强壮。在软件生命周期的最后,我们除了得到软件,还得到了一个非常稳定的架构。对于一个软件组织来说,这个架构很有可能就是下一个软件的投入或参考。

TIP:现实中迭代设计退化为"CodeandFix"的设计的情况屡见不鲜("CodeandFix"参见简单设计)。从表面上看,两者的做法并没有太大的差别,都是针对原有的设计进行改进。但是,二者效果的差别是明显的:"CodeandFix"是混沌的,毫无方向感可言,每一次的改进只是给原先就已摇摇欲坠的积木上再加一块积木而已。而迭代设计的每一次改进都朝着一个稳定的目标在前进,他给开发人员带来信心,而不是打击。在过程上,我们说迭代设计是在控制之下的。从实践的经验中,我们发现,把原该在目前就该解决的问题退后是造成这一问题的主要原因之一。因此,请严格的对待每一次的迭代,确保计划已经完成、确保软件的质量、确保用户的需求得到满足,这样才是正统的迭代之路。

准确的说,这里谈不上设计,只是简单让客户端访问不同的视图而已。当然,在设计的示意图中,我们并没有必要画出所有的视图来,只要能够表达客户端和视图的关联性就可以了。

(架构设计需要和具体的实现绑定,但是在这个例子中,为了着重体现设计的演进,因此把不必要的信息都删掉。在实际的设计中,视图可能是JSP页面,也可能是一个窗口。)

第一个迭代周的任务很快的完成了,小组负责的表示层模块也很顺利的和其它小组完成了对接,一个简陋但能够运转的小系统顺利的发布。客户观看了这个系统的演示,对系统提出了修改和补充。

第二迭代周中,模块要处理的视图增加到了30个,视图之间存在相同的部分,并且,负责数据层的小组对我们说,由于客户需求的改进,同一个视图中将会出现不同的数据源。由于我们的视图中直接使用了数据层小组提供给我们的数据源的函数,这意味着我们的设计需要进行较大的调整。

考虑到系统的视图的量大大的增加,我们有必要对视图进行集中的管理。前端控制器(FrontControl)模式将会是一个不错的技巧。对于视图之间的普遍的重复部分,可以将视图划分为不同的子视图,再把子视图组合为各种各样的视图。这样我们就可以使用组合(Composite)模式:

客户的请求集中提交给控制器,控制器接受到客户的请求之后,根据一定的规则,来提供不同的视图来反馈给客户。控制器是一个具有扩展能力的设计,目前的视图数量并不多,因此仍然可以使用控制器来直接分配视图。如果视图的处理规则比较复杂,我们还可以使用创建工厂(CreateFactory)模式来专门处理生成视图的问题。对于视图来说,使用组合模式,把多个不同数据源的视图组合为复杂的视图。例如,一个JSP的页面中,可能需要分为头页面和尾页面。

项目进入第三个迭代周期之后,表示层的需求进一步复杂化。我们需要处理权限信息、需要处理数据的合法性判断、还需要面对更多的视图带来的复杂程度上升的问题。

表示层的权限处理比较简单,我们可以从前端控制器中增加权限控制的模块。同时,为了解决合法性判断问题,我们又增加了一个数据过滤链模块,来完成数据的合法性判断和转换的工作。为了不使得控制器部分的功能过于复杂,我们把原先属于控制器的视图分发功能转移到新的分发器模块,而控制器专门负责用户请求、视图的控制。

架构设计中的方法学(7)——组合使用模式

请注意迭代的前提:需求的易变性。因此,对于那些需求容易发生变化的项目,我们就可以使用迭代式的开发过程,虽然我们会付出一些额外的成本(刚开始这个成本会比较大,但可以用较长的迭代周期来降低这种成本),但是风险减小了。而对于需求比较固定的项目,

是不是有必要使用迭代的方法,就要看具体的环境了。因此,我们是根据实际的情况选用开发方法,而不是因为先进或是流行的原因。

各模块的关联程度。在软件开发中,我们有时候很难把一些模块分离开来,要开发模块A,就需要模块B,而模块B又需要模块C。各模块的关联程度越高,迭代周期越长。当然,也相应的解决方法,我们可以在各模块的功能中选取出一些关键点,作为里程碑,以里程碑作为迭代完成点。

简单和迭代

简单和迭代关系是双向的。

在现实设计我们很难界定出简单设计的程度。怎样的架构设计才算是简单?按照我们在简单设计模式中的讨论,刚好满足目前的需求的架构设计就算是简单的设计。但是,从另外一个方面考虑,需求的易变性限制我们做出简单的设计,因为我们不能够肯定目前的需求将来会发生什么样的变化。因此,为了克服对未知的恐惧,我们花了很大的力气设计一些灵活的、能够适应变化的架构。这是源自需求模式对简单设计模式的影响。

源自需求和迭代设计的关系的讨论建议我们把需求分为多个迭代周期来实现。那么,相应的架构设计也被分在多个迭代周期中。这样的方法可以降低架构设计的复杂程度。因为设计人员不需要考虑软件的全部需求,而只需要考虑当前迭代周期的需求。复杂性的降低将会有助于架构设计的简单化,从而达到简单设计的一系列的好处(参见简单设计)。

因此,我们需要学会权衡利弊,是否有必要投入大量的资源来开发其实并没有那么有用的功能。因此,迭代设计和简单设计的结合有助于我们摆脱过度设计的困扰,把精力集中在真正重要的功能之上。

此外,简单的设计并不等同于较少的付出。简单的设计往往需要对现实世界的抽象,回忆我们在简单设计中讨论的测量模式的例子,它看似简单,但实现起来却需要大量的业务知识、很强的设计能力。因此,做到简单是程序员不断追寻的目标之一。

团队和简单

我们在简单设计中提过简单设计需要全面的设计师。除此之外,它还需要团队的配合。简单意味着不同活动间交付工件的简单化。也就是说,类似于需求说明书、设计文档之类的东西都将会比较简单。正因为如此,我们很难想象一个地理上分布在不同地点的开发团队或一个超过50人的大团队能够利用这种简单的文档完成开发任务。

因此,简单的设计是需要团队的组织结构来保证的。简单的设计要求团队的相互沟通能够快速的进行。架构设计完成后,架构的设计思路传达给所有的编码人员的速度要块,同样,编码中发现问题,回馈给设计者,设计者经过改进之后再传达给收到影响的编码人员的速度也要快。象这样高效率的传播我们可以称之为"HotChannel"。

为了保证"HotChannel"的高沟通效率,最好的组织单位是开发人员在3到6人之间,并处于同间工作室中。这样的结构可以保证讯息的交互速度达到最高,不需要付出额外的沟通成本,也不需要过于复杂的版本控制工具或权限分配。根据我的经验,一个共享式的小型版本控制工具、网络共享、再加上一个简单的网络数据库就能够解决大部分的问题了。

在理论上,我们说只要分配得当,大型的团队同样可以组织为金字塔式的子团队,以提高大型团队的工作效率。但是实际中,随着团队的人数的增加,任务的正确分配的度也随之加大,沟通信息上传下达的效率开始下降,子团队间的隔阂开始出现,各种因素的累加导致敏捷方法并不一定适合于大型的团队,因此我们讨论的敏捷方法都将受到团队的特性的限制。

模式的源头

如果你对XP有一定的了解的话,那么你可能会感觉到我们讨论的模式中应用了XP的实践。确实如此,XP中有很多优秀的实践,如果组织得当的话,这些微小的实践将会组合成为一套了不起的开发方法。不过,目前的软件开发混乱的现状阻止了先进的软件方法的应用,对一个身体虚弱的病人施以补药只会适得其反。因此,在前面讨论的模式中,我们应用了一些容易应用、效果明显的实践方法。在实践中适当的应用这些方法,并不需要额外的投入,却能够有很好的效果,同时还会为你的团队打下一个良好的基础

我们从源自需求模式中,学习到架构的设计是来自于需求的,而应用于软件全局的架构则来自于最重要的需求。还记得我们在那个模式中提到的网上宠物店的例子吗?系统采用了MVC模式,sun的官方文档一开始说明了为什么采用MVC模式,MVC模式解决了什么

问题,然后开始分析MVC模式的几个组成部分:Model、View、和Controll。其实,MVC中的每一个部分,在真正的代码中,大都代表了一个子系统,但是在目前,我们就非常的清楚系统大致上会是一个什么样子,虽然这时候它还十分的朦胧。

不要视图在全局的架构愿景中就制定出非常细致的规划,更不要视图生成大量的实际代码。因为,你的架构愿景还没有稳定(我们在其后的稳定化的模式中将会讨论稳定的问题),还没有获得大家的同意,也没有经过证明。因此,从整个的开发周期来看,全局架构愿景是随着迭代周期的进行不断发展、修改、完善的。

子模块级、或是子问题级的架构愿景

这时候的架构愿景已经是比较明确的了,因为已经存在明确的问题域。例如界面的设计、领域模型的设计、持久层的设计等。这里的愿景制定本质上和全局的愿景制定差不多,具体的例子我们也不再举了。但是要注意一点,你不能够和全局愿景所违背。在操作上,全局愿景是设计团队共同制定出来的,而子模块级的架构愿景就可以分给设计子团队来负责,而其审核则还是要设计团队的共同参与。这有两个好处,一是确保各个子模块(子问题)间不至于相互冲突或出现空白地带,二是每个子设计团队可以从别人那里吸取设计经验。

我们在这个层次的愿景中主要谈一谈子模块(子问题)间的耦合问题。一般来说,各个子模块间的耦合程度相对较小,例如一个MIS系统中,采购和销售模块的耦合度就比较小,而子问题间的耦合程度就比较大,例如权限设计、财务,这些功能将会被每个模块使用。那么,我们就需要为子模块(子问题)制定出合同接口(ContactInterface)。合同的意思就是说这个接口是正式的,不能够随意的修改,因为这个结构将会被其它的设计团队使用,如果修改,将会对其它的团队产生无法预计的影响。合同接口的制定、修改都需要设计团队的通过。此外,系统中的一些全局性的子问题最好是提到全局愿景中考虑,例如在源自需求模式中提到的信贷帐务的例子中,我们就把一个利息计算方式的子问题提到了全局愿景中。

代码级的愿景

严格的说这一层次的愿景已经不是真正的愿景,而是具体设计了。但是我们为了保证对架构设计理解的完整性,还是简单的讨论一下。这一个层次的愿景一般可以使用类图、接口来表示。但在类图中,你不需要标记出具体的属性、操作,你只需要规定出类的职责以及类之间的相互关系就可以了。该层次愿景的审核需要设计子团队的通过。

架构愿景的形成过程

架构愿景的形成的源头是需求,需要特别指出的是,这里的需求主要是那些针对系统基本面的需求。比如说,系统的特点是一个交互式系统,还是一个分布式系统。这些需求将会影响到架构愿景的设计。在收集影响架构愿景的各项需求之后,按照需求的重要性来设计架构愿景。

值得注意的是,架构远景可能会有多种的视角,下文讨论了一种设计模式的视角。但是实际设计中还可能会基于数据库来设计架构愿景。但在企业信息系统的设计中,我推荐使用领域类的设计,也就是下文中讨论的例子。

架构愿景设计好之后,问题的焦点就转到如何传播架构愿景上来,为了达到在开发团队中取得统一设计意图的效果,可以考虑援引团队设计模式。除此之外,针对性的项目前期培训也会是一种有效的做法。

使用架构模式

假设我们需要设计分布式的交互式系统。分布式系统和交互式系统都有特定的架构模式,前者为Broker模式,后者为MVC模式。首先我们先要根据系统的特点的重要程度来排列模式的顺序。这里假设需求中分布式特性更重要一些。那么我们首先选择Broker模式作为架构的基本模式:再考虑交互式的特点,根据MVC模式的特点,我们需要从目前的基本架构中识别出Model、Controller、以及View。Model和View都很简单,分别分布在上图中的Server和Client中。而Controller则有两种的选择,假设这里的Controller部署在客户端,上图则演化为下图:这样,基础的架构愿景就已经出现了。如果我们还有更多的需求,还可以继续改进。但是,记住一点,架构愿景不要过于复杂。正如我们在上一节中所讨论的,这里我们虽然是基于设计模式来讨论架构愿景,但是实际中还有很多从其它的视角来看待架构愿景的。至于要如何选择架构愿景的视角,关键的还是在于需求的理解。

1,您好,请先向我们的网友简单做一下自我介绍自己好吗?

我05年9月开始到盛大网络,任架构师一职。当时BorlandChina也有offer,但在顾问、软件工程师与架构师之间,我选择了架构师这个职务,因为我对这个角色更加感兴趣。我目前的工作,主要是盛大的软件平台方面的架构、设计和一些实施方面的事务。虽然很多人认为盛大是做游戏的公司,但我基本不涉及游戏产品的开发。

在开发技术方面,我03年出版过一本《Delphi源代码分析》。在工程方面,《大道至简——软件工程实践者的思想》一书在下月初就应出版了,它的第一版是以电子版的形式发布的。我在写的第三本书则是讲计算机语言的,题材是“动态函数式语言”。

2,您做为盛大网络的架构师,请介绍一下在软件项目中平台架构师是一份怎样的角色?主要处理哪些工作?

架构师有很多种。很多人把体系架构师与架构师等同,其实不对。各类架构师基本素质要求大抵一致,例如分析能力、设计的技术方法,以及对设计目标的前瞻性。但是他们的专业素质会有一些差别。举个实例来说,如果让我设计游戏引擎的架构,我就会做不好。但是,如果这个游戏引擎要设计成一个独立的平台层次,具有语言无关性、平台整合能力,或是对不同类型游戏的统一支撑,那么就是平台架构师的职责了。

具体来说,平台架构师会决策某个部分与其它部分的相互关系、界面的规约和检测评估它们的方法。如果一个游戏引擎只为某个游戏而设计,那么是用不到平台架构师的。但如果A游戏中的引擎要移植到B游戏,或者更多的游戏,甚至只是抽离它的部分,以作为某种体系中的一个数据交互层,那么就需要平台架构师来考量技术上的可行性、稳定性以及它对于更大范围内的平台建设的价值——当然,如果没有价值,架构师也会否定它。

平台是长期建设的。平台架构师的重要职责之一,就是长期的规划和持续的推进。所以平台架构师的工作总是伴随客户的战略决策的。如果一个设计只是解决短期的技术问题,那么也并不需要平台架构师,但如果是几年或十几年要在上面持续经营的一个整体方向,那么平台架构师就需要围绕战略来设计架构的蓝图,并决定规划的实施步骤。在这些方面,他可能需要协调很多团队一些来工作。不过,这可不是跟项目经理抢饭碗。因为项目经理重在实施,而架构师重在规划。

当然,事实上我也做一些其它类型的架构设计工作。例如设计一个小的模块,或者一个业务工件。好的架构师不会拒绝这些工作,而是从更多的、细节的工作中发现整体与局部的关系。也只有触及到具体工作的细节,架构师才可能更早地发觉设计上的隐患或者与目标的偏差。

这几个问题我基本上都在《杀不死的人狼》一文中讲过了。概括来说,我认为有以下三点:

一、讨论“有或没有”银弹这样的话题没有意义,因为《人月神话》所述的人狼根本杀不死,而且Brooks所设想的银弹也过于学术。二、《人月神话》从广义工程的角度设定了这个命题,这个命题的根本目标与次要目标正好与具体工程(狭义工程)相反。三、我承认《人月神话》神话所述的答案以及建议在如今的软件工程中得到了体现。但我们应该更清醒地辨析出现象、答案与本质,并分析哪些是本质的自然延伸,而哪些只是《人月神话》所带来的影响——Brooks预言了未来,也就改变了未来,即使未来未必应该如此。

我并不反对《人月神话》中的大多数工程观点,以及我们现在的软件业中的工程实践经验。但是狭义工程没有必要去追寻银弹或那些看起来看银弹的东西,我们应该更加灵活。

4企业在进行项目的软件架构设计时,需要考虑哪些关键的问题?

企业实施过程中的架构问题,可以分成两个部分来考虑。一个是软件企业自身,一个是工程的目标客户(有些时候它与前者一则)。基本上来说,架构设计首先是面向客户的,甚至在整个工程的绝大多数时候都面向客户。因为理解决定设计,所以让架构师尽可能早地、深入地了解工程目标、应用环境、战略决策和发展方向,是至关重要的。否则,架构师是不可能做出有效的设计来的。

稳定性由架构师的设计能力决定。架构的好坏是很难评判的,但基本的法则是“适用”。如果一个架构不适用,那么再小或者再大都不可能稳定。所因此进一步推论是“架构必须以工程的主体目标为设计象”。看起来这是个简单的事,但事实上很多架构设计中只是在做边角功夫,例如为一两处所谓的“精彩的局部”而叫好,全然不顾架构是否为相应的目标而做。

持续性由架构师的地位决定。如果不能认识“设计的一致性”,以及架构师对这种一致性的权威,那么再好的架构也会面临解体,再长远的架构也会在短期内被废弃。架构的实施是要以牺牲

自由性为代价的,架构师没有足够的地位(或权威),则不可能对抗实施者对自由的渴望。通常的失败,并在于架构的好或坏,而是架构被架空,形同虚设。

代价的问题上面有过一点讨论,但方向不同。这里说明的是,如果架构师没有充分的经验,不能准确评估所设计的架构的资源消耗,那么可能在项目初起便存在设计失误;也可能在项目中困于枝节,或疏离关键,从而徒耗了资源。这些都是架构师应该预见、预估的。

最后说明一下,我认为目前大多数的企业项目都缺乏架构上的考量。大多数软件公司只是出于自身的需要(例如组件化和规模开发)而进行架构设计。这样的设计不是面向客户的,事实上这增加了客户投资,而未能给客户项目产生价值。这也是我强调架构面向客户的原因之一。

5目前,你的团队在使用什么样的产品或者方法来进行软件架构设计?

架构设计的主要输出是文档,因而并没有什么特别的工具来帮助你做架构设计。很多工具是辅助分析的,例如MindMananger;另外一些则可能辅助你表述,例如Together和Rose。

大多数技术出身的架构师会仅把“软件编写的东西”才称为工具。其实不然,会议室里的那面白板也是我的工具之一。放开思路,市场规划图、技术架构路标图、特性/收益规划图等等这些图表也是我们的工具。除开这些之外,模式语言和建模语言也是主要的、形式化的工具。

我经常按RUP的规范写文档,也偶尔放弃其中的某些具体格式。这些既有的文档模板也是工具。当然,毋庸置疑的是这样的工具也包括WORD和PowerPoint——很多人并不知道,我有1/4的设计是先用PowerPoint/Visio来完成的。

具体到方法,则非常多了,但应用哪一种则与场景有关。不过最先做的则是分层,这与自顶向下的结构分析很象——事实上在分析和设计的最初阶段,这种方法几乎是必须的。

6,您觉得国内外软件架构设计这个环节的主要不同在哪里?

正如你这个问题所表现出来的一样:我们太注重于工程环节的某个局部。

国外软件行业在工程实践经验上已丰富得多,因此大多数程序员、项目经理或测试人员等等对工程的理解也深刻得多。他们并不自恃于当前的环节,也不否认其它环节。这意味着在整体实施

中大家更容易达成一致。然而国内的软件工程则很少强调这种合作,项目经理强调管理,程序员强调技术,架构师强调一致性和持续性,测试人员则很开心的看到每一个错误并以及数量作为评核依据。

显然这里出了问题:我们的合作环节在各自为战。大家都在强调自己的重要性,于是工程就没法做了。解决的法子,还是让大家都意识到对方工作的目标与职责,而不仅仅是了解自己的那个小圈子。

7,可以介绍一下你目前的Qomo项目吗?我们的网友该如何参与?

QomoV1只是整个QomolangmaOpenProject构想中的一很小一部分——尽管它重要。Qomo项目提出的整体目标是:-Qomo内核是足够强大的能应用在不同的JavaScript宿主环境下的通用扩展。-Qomo有能力提供胶合不同的应用环境下功能需求的中间代码。-Qomo可以作为定制的宿主应用的代码包的一个部分以提升应用的体验或局部性能。

所以QomoV1并不完备。即便是我们正在展开的QomoV2,也并不完备。V2计划提供组件库、数据库存取层和图形表现层。此外,QomoV2也打算启用数个实践项目,一方面作为Qomo的范例,另一方面也验证Qomo的设计。

Qomo已经在sourceforge上注册过,但在那里表现并不活跃。你可以总是从我的blog上得到Qomo的最新消息,包括Qomo的计划与每个版本发布。至于参与这个项目,请发mail给我。

THE END
1.javassm宠物管理系统毕业论文.docxPAGE 毕业设计题 目:宠物管理系统作 者:学 号:所属学院:专业年级:学校导师:职 称:班级导师:职 称:完成时间:目 录 TOC \o 1-2 \h \z \u 摘 要 I Abstract II 第1章 前 言 2 1.1 研究背景 3 1.2 研究现状 3 1.3 系统开发目标 3 第2章 系统开发环境 5 2.1 SSM框架 5 2.2 JAVA简介 6 2.3...https://max.book118.com/html/2022/0611/8027051053004107.shtm
2.医院医嘱管理系统的设计与实现(毕业设计)毕业设计ssm基于java的医院住院管理系统的设计与实现+jsp源码含文档含教程 后台是ssm框架,页面是jsp,数据库mysql,jdk1.8,开发工具用ecplise、myecplise、sts、idea都可以 医院住院管理系统在Eclipse环境中,使用Java语言SSM框架。系统可以提供信息显示和相应服务,其管理员查看住院病人消费金额统计报表,管理医生与护士的资料,...https://www.iteye.com/resource/weikun19850312-2359422
3.基于SSM的宠物领养系统的设计与实现3.功能设计 本系统会员分为游客、用户、管理员三个角色。系统结构图所示: 管理员权限: (1)管理员具有管理用户的权限主要是:删除违反协议、长时间不登录等用户的用户信息。 (2)管理员具有管理宠物的权限主要是发布新宠物信息、删除已死亡宠物信息、修改宠物领养助养状态信息、审核用户发布的宠物等。 https://developer.aliyun.com/article/1375390
4.2015级本科生毕业设计(论文)选题情况学生学号专业班级课题题目题目类型指导教师职称李正浩201511010126计算机科学与技术卓计本1501基于Web的大学生作业管理系统设计-应用研究郑向伟教授曲晓帆201511010130计算机科学与技术卓计本1501大学生上网情况与学业成绩的关系论文-基础应用研究王新华教授李孟娜201511010http://www.ischool.sdnu.edu.cn/info/1408/7275.htm
5.计算机毕业设计之SSM宠物领养救助系统平台前端:bootstrap jsp模板引擎 ajax jQuery 百度echarts图表 后端:ssm框架 maven tomcat 数据库:mysql 运行截图 宠物领养救助系统 宠物领养救助系统 宠物领养救助系统 宠物领养救助系统 宠物领养救助系统 宠物领养救助系统 宠物领养救助系统 宠物领养救助系统 宠物领养救助系统 不同意领养列表 宠物管理 宠物知识板块 宠物知识...https://www.jianshu.com/p/c6e91a9b8329
6.毕业设计宠物医院管理系统messageInfo宠物医院管理系统 运行图片 设计原型 涉及终端 , 后台管理系统 搭建框架 涉及多个版本, ssm, springboot微服务版本 前端使用vue,小程序使用原生进行开发 数据库是用 mysql 8.0 后台设计技术栈: logback 日志输出, Springboot2.5, mybatis-plus, swagger https://www.cnblogs.com/studyexperience/p/18121302
7.JavaWeb代码实例下载浏览59评论0下载4牛币7毕业设计Java zdmxjxjLV117月16日 精集成了微信公众号、工作流(activiti)可视化界面的OA开发框架,SSM 项目描述可以作为作企业OA开发框架,java jsp mysql ssm结构,集成了微信公众号管理、数据库备份 逆向 代码生成、可视化的activiti操作界面,可以在线创建流程、部署等,也可用作学习。运行环境jdk...https://www.zuidaima.com/code/java/web.htm
1.基于servlet+jsp实现的宠物诊所系统(源码+数据库+文档报告)资源...2、系统需求概述“爱心”宠物诊所的职员在工作中需要查阅和管理如下信息:诊所的兽医、客户以及客户的宠物。 3、系统总体结构系统设计时基于MVC设计模型,采用三层架构 4、系统设计 1.关键抽象从需求中可以得出系统的如下关键抽象:兽医、专业特长、宠物主人、宠物类型、宠物和宠物的访问。这些实体可以设计为JavaBean类,例如...https://download.csdn.net/download/2301_78772942/89971478
2.计算机毕设答辩常见问题真实记录2023腾讯云开发者社区7、基于Java的网上租车管理系统的设计与实现 答辩记录: (1)是否考虑设计手机小程序? 答:考虑过,但难度略大 (2)论文图片不清晰 (3)参考文献不规范且未按顺序排列如6、8、10、20。 (4)建议摘要重写,第一段简洁些,第二段口水话太多。 (5)关键词去掉“数据库”和“框架”。 (6)系统车辆状态更新不及时。 https://cloud.tencent.com/developer/article/2343942
3.库存管理系统uml数据库课程设计 题目:小型超市管理系统 1、项目计划 1.1系统开发目的 (1)大大提高超市的运作效率; (2)通过全面的信息采集和处理,辅助提高超市的决策水平; (3)使用本系统,可以迅速提升超市的管理水平,为降低经营成本, 提高效益,增强超市扩张力, 提供有效的技术保障。 https://www.zboao.com/cgal/9126.html
4.web大作业基于Web的宠物社交网络平台开发设计基于JSP+Servlet的毕业生离校管理系统(源码+论文) 立即获取 查看详情 JSP项目 源码+数据库 基于JSP和SQL Server实现的网上招标系统 立即获取 查看详情 JSP项目 源码+数据库 基于JSP和SQL Server 2008实现的网上手机销售系统 立即获取 查看详情 JSP项目 源码+数据库 ...https://cs-work.com/article/230201
5.软件研发工程师岗位职责17篇(全文)应用软件系统项目评审;应用软件项目疑难问题处理;应用软件疑难故障分析处理;软件人力资源组织/考评;应用软件开发团队组织;应用软件工程师集训学习;应用软件体系框架设计与定制;应用软件技术积累与探索;应用软件开发技术规范编制;应用软件的技术资料管理;应用软件知识产权等相关文档编制;应用软件的鉴定、认证; 应用软件的质量...https://www.99xueshu.com/w/fileya61xaaf.html
6....java源码vuejspspringbootssm框架的源码+论文打包下载springboot vue2 mysql医院管理系统 源码+文档 springboot vue2 mysql卫生健康系统 源码+文档 springboot vue2 mysql古典舞在线交流平台 源码+文档 springboot vue2 mysql员工绩效考核系统 源码+文档 springboot vue2 mysql图书进销存管理系统 源码+文档 springboot vue2 mysql在线宠物用品交易网站 源码+文档 springboot...https://www.bisheonline.net/onebs.php?id=2178
7.基于Java宠物用品购物商城管理系统的设计与实现基于javaweb宠物...2、设计系统的整体框架,包括版面设计和多线程并发设计实现无跳转异步页面刷新。 3、保证程序运行的稳定性、可靠性和安全性。 解决问题的思路: 1、通过搜集市面上的有的宠物商店资料熟悉产品管理的业务流程,归纳、整理出需求信息,并根据需求信息分析设计数据库和后台系统需要实现的各个模块,并通过迭代的方式进行整个网上...https://blog.51cto.com/u_16213718/8811540
8.2022年山东省春季高考统一考试招生专业类别考试模块建筑设计与管理类专业 机械制造类专业 设备维修类专业 机电技术类专业 自动控制类专业 电气技术类专业 电子技术类专业 化工技术类专业 环境保护类专业 服装工程类专业 纺织工程类专业 服装展演类专业64 车辆维修类专业 水上运输类专业70 运输管理类专业74 http://m.zk985.com/nd.jsp?id=2474
9....Sitemap企业网站建设明确网站页面 企业网站建设版面设计和文字设计 企业网站建设网页的版面编排 企业网站建设气泡...企业网站建设框架布局 企业网站建设遵循原则 企业网站建设gif格式图像的透明背景处理 企业网站建设PHP技术...企业网站建设建立旅游电子商业信用管理系统 企业网站建设国内销售环节电子商务化的现状及问题 企业网站建设...https://www.phpweb.com.cn/sitemap.html