Archive for December, 2005

正本清源:所谓Ajax输出的三种形式

Thursday, December 29th, 2005

QuirksBlog: The AJAX response: XML, HTML, or JSON?

说实话,我没想到Bing Ran会问我这个问题。早先这篇文章在TSS上贴出的时候,我很快的浏览,便一眼看出这篇文章作者所处的角度。事实上,AJAX概念的不完整和不严密性 ——异步的JavaScript + XML——导致作者将AJAX的输出分为三种类型:XML, HTML片断和JSON对象字符串。

首先看XML。对于RPC的数据传输,XML从来都是当仁不二的选择。对于将对象序列化为XML字符串的方式,往往有两种选择,一种是将对象本身的属性作为节点进行输出,一种是利用语言的元数据特性进行序列化输出。两者存在较大不同。对于第一种,输出案例如下:

[xml]

O’Reilly David Flanagan

Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

Friends of Ed Jeremy Keith

Praesent et diam a ligula facilisis venenatis.


[/xml]

而对于第二种,输出案例如下:

[xml]

java.util.List

yourapp.domain.Book
title
JavaScript, the Definitive Guide
publisher
O’Reilly
author
David Flanagan
cover
/images/cover_defguide.jpg
blurb
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
yourapp.domain.Book
title
DOM Scripting
publisher
Friends of Ed
author
Jeremy Keith
cover
/images/cover_domscripting.jpg
blurb
Praesent et diam a ligula facilisis venenatis.
[/xml]

前 一种一般来说是同一进程内(同一JVM内)对对象进行序列化和反序列化的方法,在XML-Java绑定一类的框架中比较多见,例如 XStream, JiBX, Castor等等。当同一进程内能够找到对象具备的正确类型时,这种序列化/反序列化设计和实现都不太困难,而且针对空值处理也比较容易。

可以看出,由于这种方式成本较低,有大量成熟的开源库可用,加上在AJAX中的X(ML)的“理论”指导下,许多开发者采用这种方式将对象输出给前 台浏览器,然后利用浏览器的XML能力进行输出显示。从那篇文章中可以看出,这种工作是纯粹的dirty work, 并且由于领域模型或者DTO的不同,输出的xml结构含义也不同,在对空值的处理上更是麻烦,在处理显示逻辑的时候,基本上很难在客户端对以这种方式传递 的XML以一种统一的方式进行还原。以这种方式来进行AJAX开发,小规模应用还不能显出弊端,但是大规模应用出现,领域对象较多时,必然出现怨言。而我 们使用AJAX的真实意图并非来无趣地去解析各种各样的XML,而是需要XML中代表的数据。至于XML是什么样子,除了调试阶段,没有人会关心。

第二种XML的序列化方式是绝大多数跨进程远程调用协议/框架所采取的方式。SOAP/WebService如此,XMLRPC如此, Buffalo采用的Burlap也如此。这种远程调用的特征是,在协议约定的条件下,调用方和被调用方需要保证数据语义的完整性。拿什么保证?就是数据 定义信息了。这些协议的共同特征是采用谋一些标记来描述数据类型:int, long, float, string, list…这样定义完成后,只要根据协议,任何语言都能以一种通用的方式对数据进行还原。AJAX引擎的概念也就渐渐呈现——通过某一种协议,他就处 于中间的位置,负责将调用方的请求包装为协议,转化为执行方能够理解的动作加以执行;然后将执行结果转化为协议的值,传递给客户端,客户端引擎将协议内容 解析为能够理解的对象结构传递给客户端,然后就可以利用这个数据来显示了。XML-RPC如此,WebService如此,DWR如此,JSON如此, Buffalo也如此。

综上所述,纯粹使用领域模型特定的输出XML传递给客户端是一种相当原始的做法。他只在很低的层次上印证了所谓AJAX的概念。然而,这种概念的深入思维结果便是一个AJAX引擎。

文中提到的第二种输出方式:HTML——应该被看作WEB的一个特例,应该说这是历史因素、浏览器能力、设计者等多方因素达到的一个平衡。许多历史 应用中,大多采用将页面进行一定规则的分割,然后include或者jsp 2.0 tagfile的方式对公共区域进行处理,留下一小部分进行动态显示。这里举一个例子:查询,显示书籍列表。传统做法就是上面一个搜索条件输入文本框,下 面是搜索结果列表,处于同一个页面。原来的搜索方式每次提交都要刷新整个页面,用户体验不太好,现在需要改进。按照激进的Ajax做法应该是当搜索按钮点 击时,调用bookSearchService.search(String terms)的方法,取得结果列表,然后Ajax引擎处理结果数据,将数据反序列化为javascript对象,开发者利用这些对象,要么利用DOM, 要么利用JavaScript Template, 在页面对搜索结果进行展示。然而,问题出现了:

搜索结果太多了,用DOM操作速度太慢;
开发者人手不够,没有时间,而这个页面以前写过;

那么出现这种情况时,很可能的做法便是,见原来那个搜索结果页面刨去其他不相干的部分,留下搜索结果部分,然后利用一个resultDiv.innerHTML=xmlhttp.responseText搞定。这样做,既达到了改善体验的效果,也提高了开发速度。

