Posted in March 2010

复杂web应用的非侵入Javascript之路

就跟Javascript是世界上被误解最深的语言一样,HTML也是一种古老的原本简单的技术,现在却被大量甚至过度使用,旧有技术并没有考虑到方方面面,也没有鼓励和抑制某种用法。这样对于复杂应用,旧有的编程模型就得大量的改进。

1. 混合

早期的页面都是逻辑和展示混合在一起的。比如<button id=’sub’ onclick=”submitData();”/>。

2.分开

采用事件绑定。比如在jquery中,$(‘#sub’).bind(‘click’, function(){…}),这样逻辑和显示分开了。这些绑定的代码大多写在页面的onload里面,但这不代表所有的情况。

3.javascript模块化

对于web2.0或者Ajax使用很多的应用,用户感觉他始终在一个页面操作,比如Gmail,左侧的栏是一直在的,不会出现整个页面刷新的情况,多数时候是页面上的某一小块更新内容。

web-dev

比如上面页面右侧区域的内容是根据用户左侧点击操作而动态更新的,这块区域的事件绑定就需要动态的,而不能在整个页面装载时绑定。这样页面各个区域以及整个页面的javascript其实是可以分离开的。

这种web页面结构已经有点走向传统C/S界面开发了,但是html+javascript开发起来难度就大很多。为了避免走向过度复杂,当程序走到这一步需要打住:1)保持简单,避免过度设计(特别是对于小的应用)。只有很少的应用需要做到Gmail的复杂程度。简单是web的本质。2) 重构页面,重构操作模式,不能把C/S的开发思路硬搬到web开发。3)使用RIA之类的胖客户。

模块化为减少全局变量的使用铺平了道路。全局变量不仅指<script>title = ‘All’;</script>这种声明的变量,通过document.getElementbyId也是对全局变量document的访问。这种方式很容易的可以访问页面其他的元素,鼓励了页面元素间的依赖关系。这种细粒度的依赖织成复杂的关系网,当测试复杂程序时会非常困难。

减少全局变量则使另外一个问题突出来:模块间的交互。在有全局变量时候,模块间可以使用这种共享变量来进行通信,现在得另外找道路。event和Observer模式是一个降低模块间耦合度的好方法,jQuery和dojo对这方面都有关注,javascript的函数式语法处理这些得心应手。有些模式比如Front controller也可以达到这种效果。

3.组件

当web应用不可避免的走向B/S模式时,B/S中的组件模型也被复制到html中。典型代表是Dojo,也即Digit widget,还有Ext JS。页面被划分的更细,组件有独立的javascript(事件处理),css。显然这种方式是web开发的理想方式:封装更好,重用性更好。

不过web的优点在于简单和标准,组件对已有编程模型改变太大(侵入式),是一个“框架”而不是“工具”,适合建立复杂的web应用,比如企业应用。一般的应用采用jQuery这种辅助性js库开发更轻量级,更灵活。

Web Service/SOA总结

最近的一个项目大量用到了web service,这里作下总结。

主观的说,不大喜欢web service, 这个东西是很好,但是太复杂了。More Joel on software 里面提到了类似的落后技术战胜“先进”技术的场景,比如虽然HTML有这样那样的局限,但是依然很流行,因为它简单。

web service好在哪里呢?标准和规范。所有的报文格式都有明确而细致的定义,方法也有定义,有点偏向“基于契约编程”和“接口编程”。这些适合企业内部的信息集成,适合变化缓慢的业务需求。而对web应用(互联网行业)这种快速开发模式来说,web service就显得笨重和过度设计。

所以如果使用了web service,必定要多多应用SOA的理念,“…把业务转换为一组相互链接的服务或可重复业务任务”,这样web service优点才能体现出来。

做多了企业信息系统后,发现这个东西很boring,官僚,保守… 啥都利益导向,没劲。

现在的农村

最近去了两趟农村:春节去了湖北老家,前些天去了趟我老婆的江苏老家,都是当地很典型的农村。

坦白的说,我都有点不适应。虽然我是土生土长的农村人,小时候都美好回忆都在乡下,但是读书和工作都在城里,去过一些大城市,看到现在还很落后的乡下,或许变的跟鲁迅说的一样“我从乡下跑到京城里,一转眼已经六年了。其间耳闻目睹的所谓国家大事,算起来也很不少;但在我心里,都不留什么痕迹,倘若要我寻出这些事的影响来说,便只 是增长了我的坏脾气,–老实说,便是教我一天比一天的看不起人”。

乡下衰败了很多啊!白色垃圾到处扔,这种东西真的是常年都不降解,搞过化学的会觉得这东西看起来比牛粪还恶心。人气也不比以前了,春节还热闹点,一过就看不到啥人了,堪比浦东郊区的夜晚啊。现在农村晚上一般都通电了,可是没有说话的声音,白质灯泡到了晚上感觉孤零零的。

回到上海的东昌路,车水马龙,恍如隔世。

城乡间的差距很大啊!这个差距不仅只是农村物质上的落后,更多的是城市对农村的精神冲击。在电视电话这些东西把世界整平后,农村和城市的差距越发明显。乡下的小孩现在也能看到动画片,跟城里的小孩一样喜欢机器猫,但是当他/她家里买不起机器猫的玩具后会是什么想法呢?农村原有的传统和道德观念渐渐丧失后,就没有东西来抵抗城市的冲击,这会要人想方设法成为一个城里人。

如同“帝王将相,宁有种乎?”,我并不认为从人的角度来说,城里人比乡下人更有资格过更好的生活。谁更聪明、更努力吗?我上班大多无所事事,我不知道自己创造了多有价值的东西,我道德不比乡下人高尚,我只不过每天要傻乎乎的去挤地铁而已。

Javascript闭包(回调函数)的问题

回调函数网络上一大堆,这里举个实际的例子:

<script src="../javascripts/jquery-1.4.2.js"></script>

<script language="javascript">

  $(document).ready(init);

  function init(){
    console.log("....init");
    var sd = new Date();
    $('.list').each( function(){
      this.onclick= function(){
        console.log("you click,haha");
        process(sd);
      };
    });
  };

  function process(youDate){
    console.log("I got it:" + youDate);
  }

</script>

<div id="nav">
  <div>11</div>
  <div>22</div>
  <div>33</div>
</div>

逻辑很简单:当页面加载时注册回调函数,当点击div时激发回调函数。这里注册和激发是异步的。

注意回调函数可以访问上一级的成员变量sd(或许在FP中称为运行上下文),这个跟java的observer模式中的内部类可以访问容器类的this指针一样,这就是说当你点击div时,原来已经产生的时间变量sd还在,这样打印出来的时间都是旧的时间。这是closure的灵活强大的地方(《JavaScript: The Good Parts》里面说,“使用闭包来进行信息掩藏的方式,它是另一个减少有效全局污染的方法”。真知灼见啊!,否则又要使用大量的全局变量),但是跟Java一样,这里由于引用的关系可能会出现垃圾回收的困难,java用弱引用来处理这个问题。这篇文章Memory leak patterns in JavaScript有描述,里面提到了circular references,大概意思是javascript对象引用了DOM对象,而DOM对象反过来又引用了javascript对象。上面代码改成:

$('.list').click( function(){
  console.log("you click,haha");
  process(s);
});

可能更好点,因为this.onclick处可能隐含了DOM对象到Javascript对象的引用,而在$(‘.list’)处又有javascript obj到dom obj的引用。这个我没有求证,毕竟这种内存泄漏在浏览器上关掉当前页后就应该不存在了,不会引起很明显的问题,知道有这个事就好了。