【IT168 技术文章】
从这一篇开始,我们将会进入另一个不同的主题,和前面所讨论的模式专注于组织、过程、方法不同,以后介绍的模式更偏重于设计。但是过程、方法的影子依然在我们的讨论中隐约可见。
架构愿景是一个很简单的模式,在软件开发中所占的时间也很短。但是这并不意味着架构愿景不重要。相反,它会是设计过程不可或缺的一环。
Context
在单次的迭代开始阶段,我们已经收集好了单次迭代的需求。
Problem
架构和分析设计是密不可分的,有时候很难说得清楚架构的定义,但架构应该能够描述软件的整体。架构包括了软件的各个方面,但是每一个设计细节总是需要单独考虑,这时候就会出现设计细节之间、以及设计细节和架构之间的不一致。
架构设计的各个部分之间的设计冲突是很容易发生的。发生的概率及频率和团队的规模成正比、和沟通的频度及效果成反比。在很多次的项目开发过程中,我们发现了多处的相同功能的代码,原因是代码的作者并不知道别人已经实现了这个功能了。这可能只是浪费了一点精力,可如果不同模块间的设计冲突导致了软件无法正常运行的时候,我们就需要坐下来好好的审视,究竟发生了什么。
Solution
我们需要建立一个架构愿景。架构愿景应该能够提供软件全局视图,包括所有的重要部分,定义了各个部分的责任和之间的关系,而且还定义了软件设计需要满足的原则。而这个架构愿景的设计,应该是满足源自需求模式的,也就是说,部分的划分和部分的设计,都是根据需求而进行的。同时,架构愿景应该要能够满足架构的其它各种特点,例如简单、可扩展性、抽象性。简单来说,我们把架构愿景当作是一个mini的架构设计。
由于我们是在单次的迭代中讨论架构愿景,因此从整体上考虑,架构愿景是也是在不断的变化的。这是很自然的,因为架构愿景代表了架构的设计,架构愿景的演进代表了架构设计的演进。
架构的愿景是相对于一个范围来说的,在一个特定的软件功能范围之内,谈架构愿景才有实际的意义,例如针对软件的全局或某个子模块。在这个特定的范围中,订立了架构愿景之后,这个范围内的所有设计原则将不能违背架构愿景。这是非常重要的,是架构愿景的最大的用处。有了这样的保证,我们就可以保证设计的一致性和有效性。任何一项设计的加入,都能够融入到原先的架构中,使得软件更加的完善,而不是更加的危险。
当然,要做到这一点并不是一件容易的事情。特别需要指出的是,架构愿景模式仅仅是实现该目的的一条道路,并不是一个充分条件。如果在设计中愿景不能够贯彻其意志,或是愿景制定本身就存在问题,那么要想达到上述的效果,几乎是不可能的事情。此外,该模式仅仅只是达到该目的的第一步,我们在接下去的模式中会发现还需要很多方面的配合。
架构愿景的层次
我们根据架构适用范围的不同,把架构愿景分为几个类别讨论:
软件全局
软件全局的架构是我们所最关心的,因此也会花费最多的笔墨。
软件全局中的架构愿景一般很难具体化到代码级别,其实你会发现,就算是具体化到了代码级别,也会因为实际中存在的问题,导致代码没有太多的价值。因此,为软件全局设置的架构愿景可以以原则、或是模式名的方式体现,并用自然语言或伪代码描述。例如,可以为一个系统规定三层架构作为其愿景,并指出三层的分类原则。注意,我们需要指出分类原则,否则规定三层架构并没有太大的意义,因为三层架构随着实现平台的不同、开发人员的不同而有很大的差异,如果不能够规定一个可操作的规范,那么愿景是没有意义的。在Java环境下,我们可以这样说:
"客户端采用前端浏览器界面,业务逻辑采用servlet,配合JSP编写,浏览器到服务器的数据采用集中处理,具体的方法是在业务逻辑和前端浏览器之间采用Front Control模式,接受前端浏览器传送过来的数据,并指派给相应的业务逻辑处理。数据的合法性检验分为两个部分:和业务逻辑无关的基本合法性验证在前端使用Java Script处理,和业务逻辑相关的合法性验证在业务逻辑层处理,可以使用一个集中的servlet专门处理错误情况。"
而在Windows环境下,我们知道三层结构的分界和Java中的并不相同(关于这一点,下一篇的文章中将会有详细的描述),我们可以在业务逻辑层或显示层直接操纵数据,非常的方便,因此,在Windows中的架构愿景的描述又不一样。另外,在非面向对象的环境中,在分布式的环境中,在Lotus Notes的环境中,其架构的描述都不一样。
注意到,架构愿景的制定是根据不同的应用环境而变化的,这一点我们在文章的一开始就强调过,这里又出现了相同的问题。我们可以通过一个简单的例子来加深对这个问题的理解。在Java的环境下,特别是J2EE的环境下面,经典的设计思路是把数据库的一张表视作一个类,表中的每一行都是这个类的一个具体的实例,表的每一个字段对应了类的一个变量,类一般支持Find方法,来获取数据不同的实例。这是一种很自然的设计思路,而且可以通过CMP等技术来简化设计的繁琐步骤。可是,在Windows环境下,相信没有多少人会这么做。常用的处理方法是使用记录集(RecordSet)的方式,也就是说针对一组的记录来进行操作,而不是单个的记录。这些记录可以是跨表的(使用SQL的连接),也可以是单表的。由于Windows环境下大多数的编程语言都能够支持记录集方式,因此编写基于记录集方式的程序是相当简单的。当然,我们也可以采用J2EE平台的编程方式,但是会导致编程量的激增,同时也难以达到预计的效果。这种平台的差别导致了架构愿景的差别。
此外,我们注意到我们对架构的描述其实还是不够仔细,这是非常正常的,因为随着开发的深入,我们会不断的完善架构的描述。例如,我们可以写出Front Controll的类框架,写出主要的几个Servlet,以及他们之间的关系。这个时候,使用UML类图会是一个不错的选择,实际上,我非常推崇在架构设计中大量的使用类图。不过在实际的运作中,每个软件团队大多数都有自己熟悉的架构设计思路,使用何种工具并不是主要的问题。
我们从源自需求模式中,学习到架构的设计是来自于需求的,而应用于软件全局的架构则来自于最重要的需求。还记得我们在那个模式中提到的网上宠物店的例子吗?系统采用了MVC模式,sun的官方文档一开始说明了为什么采用MVC模式,MVC模式解决了什么问题,然后开始分析MVC模式的几个组成部分:Model、View、和Controll。其实,MVC中的每一个部分,在真正的代码中,大都代表了一个子系统,但是在目前,我们就非常的清楚系统大致上会是一个什么样子,虽然这时候它还十分的朦胧。
不要视图在全局的架构愿景中就制定出非常细致的规划,更不要视图生成大量的实际代码。因为,你的架构愿景还没有稳定(我们在其后的稳定化的模式中将会讨论稳定的问题),还没有获得大家的同意,也没有经过证明。因此,从整个的开发周期来看,全局架构愿景是随着迭代周期的进行不断发展、修改、完善的。
我们如何确定全局架构愿景工作的完成?一般来说,你的架构设计团队取得了一致的意见就可以结束了,如果问题域是团队所熟悉的,一两个小时就能够解决问题。接下来设计团队把架构愿景传播到整个的开发团队,大家形成一致的认识,不同的意见将会被反馈会来,并在本次的迭代周期(如果时间比较紧迫)或下一次的迭代周期中(如果时间比较宽松)考虑。
子模块级、或是子问题级的架构愿景
这时候的架构愿景已经是比较明确的了,因为已经存在明确的问题域。例如界面的设计、领域模型的设计、持久层的设计等。这里的愿景制定本质上和全局的愿景制定差不多,具体的例子我们也不再举了。但是要注意一点,你不能够和全局愿景所违背。在操作上,全局愿景是设计团队共同制定出来的,而子模块级的架构愿景就可以分给设计子团队来负责,而其审核则还是要设计团队的共同参与。这有两个好处,一是确保各个子模块(子问题)间不至于相互冲突或出现空白地带,二是每个子设计团队可以从别人那里吸取设计经验。
在设计时,同样我们可以参考其它的资料,例如相关的模式、或规范(界面设计指南)。在一个有开发经验的团队,一般都会有开发技术的积累,这些也是可供参考的重要资料。
我们在这个层次的愿景中主要谈一谈子模块(子问题)间的耦合问题。一般来说,各个子模块间的耦合程度相对较小,例如一个MIS系统中,采购和销售模块的耦合度就比较小,而子问题间的耦合程度就比较大,例如权限设计、财务,这些功能将会被每个模块使用。那么,我们就需要为子模块(子问题)制定出合同接口(Contact Interface)。合同的意思就是说这个接口是正式的,不能够随意的修改,因为这个结构将会被其它的设计团队使用,如果修改,将会对其它的团队产生无法预计的影响。合同接口的制定、修改都需要设计团队的通过。此外,系统中的一些全局性的子问题最好是提到全局愿景中考虑,例如在源自需求模式中提到的信贷帐务的例子中,我们就把一个利息计算方式的子问题提到了全局愿景中。
代码级的愿景
严格的说这一层次的愿景已经不是真正的愿景,而是具体设计了。但是我们为了保证对架构设计理解的完整性,还是简单的讨论一下。这一个层次的愿景一般可以使用类图、接口来表示。但在类图中,你不需要标记出具体的属性、操作,你只需要规定出类的职责以及类之间的相互关系就可以了。该层次愿景的审核需要设计子团队的通过。
而设计细分到这个粒度上,执行愿景设计的开发人员可能就只有一两个左右。但是比较重要的工作在于问题如何分解和如何归并。分解主要是从两个维度来考虑,一个是问题大小维,一个是时间长短维。也就是说,你(设计子团队负责人)需要把问题按大小和解决时间的长短分解为更细的子问题,交给不同的开发人员。然后再把开发人员提出的解决方法组合起来。
架构愿景的形成过程
架构愿景的形成的源头是需求,需要特别指出的是,这里的需求主要是那些针对系统基本面的需求。比如说,系统的特点是一个交互式系统,还是一个分布式系统。这些需求将会影响到架构愿景的设计。在收集影响架构愿景的各项需求之后,按照需求的重要性来设计架构愿景。
架构愿景的设计并不需要很复杂的过程,也不需要花费很多的时间。我们已经提过,架构远景的主要目的就是为了能够在开发团队中传播设计思路,因此,架构愿景包括基本的设计思路和基本的设计原则。
值得注意的是,架构远景可能会有多种的视角,下文讨论了一种设计模式的视角。但是实际设计中还可能会基于数据库来设计架构愿景。但在企业信息系统的设计中,我推荐使用领域类的设计,也就是下文中讨论的例子。
架构愿景设计好之后,问题的焦点就转到如何传播架构愿景上来,为了达到在开发团队中取得统一设计意图的效果,可以考虑援引团队设计模式。除此之外,针对性的项目前期培训也会是一种有效的做法。
使用架构模式
架构模式也是一种很好的架构愿景设计思路的来源。随着对设计模式的研究的深入,人们发现其中的一些设计模式可以扩展、或变化为软件设计的基础。在这个基础上再实现更多的设计,这些模式就形成了架构模式。当然,不同的软件,它们的架构模式也是不一样的。在《Applying Pattern》一文中,有一个很典型的架构愿景的例子:
假设我们需要设计分布式的交互式系统。分布式系统和交互式系统都有特定的架构模式,前者为Broker模式,后者为MVC模式。首先我们先要根据系统的特点的重要程度来排列模式的顺序。这里假设需求中分布式特性更重要一些。那么我们首先选择Broker模式作为架构的基本模式:
再考虑交互式的特点,根据MVC模式的特点,我们需要从目前的基本架构中识别出Model、Controller、以及View。Model和View都很简单,分别分布在上图中的Server和Client中。而Controller则有两种的选择,假设这里的Controller部署在客户端,上图则演化为下图:
这样,基础的架构愿景就已经出现了。如果我们还有更多的需求,还可以继续改进。但是,记住一点,架构愿景不要过于复杂。正如我们在上一节中所讨论的,这里我们虽然是基于设计模式来讨论架构愿景,但是实际中还有很多从其它的视角来看待架构愿景的。至于要如何选择架构愿景的视角,关键的还是在于需求的理解。