输出HTML另外一种方式文中也没有提及。事实上,HTML不仅仅作为片断,更重要的是作为页面视图的一部分。在buffalo的demo中,可以 看到所有的页面都被管理起来了,buffalo接管了视图的切换;这种设计也存在于gmail/163新版邮箱中。这个应用比上面的HTML片断的使用方 式还要重要,因为这里是缓存可以介入的地方。通过不同的缓存策略,可以将用户的实际和心理等待时间大大减少,从而进一步改善用户操作体验,提升产品竞争 力。(PS. 在Buffalo 1.3中将加入客户端缓存模块,无需你动手,buffalo为你缓存视图)

文中提及的第三种方式,JSON,根据第一部分的描述,应该比较清楚了。实际上他扮演了一个Ajax引擎的角色。这里不得不提的是,使用JSON的 相当危险的。因为他的协议表现与语言本身绑定太死。如果某一天,JSON协议变化了,那么使用JSON的应用基本上不可能应对这个变化——因为返回结果是 eval()得到的。而Buffalo将协议隐藏起来了,1.2版本甚至连服务器端的ServiceInvoker都将burlap实现依赖隔离开。现在 使用burlap,也许某一天不用了,buffalo的应用照样可以运行。因为里面的细节都是透明的,作为开发者,你只需要关注数据对象本身,而非用来描 述对象的那一堆字符。

Web2.0:开发者,你就是司机

Wednesday, December 28th, 2005

他们说,Web2.0是个好东西。
他们说,Web2.0真正尊重我,体贴我
他们说,Web2.0不是商业模式。
他们说,Web2.0不一定赚的到钱,不是Web2.0一定赚不到钱。

作为开发者,驾驶着Web的快车,你要把用户带到哪里?

这世界产品的成功越来越依赖于产品是否做得用心并且颇具创意。Google的成功依赖于此。对产品的热爱,对最终用户的贴心考虑。不妨问一下,作为J2EE开发者,使用着世界上最领先的开源技术,体会着世界上最精妙的设计模式,使用着最先进的开发工具,作为开发者本人,自己做出来的应用是否愿意使用?

客户:XXX系统真难使用!
YYY系统的开发者:是吗?比YYY系统更烂?

真是一个玩笑。这其中差别在于对我们创造的系统的价值的根本认知。无论是大系统还是在小系统中,开发者都被认定为代码开发者和业务功能实现者,而非奇迹创造者。而传统的工业模式限定了我们,任何事情都有明确的分工,美工做界面的事情,我们开发者只需要写程序OK了,然而这种分工将用户体验这个角色远远扔在外面,没有人关心系统的易用性。事实上,软件系统发展了这么多年,用户早已不再满意仅仅功能的实现。真正的可用系统应当是用户友好的。代码开发完毕的系统,使用上首先要过自己这一关,如果写完代码后自己都懒得多看一眼,如果自豪的给用户使用?作为开发者,他真正的价值不在于依靠什么样的技术实现了这个功能,而在于如何以恰当的方式交付给用户,让用户去创造更大价值。用户的快乐才是开发者价值的所在,用户的快乐才是开发者的快乐。

哦,忘了,我们只是写代码的,不能具备那么多能力。你可以不懂得色彩搭配和颜色布局,但你一定知道怎么操作这个系统才好用。你不必具备将界面弄得很绚丽的能力,但一定得有能力将复杂的东西弄得简单清晰。一句话,Web2.0时代,你就是司机,驾驶着各种先进技术组装的车上,带着你的乘客,快速而舒适的送乘客到达目的地。

写在Buffalo1.2发布之后

Tuesday, December 27th, 2005

buffalo1.2发布了,有了许多感想,有必要写下来。开发过程中的一些点滴,也许并不像像外人一样那样容易。现在开始明白,一些独立以个人之力进行专业化软件开发之路的开发者,是多么的不容易。可以说,每一个新版本release的背后,都留下了辛勤的汗水。

从一开始,就没想到buffalo能走到现在。buffalo 1.0出现后,也许会像jsvalidation一样,轰动的来,悄悄的去,莫名无声。然而,清风和nemo大胆的在Sina的内部系统中应用了buffalo, 证明了buffalo的可用性,这给了我极大的鼓励(事实上,我一直在这样各方面的鼓励中,不断的改进buffalo)。后来社区的引入,逐渐有了像董董,宋来这样的热心的用户,不断提出意见和建议,督促着buffalo往前走;曹晓钢老师也不断提供资源的支持,amowa和buffalo站点都是在他的服务器上。没有各方面资源的支持,我想buffalo不可能走到今天。

buffalo api的实现都很简单,但是都是长期思考后得到的,我认为能够让使用者得到最大自由度的,并且不依赖buffalo的接口定义。当一个新的特性需要被加入的时候,我首先考虑的是是否会加重使用者的学习负担,其次是如何设计最直观最人性,最后才是实现。现在的开发者需要学的东西太多太多了,如果这套api不能在5分钟内告诉他们怎么用,30分钟内不能开始使用,这不能说明这个产品的成功,而正好证明了他的失败。在现在的JavaEE领域,没有把任何事情比把事情弄得复杂更加容易的事情了。复杂不是优点,是缺点。我很高兴的发现,今天发布之后,有新的使用者能够在看完api后说,功能差不多,比DWR简单。

