本文作者:雷志兴 原文刊登于《程序员》杂志2011年第二期。觉得写的非常好!所以转过来跟大家分享分享!
模块化的Javascript库 —— Tangram
Tangram是一个适用面广、高度模块化的Javascript库。内含大量基础方法与Javascript组件,开发人员能基于它便捷地完成开发工作。本文将介绍Tangram的历史、设计原理和系统架构,旨在帮助各位读者更好地了解Tangram。
历史
要理解Tangram的使用场景和设计思想,需要从Tangram的历史渊源说起,其实这也是百度Web前端库的发展史。
05 - 07年,百度前端处于洪荒年代,没有Javascript库,仅在部门wiki中存在一些函数积累,工程师开发时,copy-paste以后稍作修改便成为产品的一部分。
07年起,部分产品逐渐开始基于开源库(prototype,YUI等)进行修改,形成产品内部的JS库,积累也逐渐增多。但是开源库的功能相对百度的需求都过于复杂,体积庞大,部门内出现需要百度Javascript库的呼声。
08年初,一些有想法的工程师利用项目闲暇时间,整理编写第一个通用Javascript库 —— FE,FE库在百度社区类产品线得到了较广泛的使用,从那时起逐渐形成了模块化、无侵入的设计思想。
09年6月,由于FE库没有固定的维护人员,同时在接口组织,可维护性上还有很大的提升空间,经过讨论,决定基于公司内多个Javascript库,由专人负责,开发出一个新的类库。于是我们有了Tangram这个全新的基础库,经过一年多时间发展,Tangram已经包含开发中大多数常用的功能与组件,成为了百度应用最广泛的Javascript库。
10年12月底,Tangram正式开源,现已正式发布两部分。一部分是基础库,包含DOM操作,ajax等基础功能,另一部分是组件库,包含大量可重用的ui控件以及动画效果等。除此之外,我们还基于Tangram开发了在线编辑器,无线库等子项目。
设计原理
七巧板 —— Tangram的中文名 ,这是一个古老、简单的模块化系统。Tangram库正如七巧板一样,它的核心设计思想就是模块化。
模块粒度小
在国内,由于互联网的连接速度仍然比较慢,同时用户的计算机与浏览器相对老旧,因此前端开发人员一直都很关注带宽占用和加载速度。市面上的Javascript库,最小的模块一般是一组功能方法(如DOM操作的相关方法)或者一个组件(如对话框)。开发人员在选择时存在一个两难问题:如果库体积精简,二次开发量就大,如果库功能丰富,就会有冗余代码。
为解决这个问题,Tangram采用了更小的模块拆分。在Tangram基础库中,每一个函数方法是一个独立的模块;在ui组件中,最小的模块单位是组件插件。开发人员通过在线代码选择功能,获得定制后的Tangram放入自己的产品中。
因此,Tangram能够不断补充功能模块,而使用者始终能按照需求,获得体积最精简的代码,这在功能丰富与体积精简之间达到了平衡。同时,每一个模块都是独立而且简单的,开发人员也可以很方便的对其进行研究,了解原理进而更好的使用。
【图1】Tangram的代码选择功能界面
易于封装、扩展
Tangram面向的产品跨度广,光是百度内部就有搜索产品,社区产品,商业产品三大系列。不同的产品对Javascript库的要求也不尽相同:搜索产品要求体积精简,社区产品希望使用方便,商业产品看重功能齐全。
很显然,Tangram不可能直接满足所有产品的需求,只能在封装和扩展的便利性上下功夫。首先,基础库中大多是静态方法,对封装十分友好。而在组件库中,提供了组件插件、公用行为等机制,让使用者可以很方便的扩展出自己想要的功能组件。使用者很方便的就能基于Tangram,选择合适的模块,封装一套符合产品自身特点的Javascript库和一个个独立的功能组件。
当然,在Tangram内部,也会利用这个特性完成一些较高层次的封装。如将DOM和Event封装成Element,提供链式调用功能。
无侵入式设计
在面对多年前的遗留系统,或者含有第三方Javascript代码的系统时,总能看到页面上泛滥着各种全局变量,或者对prototype的修改,甚至会存在同一个Javascript库的不同版本。开发者常常会因为代码之间的相互冲突而烦恼不堪。
为了最大程度的避免冲突和污染,Tangram仅仅暴露一个变量到当前作用域,使用者完全可以把Tangram放在闭包中使用,这样即使页面上含有两套不同版本的Tangram,他们之间也不会有任何冲突。同样的,组件库也采用了无污染的设计,不会对页面上的现有DOM元素、业务代码产生影响。
系统架构
Tangram从一开始就致力实现一个结构清晰、层次分明的系统。系统结构如下:
基础库
Tangram底层是基础库,包括18个功能包,如DOM,event,ajax,page等,满足开发中对基础方法的需求。基础库被分做两部分:core和extra,core是常用方法,gzip压缩后体积尚不足10K,extra则是其余不够常用的方法,这是统计了用户对接口的依赖程度后进行的划分。
为保证基础库方法的精简,所有基础库方法一律不做参数检查,由调用者或者二次封装自行保证。此外,整个Tangram库都有很强的一致性,同类的方法接口命名和参数形式都很一致。
组件库
组件库在基础库之上,其中又以UI组件结构较为复杂。所有的21个UI组件都是基于UI Base开发的,UI Base实现了UI组件的统一创建,插件与行为机制,代码也足够精简,gzip压缩后体积仅1K。
UI组件的插件与行为
正如前文所述,组件的功能丰富和体积精简之间存在矛盾。特别是在产品不需要组件的某些内置功能时,那部分代码就成为了累赘。为了调和这种矛盾,Tangram在UI体系中采用了插件机制。每个UI组件都被拆分成了一个小巧的UI核心,与一组功能独立的插件。
UI核心仅完成数据结构定义,控件DOM结构和其他控件基本功能,所有非必须功能都由插件提供。插件可以在代码选择时,由使用者根据需要,自由选择。如对话框核心仅仅完成对话框的创建、开启、关闭与更新,由插件提供拖拽、缩放大小、键盘支持、模态窗体等附加功能。
此外,针对UI组件间的共同点,我们抽取出了UI behavior,UI行为能被自由的添加到任何组件上,这个附加动作甚至可以来自用户调用,如将draggable行为附加到组件上以后,组件就拥有了拖拽行为。
开发、发布过程
Tangram现在由专门的团队负责开发和维护,为了保证库的持续发展,一套严格、可遵守的开发流程是关键。Tangram的开发分四个阶段:
调研、接口设计:调研使用场景与问题来源,同时参考同类组件,完成功能定义与接口设计,供小组评审。如果功能较复杂,需要提供一个完成基本功能的Demo,用于验证设计的正确性。
开发:完成代码,手动测试用例与基础自动用例,基础库模块采用测试驱动的方式进行开发。
代码评审:将代码提交到codereview平台上,全组参与评审,一个模块一般需经历2-3轮评审修改。评审完毕后,代码会被提交至github的dev分支上,由QA编写完整的自动化测试用例进行测试。
在开发过程中,我们尤其注重设计和代码评审阶段。一般来说,一个模块的设计时间要占到整个开发周期的50%以上,而代码评审时间在30%左右。值得一提的是,注释在Tangram中占有很重要的地位,所有API文档都是通过注释生成,因此在代码评审时,也会重点关注注释的准确性和完整度。
当dev分支上的功能累积达到roadmap目标,进入发布阶段。由发布负责人review所有新增功能与bug修复,整理changelog,同时QA负责人确认自动化用例的覆盖率,进行完整回归。测试完毕后,会将相应代码合并到master分支,打上版本tag。
文档与源码
如果你想更多的了解Tangram,或者参与Tangram的讨论或者开发,请关注下文网址:
在线文档:http://tangram.baidu.com
贴吧讨论区:http://tieba.baidu.com/tangram
基础库源码:https://github.com/BaiduFE/Tangram-base
组件库源码:https://github.com/BaiduFE/Tangram-component
Tangram base和component都将在兔年春节前后发布一个新的稳定版,此外,Tangram 编辑器也有计划于2011上半年开源,同时无线库也在紧张的开发中,敬请期待!