2015阿里11.11:前端的变革
在这个双十一结束的点上,打算分享点东西,其实我一直乐意写些实在的技术点,因为不同环境里工程手段和团队发展很不一样。不过到这个双十一是我在阿里的第三个整年,我想把这些年里我们做的真正重要的事总结总结。
发布
在我来阿里之前,其实没太想过发布这个事情,在阿里的时候,也没想过发布方式是如此重要,不过最开始来的时候,听说前端跟服务端的配合方式吓了一跳:前端产出demo页面,服务端负责把参考html代码来写vm(就是velocity模板,阿里是用Java的),这个过程就是传说中的“套页面”了,这个过程往往不是那么愉快的,有时候服务端的同学会把标签嵌套搞错,前端出了bug,则需要服务端重新改模板。这个模式我一开始确实觉得不妥,但是并没有把它当做非常严重的事情而,直到后来回忆起来,我才知道当时的想法错的有多么离谱。
然而我运气特别好,在我自己没有做出正确判断的情况下,这个问题被服务端同学解决了——虽然我们当时脑子里想的都是“要搞webapp”。当时我们对WebApp的理解是单页应用,那么以静态页面+AJAX就是首选方案了,于是服务端同学帮我们搭建了一个叫做AWP的发布平台,和一个CDN源站,又驱动把h5.m.taobao.com这个域名(我知道你们要吐槽这个域名……历史啦历史原因)指向了CDN,这个事情对CDN来说也有划时代的意义,我们稍后再说。
从今天的视角来看,这个发布平台第一次让前端工程师有了向线上的发布能力,之前前端工程师基本都是发布资源文件和提供素材的,这个事情之后,前端工程师开始有真正意义上的“发布”,我之前跟团队同学开玩笑说,在这之前,前端连搞出线上故障的能力都没有——不要以为这是好事,没风险意味着没价值。
分离与同构
接下来一个很重要的事情,是手机淘宝目前的一个核心能力有关——API网关,通俗点说,就是所有的服务端提供API,而且通过统一的出口提供出来。这个便利条件,促成了一个前所未有的前端开发模式:前端开发纯静态页面,跟客户端调用同一套服务端API。
这个模式深度地解决了两个关键问题:
- 前后端分离
- 前端客户端同构(当然这里还不是彻底的同构)
当然这个方案有得的同时,也有舍弃:它舍弃了服务端渲染的能力。而对手机淘宝的业务和架构来说,这个做法是合时宜的。这时候的一些放弃,也为接下来也为后续的一些发展做了铺垫。
另一个对同构非常重要的,是手机淘宝的导航系统,这个事情我原以为也是比较无意中达成的,但是去年手淘Android架构师离职的时候跟我坦诚他暗中推动了很多,看来世上没有那么多偶然啊:)。总之从某个时期开始,我发现手淘的业务形态开始以页面为单位组织,所以顺道跟团队的人一起,推动了几件事:
- 业务以页面为单位组织
- 每个"页面",具有切换Web和Native的能力
- 页面对应url(基础业务不论web还是native都对应taobao:协议,手淘打开web页面对应taobaovebview:协议)
这个形态让手淘变成了一个类似浏览器的东西,从业务的角度,让子业务在Native和Web之间切换更低成本,也让后来Weex等方案的诞生有了土壤。
向服务端延伸
其实说到全栈,大家一般的印象是高手、全能,感觉很遥远。但是其实并不一定是如此。我们试图用一种更亲和前端的方式去推动全栈化。考虑到阿里的服务端基本上涉及的量会比较大,需要一定的性能和容量意识,只能要求少数人去获得真正意义上的服务端开发能力。
所以我盯上了一样东西——CDN。CDN的回源服务,它的前面有CDN缓存挡着,相对来说需要承载的压力是比较低的,非常适合前端来维护。业务上,我则选择了运营业务,因为运营业务特点鲜明,页面生存周期短,短期内爆发性量大,服务端申请机器大张旗鼓搞集群也是一种浪费。
一旦脑洞开了,就会发现其实这个方向上能做的事情就变得多了起来,因为CDN+回源服务的模式在面对大流量时有极大优势,所以我们发现,非个性化的、非隐私的数据,其实都可以这么搞,最典型的场景是全局配置、运营推荐的导购内容等。到后来时,一些客户端的同学也开始用这个静态集群上面的服务。
我们的使用方式也让CDN从一个静态资源服务逐渐变成了一部分业务的载体,这种CDN的使用方式,也是不多见的,幸好阿里CDN团队是很喜欢面对新挑战的,甚至帮我们做了ABTest。
向客户端延伸
其实我特别想写这一段请直接参考勾三股四的文章……
Weex是原来WeApp的基础上发展起来的,中间经历两次大规模的重构,第一次重构,代码几乎全部重写,第二次,整个设计方案全变,从原来的服务端设计变成前端设计。
其实Weex主要的功臣和贡献者不止前端,负责Android和iOS实现的、以及服务端的同学都付出了巨大努力,而双十一会场的前端@mingelz 似乎也不明不白地被拽进坑里……
勾三股四已经写了四篇,技术上我就不重复了,其实我想说的是,我们从2013年就开始干这件事,这项目一开始坑到首批参与者几乎全部离职只剩下一个搞客户端的还在……光重写就两遍,一个玩具和一个真正能用的技术方案之间,差距就是如此。(所以拜托某些围观群众不要说我们造轮子了好么,不是所有外国东西都比中国东西早的)
性能
我挺早就提出来过一个观点——一切不做profiling的性能优化都是耍流氓。
现在我觉得应该改改:一切没有线上监控的性能优化都是耍流氓。
性能这块网上的文章很多,看上去写的认真的也有很多,但仔细看其实有些错的挺离谱的。你不亲身经历一遍,没法体会到,真机测试跟你想象之间的区别,以及测试环境跟线上之间的区别。
我一直觉得性能最适合驱动的是前端,前端是距离用户最近的代码,所以前端应该做的,不仅仅是以前端的角度去解决问题,从一个url到一个页面的过程,涉及到WebView、网络层、DNS、运营商、服务端等各个环节,找出问题,分析原因,设计方案,推动解决,这是一个完整的性能优化过程。
我们比较幸运的是,我们有一群靠谱的合作伙伴,HTTPDNS、SPDY、ZCache等等技术方案,给我们带来了充足的弹药,但是再好的东西也需要人去用,前端在这件事上,必须明确自己owner的角色,对最终结果负责。
工具和库
这个事情我又要反省,我早先对node的判断是有问题的,我一开始把node看做“只是另一个服务端解决方案”,然而忽视了node在工具方面的价值和npm的价值。所以现在我们正在做亡羊补牢的是:工具链和基础库的npm化。
任何一个搞自己的库的团队总会被质疑在造轮子。我们的基础库从最开始的base.js,逐步发展到lib系列,到现在的npm化,自己搞的原因只有一个——我们更好。我们的基础库最好的地方就是坚持了单一职责的原则,没胡乱塞东西,这也让性能优化成为了可能。
工具链方面,我们则采取了全然不同的策略,几乎是全面贯彻了“拿来主义”,我们要做的,是把babel、sass、browserify、uglify、webpack、gulp等工具做整合,形成真正意义的工程体系,最近大家也在畅想,我们是否能能把构建、调试、发布等功能集成起来,做成一个ide?这应该是下一个双十一之后该讲的故事了。
结语
前端一直是一个变化很快的职能,它太年轻,年轻意味着可能性和机会,也意味着不成熟和痛苦。自加入手淘前端来,我经常担心的事情就是,我们团队每一天都在做一样的事,或者在不断跟随和尝试,最终一无所获。所幸至今回顾,每年还是总有点不同,也算给行业贡献了些经验值吧。