不得不说,开发buffalo的过程是一段痛苦的过程,甚至真切的影响到了我的工作和生活。上班中,我时不时去论坛看看;下班路上,我在考虑如何添加新的特性,如何设计service接口更加兼容IoC容器和自定义的服务。周末,如果没有其他的事情,一般也是在做buffalo. 然而,工作中我也并非自由人,也要管人和被人管。遗憾的是,在这种平衡关系中,我做得并不好。

更重要的是,这种真正意义上的开源开发(至今为止,我没有从buffalo或者amowa或者jsvalidation中得到一分钱)让我的价值观也发生了一些变化。我开始理解Richard Stallman当初开发gcc的那种狂热,也能够理解菲利普·卡兹为何潦倒而终,归根结底,我开始似乎领略到那深邃的开源精神,那种以全世界使用者开心而开心,以使用者快乐而快乐的精神。这种精神能够让人逐渐忽略物质的需求而享受真正的精神世界。然而,我中毒尚浅,深深的明白,全盘接受这种价值观在国内跟自杀没什么差别。

下一步工作,我知道还有许多没有做。目前已经提出的有:表单到DTO对象的绑定,与jsvalidation的集成,对service调用的ACL控制,改进的对有状态service的支持,等等。只要开发者有需要,buffalo会一直走下去。buffalo会放到java.net或者其他的开放cvs上,以接纳更多的开发者。

ps. 我答应了博文视点,从明年开始与夏昕一起写一本关于JavaEE开发的书,工作更多了。

Ajax/Amowa框架Buffalo 1.2发布!

Tuesday, December 27th, 2005

经过长时间的工作和buffalo社区的支持,buffalo ajax/amowa framework 1.2发布。新版本包含了经过改进激动人心的Spring集成,Prototype集成,以及浏览器前进后退的支持。主要的新特性如下:

  • * 支持浏览器前进后退(这个特性几乎可以在小型应用中替换MVC)
  • * 重写了整个服务调用模块
  • * 重写了Spring集成代码,集成Spring更加容易
  • * 重写了burlap的依赖,移除了特定版本的burlap-fix.jar。无需任何变动,现在可以在resin app server中使用buffalo了。

Buffalo Ajax/Amowa Framework是一个全新的远程调用/Web框架。他可以向JSON/DWR一样,被应用为一个web远程调用框架,简化web客户端与服务器端的调用(buffalo的API更加简单!);也可以在小型应用中承担页面切换的任务,基于OPOA的概念,让buffalo为你管理页面切换;在大型应用中,buffalo也可以在其中承担页面无刷新获取数据的工作。Buffalo binding组件能够一致性地将数据绑定到html组件上,也可以绑定到JavaScript Template的模版上。目前已经有若干真正的商业应用在不同层面应用了buffalo。在这个版本中,buffalo提供了全面的文档,丰富的发行包,成熟的Demo,buffalo已经为企业应用作了充分的准备。

Buffalo站点:http://www.amowa.net/buffalo/
演示:http://demo.amowa.net/buffalo-demo/index.jsp
下载:http://www.amowa.net/buffalo/index.html?page=download

使用buffalo作为webwork的验证机制

Thursday, December 1st, 2005

昨天在开发中遇到了验证的问题,结果证明,基于异步的服务器端验证是最节省力气并且效果好的。由于2.1.7的xmlhttp验证基本不可用,2.2太丑陋,因此我决定用buffalo实现验证。思考结果是……发现事情是出奇的简单,实现起来美观又优雅。

1 构造一个ValidationService(POJO), 包含一个validate方法:

List validate(String namespace, String action, Map pamameters)

这个方法实现很简单,只需要根据namespace和action, 构造一个ActionProxy,
将parameters放到ActionContext中,执行Action.execute,
然后判断这个Action是否为ValidateAware, 如果是,那么调用验证方法,将getFieldErrors中的错误按照name -
value的方式作为返回值返回即可。

2 将这个service放到buffalo-service.properties, 或者用Spring集成。这方面不赘述。

3 客户端:

var buffalo = new Buffalo("/appRoot/BUFFALO");
var currentForm = null;
function validate(theForm) {
   currentForm = theForm;
   //组装form内的信息,代码略
   buffalo.remoteCall("validateService.validate",
             [form.namespace, form.action, parameters],
             callback);

   return false;
}

function callback(reply) {
   var result = reply.getResult();
   if (result.length >0) {
            //有错误的处理……
   } else {
      // 无错误就提交
        currentForm.submit();
   }
}

4 webwork中,对form.vm稍微进行修改,加上onsubmit=return validate(this) 即可

完毕。

由于buffalo封装了远程调用以及数据序列化的细节,使得编程更加简单并且清晰了,由于它的小巧和易于集成,使得这些工作只需要做一次,并且对开发者透明。这些代码可以自己封装,并且可以重用。我相信这个封装比webwork
2.2的dwr要好。