Javascript库的“实现模式编程(Programming to patterns)”

今天看到了一篇很好的讲Javascript Library的文章:http://www.clientcide.com/best-practices/jquery-and-the-ajax-experience-programming-to-the-pattern-and-what-really-makes-one-framework-different-from-another/
作者是一位MooTools开发者,他写了对实现模式编程(programming to the patterns)进行了阐述。告诉我们像Prototype、MooTools这样模拟类继承并鼓励使用OO的方式组织你的代码对于你的好处。而对比的对象就是红火的JQuery。他的观点我举双手双脚同意。

JS的通用库最基本的目的是给你解决浏览器兼容性差异,让你在与浏览器兼容性的战争中给你一个巨大的后援保证。但是只提供浏览器兼容性的JS库是不会流行的,你还需要在编程模式和代码效率(Code efficiency)上提供帮助。对于我个人来讲,对语言的流畅性改造最好的就是Prototype这个库,因为它营造了一个“最小惊讶”的Ruby语言环境,让你几乎感觉到是在编写流畅的Ruby,尤其在Rails项目里面使用更让你感觉到Ruby和Javascript结合的流畅。(此处我想到了上周Cat Chen同学和我提起的“Language Oriented Programming”的概念,也许这就是它的表现吧,扩展语言减小编程中的“惊讶”)相比之下JQuery则在代码效率上做了很大功夫,这个代码效率不是指运行速度,而是单位代码完成的功能。JQuery对Dom的DSL化封装,还有对method chain的大量使用,几乎让你感觉在声明行为,所以它让非常多的对啰嗦的Dom编程厌烦的前端程序员迅速“上瘾”。但是,我们知道DSL化的JQuery还不够,因为它很好的解决了可读,但是并不一定容易维护(尤其是过度使用method chaning)。另外一个原因就是习惯使用“声明化”以后会让一些程序员忘记“抽象”和“封装”,很多JQuery都没有使用面向对象OO的方式去组织自己的代码,而是拥抱了面向过程编程,而很多人却还自我安慰说自己使用的是“函数式编程”。如果你没有做好函数抽象,那么绝大多数情况下你的JQuery code都不符合函数式编程的本意,此时你也就离抽象出可复用的“模式”越来越远了。

其实JQuery的很多UI plugins是很好的例子,尤其是支持Progressive Enhancement的JQuery UI插件,它们都很好的规定了自己的micro formats,然后根据dom的模式来组织自己的行为模式(Behavior and Patterns)。它们才是很好的对实现模式编程(programming to the patterns)的例子。缺少了对模式的抽象也就失去了在大的项目中实现代码效率(Code efficiency)的优势(因为代码复用度会下降),这对于JQuery这样一个以“Write less, Do more”为口号的库来说就失去了它最大的卖点。

所以,实际上关键的问题就是,用哪个JS库都没错,但是如何使用和形成模式才是关键。每个库组织自己的“模式化代码”的风格不一样。但是像MooTools和Prototype(还有YUI)这类基于类去组织代码的库的源代码本身就已经告诉了你如何组织你的代码,而且它们的OO实现对于任何一个熟悉OO的程序员来说都“没有惊讶”,那么你就很容易吸取他们所推荐的代码组织风格了。

最开始所引用的文章归纳了几个不面向“模式”组织代码的坏处:

  • 缺少抽象,缺少复用
  • 会形成零散的代码,修改起来成本会比较高,维护成本也就增高了
  • 不OO,不容易组织扩展

我补充一点:

  • 过程化的代码不容易测试,不使用模式的代码也会造成测试的零散,造成浪费

更新:有一点不准确,就是关于复用,其实Javascript的各种Widget库(如ExtJS、Dojo和YUI的widget库)都做到更好的复用。缺点是目前的widget库中的高级控件都严重的绑架了Dom结构,造成自己修改Dom结构比较麻烦。而没有使用Micro Formats这样的基于标准的弱耦合,这是一个很大的问题。所以由于这样的实现绑架的问题,这些Widget库不包括在上面所述的框架对比中。