一直以来,表现层的开发在Web应用的讨论中似乎总是一个小角色。Java的开发者们热烈讨论着的Spring、Hibernate、Struts、WorkWeb也都跟它没有什么关系。技术专家们甚至理直气壮的喊出了Web表现层应当“As thin as possible”口号,于是越来越多人们开始笃信有关业务逻辑的开发技术是武学之正宗,而表现层的开发技术不过是些旁门左道、花拳绣腿。
直到2005年初伴随着AJAX的出现,GoogleMap等一批样板工程摆到了我们面前。大家才猛然发现原来Web应用还可以做成这样!在这股冲击下越来越多的人开始思考表现层真正的价值。于是AJAX迅速的窜红起来,成为这两年Web技术发展道路上的标志性名词。
其实AJAX即不是新技术也不是很复杂的技术,它不过是基于WEB的RIA应用中的一个操作特性(或技术特性)而已。AJAX只有结合了Widget(指各种各样的界面组件)之后才能真正的发挥威力。尽管如此AJAX的诞生仍然不啻为革命性的。
说到AJAX的革命性,可能很多人会大吃一惊:“AJAX不就是XMLHttp吗?这种技术早在1999年就出现在浏览器当中了,它不过是一种新瓶装旧酒的噱头!”。其实我所说的革命性,并不是指AJAX在技术上是革命性的,而是说AJAX的出现对传统Web应用的开发模式的冲击是革命性的。
AJAX对Web开发模式的冲击 – 尴尬的Struts和WebWork
说到这一点,让我们先来看一下目前流行的开发模式,即基于Model2的MVC开发模式。在Model2的眼中存在着一个这样一个基本的假设那就是Web应用的运行逻辑是由一系列的页面切换构成的,这里的每一个页面一般来讲都不是特别复杂,往往有着非常特定的功能和目的。同时页面对于浏览器而言又是不可分割的最小单元,要更新页面中的数据必须对页面进行整体刷新。
先来看一个“产品信息维护功能”的例子,现在我们需要维护一个产品信息的列表,用户可以在这里完成对产品信息的CRUD四种操作。在Model2中通常的设计方式是这样,我们至少需要编写两个页面,一个用于根据查询条件列出产品列表,另一个用于对单个产品的详细信息进行维护。最终通过这两个页面的交替协作完成所有的功能。假设用户今天要进行如下的操作,输入查询条件查询出他关心的部分产品,然后修改其中的两个产品,新增一个,最后删除一个。基于上面的设计最终要走完这个流程我们的系统做了些什么呢?
在这一系列并不复杂的操作中用户界面却刷新了足有8次!每一次刷新都意味这用户需要等待和重新适应新出现的页面,思维和操作至少会被这次刷新打断2秒。不难想象一个原本正心情愉悦的打算开始一天工作的用户在经历这了8次的打断之后肯定会倍感挫折。而这只是他今天工作的开始,更复杂的还在后面!
那么结合了AJAX的表现层又如何来处理这个问题呢?利用AJAX的通信机制结合一套好的Widget(UI组件),我们完全可以把上面所有的这些操作都合并到一个界面当中。如果产品信息并不复杂,我们可以使用一个可编辑的Grid组件,让用户直接在Grid中进行产品信息的维护。如果产品信息比较复杂,我们可以在界面上再放置一个产品信息的维护表单,用户可以直接在Grid中选择要编辑的产品。所有这些编辑操作的结果都会暂时的缓存在客户端,直到用户完成了上面的各个步骤再一次性的利用AJAX技术提交到后台。这样,在整个操作过程当中用户始终不需要离开这个界面。
由上面的分析可见,AJAX一出场便推翻了Model2的基本假设,用户操作已不再是由一系列页面的更替和刷新构成的了。因此表现层开发技术的升级必然将导致对于MVC设计模式的重新思考和定位。
如上图,在传统Web应用的例子中我们很容易在其中找到Struts/WebWork在其中的价值所在。应用中有着大量的页面流,我们需要一种有效的机制对它进行管理。同时由于表现层的功能相对非常薄弱,控制器往往还要承担起为表现层准备数据的工作。这些在控制器中准备好的数据一般都是利用上下文(如Request的Attributes)以推的方式交给表现层,即推模式(Push Mode)。
这种推模式在页面总是以整体刷新的方式获得更新的开发方式中并不会出现什么问题,看起来一切都可以良好的运转。可是当AJAX出现之后,这种运转机制就出现了问题。因为AJAX强调的是减少页面的整体刷新,代之以局部数据刷新。当一个局部数据刷新的请求从客户端被发起时,表现层必须有能力主动的获得所需要的数据。这种操作类似于客户端通过表现层从后端的数据模型中的拉取数据,即拉模式(Pull Mode)。这一功能需求又与传统的Model2思路产生了抵触。
回顾上面的分析,我们已经在传统的Model2和AJAX之间找到了两个冲突点:
1、对页面流的基本假设不同
2、推模式和拉模式的矛盾
重构MVC开发框架
Model2和AJAX之间存在着不和谐,这是一个不争的事实。但并不是说我们就必须因此而全盘否定掉传统的MVC架构模式。事实上,企业在过渡到AJAX的过程当中,目前MVC开发框架中的主体仍可以保留下来,只是我们需要对其中的局部进行一些调整。我们将这个过程称之为对MVC开发框架的重构。
在这个重构过程当中,首当其冲面临调整的就是控制层,我们需要重新为控制层找到一个定位。如果说在传统的Web应用开发模式中控制层的作用是解耦数据模型和页面的话,那么在新的表现层技术引入之后,控制层的作用就应该是解耦数据模型和表现层的数据接口。如此一来Server端的表现层逻辑就全面接管了与Client端的通信,对于Client端来讲控制层被隐藏到了表现层的后面,只负责表现层与数据模型之间的对接。相应的,原先MVC架构与Client端形成的三角关系也就演变成了垂直分布的三键模式。如下图:
如果以这里提出的新MVC架构结合目前比较流行的Java HSS开发模式(即Hibernate+Spring+Struts/WebWork)。那么在后端的数据持久化和业务逻辑对象(BO)这两个环节的设计几乎不会受到架构重构的任何影响。在Hibernate和重构点之间至少有BO作为隔离墙,使用Spring来实现数据模型和表现层之间的衔接也是一种非常顺理成章的设计。如此一来Spring就全面接管了新的控制层的实现,Struts/WebWork的核心价值在这里受到了强烈的冲击。尽管我们仍然可以将Struts/WebWork引入到表现层与客户端的之间,用于进行一些整体的控制,例如权限的校验等。但是这样的使用方式相比起它们最初的设计思路而言就多少显得有些尴尬了。
落寂的JSF
在Web应用开发这场大戏中还有一个不得不提的角色——JSF。原本因为有了Sun的大力支持,JSF完全可以成为这场大戏中的明日之星。谁知半路杀出的AJAX打破了这个美梦。JSF的设计初衷是以组件化的方式来进行Web界面的开发,同时以事件驱动的方式进行业务逻辑的植入,它的主体设计思路与ASP.net非常相似。
可见JSF的主要设计目标是简化Web界面的开发,尽可能的为开发人员屏蔽JavaScript和DHTML编程。提高Web界面的表现力和交互性并不是JSF的主要目的。因此JSF仍然秉承了传统Web应用的一贯思路和缺点。JSF的事件模型完全是基于Server端的,所有的事件触发都必须通过和Server端的交互来完成。应用界面的交互方式并不会因为使用了JSF而发生什么改变,用户仍然需要在页面的来回跳转和频繁刷新中完成他的操作目的。
可以说在JSF的发展道路上受益的只有开发人员,而用户体验却被排除在外。这不符合我们目前对Web应用价值的思考,Web应用最终是为用户设计的!
据说JSF的设计者们已经意识到了这个问题,JSF2.0的规范正在紧张的制定当中。从目前的透露出的消息来看JSF2.0中将引入部分AJAX的特性同时会考虑对客户端事件的支持。不过根据历史的经验当一种新的需求或技术出现后,在这一领域的竞争中最终获胜的往往不是那些打了补丁、委曲求全的旧框架。所以笔者本人并不看好JSF的将来。
表现层中的架构模式
以往我们只习惯于讨论Server端的架构模式,在国内一些知名的技术论坛上这一类的讨论空前的热烈。而现在我们有必要再来讨论一下表现层中的架构模式。因为随着技术的发展,表现层的功能和设计已经变得越来越复杂,现在已经不再是那个表现层里只有HTML的年代了。从前面的章节中提到的“重构后的MVC架构”的图中,我们不难发现在新的设计中,表现层已经成为了一个跨越Server端和Client端的子系统,在这里既有对UI组件的管理,又有对AJAX通信的封装。它的复杂度甚至已经超过了原本被我们认为是绝对核心的业务逻辑层和持久化层。所以,进一步将MVC设计模式引入到表现层中已经成为一个非常现实的话题。
在继续这个话题之前让我们先来看看经典的《AJAX in Action》中提出的AJAX交互的三大类别:
1. 以内容为中心的交互。即通过AJAX传递内容的是HTML。
2. 以脚本为中心的交互。即通过AJAX传递内容的是可用于执行的脚本。
3. 以数据为中心的交互。即通过AJAX传递内容的是用于展现的数据。
事实上我们也可以认为这就是AJAX应用发展的三个阶段。因为从“内容”到“脚本”到“数据”的发展过程意味着我们必须为表现层提供越来越多的基础代码和框架支持。每一个阶段的抽象度都高于前一个阶段。最终的目的就是实现UI组件和数据的彻底分离,这一目的正是MVC所倡导的数据与表现的分离。
目前,由于AJAX诞生的时间还不长,所以很多AJAX的应用还处于相对简单的“以内容为中心”的阶段。这种交互又被成为AJAH(Asynchronous JavaScript and HTML)。这种开发方式对现有MVC的影响稍小,但能够起到的改善交互性的作用也非常有限。因此只能算作是一种过渡的模式。从发展的角度来看,MIS类企业Web应用的开发的主流一定会走到“以数据为中心”的阶段。“以数据为中心”的表现层应用才是真正具有生命力的,以下我们称之为数据模型驱动型表现层。
那么怎样才能实现一套数据模型驱动型表现层的开发框架呢?对于大多数企业来讲是很难独立的发展出符合这一要求的框架的。因为开发一个完整的成熟的表现层开发框架将会涉及到大量的技术积累以及时间。这种付出对于很多企业而言是不可接受的,事实上也是完全没有必要的。我们可以借助强有力的第三方框架或组件库。就像在Server端我们需要Spring、Hibernate等来帮助我们搭建框架一样。
随着AJAX的持续火爆,各种AJAX的第三方框架或组件库也在不断涌出。不过在这些产品中真正能够直接帮助我们实现数据模型驱动型表现层的并不多。像Backbase、Bindows、DOJO、YUI、Qooxdoo这些产品都基本仍是以提供丰富的UI组件作为其主体设计思路,在这些产品中都缺少一种机制真正的将表现层中的数据管理起来,因此这些产品的表现形式是一些看起来相对独立的UI组件。这一类产品笔者称之为“离散控件集”。
在表现层中实现一个真正MVC模式应当是数据模型驱动型表现层框架的基本要件。让我们尝试换个角度来分析问题,我们可以把Server端中MVC的各个组成部分看作是一个封闭的子系统。这个子系统的功能就是从数据库中提取数据经过一些列处理之后交给Client端,同时对Client端提交的数据进行一些列处理之后再保存进数据库。同样如果我们把Client端中MVC的各个组成部分也看作是一个封闭的子系统,它所完成的工作事实上跟Server端的子系统非常相似,只不过这个子系统的两个交互对象分别是用户和Server端。按照这种思路,最终形成的Web开发模式将是一种迭代式的MVC架构。
目前笔者所参与的产品dorado就是基于数据模型驱动型表现层框架开发的,下图是一张该产品示例页面的效果图。
后言
AJAX虽然是一种新瓶装旧酒的技术,可是它的价值已经得到了各大厂商和技术社区的认可。预计在今后的一段时间内AJAX仍会持续的热下去。同时,其他的一些表现层的相关技术也会不是冒出来。
目前除了AJAX之外,您也可以给Comet投入一点关注,这是一种利用不间断的Response的技巧实现的推技术。通过它可以我们制作出一些实时性要求比较高的Web应用,例如:WebIM、Web状态监控、股票信息等。此外还有Canvas技术,它让我们可以在浏览器中实现图型绘制功能。
也许是这场由AJAX导演的表现层变革来的太过突然,很多开发人员和企业似乎都还没有做好迎接它的思想准备。“做界面是美工的事情”、“好的技术人员应该去开发后台”这些仍然是很有市场的想法。在一切追求“科技以人为本”的今天,如果您或您的企业能够尽早的认识到表现层的重要性并适时的做出调整,那么一定会有更大的机会登上市场竞争的制高点。