Web系统可复用架构
本文讨论Web系统可复用架构,也使用于各类其他软件系统,所谓万变不离其宗。
提示:本文分三个部分,分别是问题、解决方案概述、架构中的核心事宜,重点在最后一个部分。
非常有经验的读者可以直接看最后一个部分,当然我还是建议大家通读本文。
衷心希望所有的读者看完此文,可以对此文提出任何建议、质疑、问题,相互切磋,一起提高,在此表示感谢。
(一)问题
先来看一些问题架构设计引起的问题:
问题一:系统开发完成之后,需要加入新的功能模块,发现不知道从何处入手,因为需要加入的模块会与其他各个模块有业务关联,并且需要用到很多其他模块的代码,但是,其他模块的代码并没有提供良好的接口,也没有分层设计,界面层直接就完成了全部功能。
问题二:某大型系统A开发完成,运行良好,然后公司决定开发另一个系统B,B和A的核心业务不同,但是很多基础框架和基础模块是类似的,如何复用到A系统的那些模块呢?
问题三:某公司上线的系统A已经测试完毕,只是在最后一个环节发现一个小的Bug,然后交给开发人员修改,开发人员修正了这个Bug,然后直接发布。客户使用了这套系统,发现几乎不能用,除了开发人员最后修正的那个问题。
问题四:某公司开发大型系统,约有200位软件开发人员,分别在三个研发中心,那么如何有效协作?
(二)解决方案概述
为了方便讨论,笔者会虚拟一个场景,讨论在此场景下的系统设计和实现。
假设情景如下:
某公司需要搭建一套项目管理系统,假设包括三个子系统,分别是:用户管理子系统、产品管理子系统、项目管理子系统。
用户管理子系统负责用户的登录检测以及简单的权限控制,产品管理子系统负责管理产品的名称和版本,项目管理子系统包括项目的信息和进度管理。
那么该如何进行设计该套系统,才能做到系统的扩展性、可复用性、可维护性、可大规模开发性达到最高呢?
先来解释一下这几个要求:
扩展性:即可以在此套系统中加入其它的子系统,如会员管理、考勤管理等。
复用性:包括界面的复用、业务逻辑的复用、数据访问代码的复用、某个子系统的直接复用等。
维护性:系统上线之后,发现一个Bug,是不是比较容易定位和修改,并且不会影响其他的功能。
大规模开发:多人协作的团队,如何进行合作分工和交流,代码如何提交编译等。
首先我们会想到对此系统进行分层设计和模块划分,
所谓分层设计,即横向分层,如常见的界面层、逻辑层、数据层;
所谓模块划分,即纵向分层,将项目管理系统分成用户管理子系统,产品管理子系统,项目管理子系统。
经过横向和纵向的模块划分之后,整个系统变成了一个表格式的东东,每个单元格代表一个模块。
为了复用性的设计,
横向的各个模块之间不可以相互引用,
纵向的分层模块不可以出现跨层调用,数据访问层除外。
下图给出了此情景下的 架构设计:
业务逻辑层被拆分为两层,分别为BLL Manage和BLL EO层,Manage层处理纯粹的业务相关,EO层处理业务实现,以及一些简单的个体性业务。
数据访问层也被拆分为两层,分别为DAL Data和DAL Access层,Data层针对每张表进行增删改查操作,Access层则只是执行与数据库交互,如执行SQL语句。
各个工程编译之后,生成的库文件引用如下图所示:
(三)架构中的核心事宜
好了,到这里我们要解决几个很重要的问题。
我们遇到的第一个问题是,在BLL Manage层,大量使用了BLL EO层的对象,那么,这样一来,BLL Manage和BLL EO层将会深度耦合,完全没有办法拆开,如何进行解耦,以达到每一层的模块都可以单独复用的目的呢?
目前的解决方案:考虑到各个模块的单独复用,层与层之间交互,最好通过接口的方式来传递数据,而不要进行对象引用,否则耦合性会很高。
我们遇到的第二个问题是,在Web系统的开发中,经常会涉及到表的关联查询,直接构造SQL语句,然后执行,这样的话,同样关联性和耦合性都会很高,那么,应该在哪一层哪个模块中做这些事情呢?
目前的解决方案:涉及到表的关联查询等,可以放到BLL EO层,这一层会深度关联,一般难于复用。而且,这时会过DAL Data层,直接与DAL Access层交互。
我们遇到的第三个问题是:系统分层很多,通过什么样的数据结构在各个层次之间传递数据?这些数据结构在各个层各个模块内部直接定义吗?还是说建立一个CommonData库,统一放在其中?
目前的解决方案:关于数据结构在各层之间单独定义还是定在在CommonData中,取决于具体的系统,各有优劣。
我们遇到的第四个问题是:系统分层很多,各层之前传递数据如果全部从用拷贝的方式,系统的运行效率如何保证?
目前的解决方案:从数据安全和系统稳定性的角度,各个库之间的接口调用和数据传递,一般采用拷贝的形式。
如果确实需要分层比较多,数据拷贝方案不行,有几个其他的方案可以考虑,以EO层和Manage层为例。
方案一:EO层需要为Manage层提供数据,EO层管理数据的生命周期,Manage层通过引用的方式使用数据,EO层删除数据的时候,会通知其调用者。如何通知,方式待定。
方案二:EO层需要为Manage层提供数据,EO层管理数据的生命周期,Manage层通过引用的方式使用数据,EO层将数据删除的权利提供给其调用者,可以通过智能指针引用计数的方式实现,COM技术中也有用到,由Manage层管理引用计数。
方案三:多层传递数据,如一共有5层,但是只是在最顶层拷贝数据,其它层只是引用传递。如从A层开始传递数据,需要最终传递到E层去使用,在E层进行拷贝使用,其它层制作引用传递。这个方案的问题是,B、C、D中间层如果确定只是传递引用,而不拷贝数据,那么,B、C、D这些模块单独复用,也是不会拷贝的,这样就会存在很多潜在的危害。
综上,方案二是比较好的方案。
遵循以上架构,还需要注意以下几点,才能达到我们的目标:
(1)各个库接口的定义一定要明确给出,这是一种必需遵循的约束。这样做的好处是,如果不遵循约束,代码无法编译通过,程序无法运行。
感谢李**、郭*对此文提出的建议和修正,尤其是李**提出了很多有价值的建议,在此表示衷心感谢。