经历了近10年的发展,前端从刀耕火种到百花齐放,繁荣下孕育着一些趋势和变革。站在现在看未来,前端的边界在哪里,如何跨越这边界?如何看前后端分离?如何看全栈?前端工程师的未来是怎样的?
桐木,阿里巴巴B2B高级前端专家,专注前端十年。从浏览器到Web前端,从数字电视到互联网,从社交到电子商务,从技术架构到团队管理,桐木老师从这些不同角度出发,深入前端领域,积累了很多经验,悟出了很多道理。桐木老师对前端的发展有着自己的看法,InfoQ带你和桐木老师一起,看前端发展,预测前端未来。
桐木:我的工作经历大致分三个阶段,从数字电视行业到互联网行业的社交方向,然后又到电商方向。
我刚毕业时,误打误撞进入了数字电视行业,主要工作是做机顶盒上的前端开发(当时的中间件架构,UI层是基于Web的,和后来的Web OS有点像)。我在这个行业里摸爬滚打了四年,其中三年是做前端开发,一年是做浏览器开发。
2011年,Q+的一则招聘广告,激发了我对互联网行业的热情。遂加入腾讯,在即通做平台类产品,同时负责团队的基础建设。2014年下半年,我加入阿里B2B,进入B类电商领域,从此又得到了不一样的氛围和发展空间。
我目前的工作职责主要是技术架构和团队管理两方面。我的团队负责的业务是1688这一块的电商中比较基础的平台类业务,比如商品、交易、旺铺、会员、运营等。
桐木:1688的基础业务发展了很多年,在这些年里前端领域的技术也一直在飞速发展,所以前端的架构也一直在演变。WebView中留下了技术发展的脉络和痕迹。比如在一些古老的业务中,还有早期的Prototype式的,以及命名空间来挂不同模块的代码,还有晚一点的YUI的代码,然后接下来进入一个主流的“jQuery + amd loader + jQuery components”的时代,这部分代码现存的还比较多。
近几年我们不同团队也尝试了 ng、avalon、react、vue 这些 mv*的框架,这个方向最终被我们收拢到 PC React、无线 vue & react 的路线上来。总的来说,我们自己造的轮子不多,大体脉络是 YUI→jQuery→mv*,工程体系也是这几个东西的周边配套加上我们的一些定制。
Hybrid当然有用到了,原因是,想要在动态化、开发效率和用户体验三者之间取得一个平衡,在两三年前也没有多少别的选择。
Hybrid方案本身是为了在实际的项目中,使得Native与Web互相取长补短,互为备份的。这里可以特别提一下的是,需要做到面向未来的一些权衡:原则上能用Web做的还是尽量Web来做,有标准的尽量用标准,遇到碎片化、底层能力不平坦的情况,则采用Polyfill的方式。一些为了性能和体验做的一些事情,尽量对Web开发者透明,架构设计上正交出来。
桐木:刚才的问题中已经提到了一些,那么现在另外提两点。
首先,我们在很多场景下做到了PC和无线使用一套核心代码,不同端一套代码。这背后一方面是对前端模型层和后端数据及模型的梳理和抽象,不同的设备和端,在模型层其实差别很小,这部分抽取出来以后就是稳定可公用的一层。另一方面,View层虽然看起来不一样,但很多东西用语义化的方式去描述,又能再次屏蔽掉一些差异。所以到最后有差别的部分只是CSS、交互逻辑、数据的适配和定制以及少量View定制了。
第二,对于端的碎片化,我们有一部分通过Native能力来抹平,另一部分,我们引入了UC的WebView,也极大的帮助我们屏蔽了一些底层差异。
桐木:其实我们这边不太喜欢提前后端分离,更喜欢讲前后端融合。从技术架构来看,需要把数据模型和展现层分离,这就是所谓前后端分离。那融合怎么讲呢?是讲实施层面和人的层面,因为B类业务的复杂度、跨越业务复杂度的门槛往往大于跨越技术复杂度,所以,如果我们能把两边的技术门槛,通过服务化的方式降低,那么在写业务的时候,就可以根据情况,通过后端服务化的方式让前端来把Controller也给写了,或者反过来,通过前端服务化的方式让后端把View给写了。
所谓真正的分离,应该是在架构层面的解耦,也就是说,不管你是前端还是后端,除了一层Schema约定之外,写Controller的时候完全不要考虑View,写View的时候完全不要考虑Controller。在这方面我们算是已经摸索出一条路来,近来还有一些有意思的想法和实践,有机会的话会和大家详细分享。
桐木:混合开发主要是为了实现动态化和节约开发成本,但WebView里跑的部分无论如何也很难达到Native的性能和体验。目前很多技术的发展其实都是在改造WebView,试图甩掉一些包袱或者说历史负担。有人可能会奇怪,WebView有哪些历史负担呢?我们可以来仔细看看:
首先,是标准兼容上的包袱。由于WebView作为一个通用的浏览器内核,本身要求具备向前兼容性,比如虽然用flexbox布局浏览器可以更高效地layout,但为了兼容它仍然必须得能认得浮动布局、相对定位布局甚至表格布局。这些逻辑交织在一起非常复杂,牵一发而动全身。假设我现在fork一个新的WebView出来,裁减掉flexbox之外的支持,就大大降低了layout逻辑的复杂度,即使不做优化就已经能快不少了,更何况情况变简单以后还能够针对flexbox布局做专门的优化,获得更大的性能提升。
其次,浏览器的内部机制以及js语言在设计上,其实也有一些历史包袱。比如浏览器从一开始设计,js engine和dom engine就是两块独立的黑盒,js调用dom时相当于一次rpc调用,每次调用都会涉及上下文的保存和恢复。同时,js excute和dom render是跑在一个线程里的,即使两者没有调用关系,dom也必须等js执行完毕才能render。这两件事的结果就是网页在运行过程中会在这两个黑盒之间来回切换,各种上下文切换,各种互相等待,这样一来掉帧就在所难免了。所以,如果我们能够让js engine和dom engine在执行层面能够打通,变rpc调用为本地调用,就能加快不少。更进一步来说,如果能够有效利用多核,把js excute和render在一定条件下并行起来,或者把style resolving和layout并行起来,也能提升新性能。
再次,WebView本身确实也在越变越快,但有些OS的限制或者一些设备老旧WebView的存在,会导致碎片问题,这也在拖慢我们的脚步。这个大家比较熟悉了,例如iOS的Nitro、WKWebView之于UIWebView,还有Andorid4.4之后的Chromium WebView之于之前的WebKit WebView。
老郭的BeeFramework/Samurai、阿里的birdnest,是在甩前两项包袱,一方面取Web标准的子集,一方面把所有东西都拉到Native的runtime里执行;FB的React Native和阿里的Weex,主要在甩第一项包袱(部分优化了第二项);Mozilla的Servo致力于并行化和GC,主要是在甩第二项包袱;Intel的crosswalk、微信的X5、阿里的UCWebView等,是在一定范围内甩第三项包袱……大家为了甩掉这些包袱,都提出了不同的解决方案。
不论大家走哪条路,有一个共识还是大家都找到了的,那就是看齐Web的几个标准。因为Web的技术体系在UI的描述能力以及灵活度上确实设计得很优秀的,而且相关的开发人员也好招。所以,如果说混合开发指的是Native里运行一个Web标准,来看齐Runtime来写GUI,并桥接一部分Native能力给这个Runtime来调用的话,那么它应该是一个永恒的潮流。
桐木:全栈这个词挺时髦的,含义么,不就是啥都干,万金油么。
其实很久以前,哪分什么前后端,大家都是工程师,从头到尾,从数据库设计到接口实现,再到前端展现,从存储过程到负载均衡再到部署运维,大家样样都得搞。
但行业在发展,每个细分领域都越来越复杂,要从头搞到尾既不是不行,也不是太辛苦,而是根本就不可能。真要都搞的话,那么对每个领域的了解只能是半瓶水,搞出来的东西就是玩具。那怎么办呢?这就需要专业细分,在分工以后各自往深处去发展。
但问题又来了,分工以后我们还是需要把各环节连起来,这对接口设计提出了要求,还要考虑去联调这个环节。分工以后有了上下游关系,工期大家也需要配合好。
另外,还有一个情况:假设有两个业务,业务逻辑非常复杂,我们有两个人来做。如果是一个前端一个后端,那两个复杂业务的大部分细节,都是两个人都要了解的。因为B类业务特别复杂,所以这种情况比较普遍。这时候又不能直接退回到原来的“万金油”模式上去,怎么办呢?
全栈的模式这时候就被提出来了。全栈和最早的万金油模式的不同之处在于,每个领域通过服务化的方式隐藏了大量复杂度和细节,全栈工程师主要关注业务逻辑和业务架构,以及为了实现业务架构,必须掌握的前后端在服务化边界上的技术以及解决方案。这样就可以以比较小成本,由两个人分别把两块复杂业务扛下来了。
对于是否鼓励全栈的问题,其实,只要是有利于提升整体生产率的方式肯定都是鼓励的。全栈是否能够提升生产效率呢?这和业务特点、前后端的服务化水平,以及团队的人员结构都有关系。另外,也需要考虑个人意愿。所以,我们从两方面在推行这件事。一方面是在识别出来全栈确实能够提升生产率的场景下,通过提升服务化水平,来让这件事可能发生,这是外因;另一方面,通过职业发展路线、晋升标准和Job Model等配套设施的优化,配合技术新鲜感成就感的培养,甚至大量福利,来促进一批偏业务的、有全栈意愿的同学能放心且踏实地在这个方向发展下去,这是内因。
目前阿里推进全栈的BU不少,大家的阶段不同,取得的进展也不同,至于最后的结果,让我们拭目以待。
桐木:这个话题是我感受相当深的,不光是技术上,在职业发展、技术管理、架构治理过程中,我发现过去的很多经历都和这句话有或多或少的关系。
提一个早点的例子,在做嵌入式的浏览器的时候,WebKit还没火起来。那时,我们维护着一个内部自研的浏览器引擎,当时js引擎和layout都有各种bug,而且从设计上非常难解决。到2009年底,Android 1.5上WebKit的时候,我们意识到该放弃手上这个Web core,然后切换到WebKit了。这是一个较大的转折,当然,中间件全面转Andorid,也是不可逆的潮流。而这件事,则表明了视野和对未来方向的把握很重要。
面向未来,体现在职业发展上,从广电行业来到互联网,以及在周围前端大批转iOS/Android时坚守前端,这里面没有什么对错,但背后也是对趋势的判断、对未来的一种相信。
面向未来,也体现在技术架构选择上。比如:无论是鸟巢还是Samurai,早期的DSL设计都是Web标准体系比较远的,后面都不约而同的切换到了HTML+CSS+JavaScript这套标准上来了。这里体现了一个原则,就是能用Web做的还是尽量Web来做,有标准的尽量用标准,遇到碎片化、底层能力不平坦的情况,则采用polyfill的方式。
面向未来,还体现在接口设计上。不过这里要举的是个反例。
例如现在经常说的一个反模式:“除非你是在很明确的知道自己在做polyfill,否则不要去扩展原生对象”。这样做有什么坏处呢?有人可能脱口而出:“扩展了prototype,会破坏for...in时对象的纯净性”。恩,这是个原因,不过因为之前的这种遗毒,大家现在都很习惯for...in的时候用hasOwnProperty过滤一下了。
但最大的原因还不在于此,而在于这样做“失去了对未来扩展的兼容”。怎么理解呢?我这里举个具体的例子大家可能就明白了:以 Array.forEach
方法为例,在比较早的年代,Array对象下面并没有这个方法,当年Prototype库的引领下,很流行用扩展原生对象的方式来“方便"地增加一些好用的特性,于是很多人都用添加原型的方式自己添加了一些方法给Array,其中就有不少人添加遍历方法时正好选择了 forEach
这个方法名,就像这样 Array.prototype.forEach=fuction(){...}
。
这样看起来好像挺不错的,但问题在哪儿呢?我们一起思考:
你当时怎么知道以后规范不会往Array上加forEach这个方法呢?好,我确实不知道,所以保险起见,我防御性地加个 if(!Array.prototype.forEach)
的判断总行了吧?
问题是你怎么知道以后标准的这个forEach内部实现是不是跟你一模一样?好,你运气比较好,里面的内部实现还真是一模一样的。
问题是你怎么在规范出来前知道这个function的参数是几个,什么顺序?说实话,这个在设计上是很难预测的,比如jQuery的$.each方法,三个参数的顺序就是 index,value,array
,而后来规范中的forEach三个参数顺序是 value,index,array
。所以设想下,如果你当时用上面的参数顺序扩展了Array.forEach,那么在标准出来之后,请问你准备怎么修改,才能够让全站所有依赖这个方法的代码和去和新的基于标准方法的代码来愉快地玩耍呢?
面向未来之外,更需要立足当下。
我身边有一些架构治理、技术管理的例子,但因为需要交代太多背景,不方便展开,我觉得可以举HTML5和XHTML2标准之争的例子。
HTML5为什么能够打败XHTML2成为事实上的标准?有人认为浏览器开发商更有事实上的话语权一些,所以打赢了。但我要说这里面更多的是HTML5遵循的理念带来了胜利。我们来看看它背后的几个理念:
这些理念保证了一个标准能够在推进过程中,能够不对现有生态产生破坏性颠覆性的影响,能够争取尽可能多的人的支持,可以通过渐进的方式,由点及面的方式来落地。
当然,渐进性改革有时候却可能缺少点魄力,什么事情都不是绝对的,不是还有休克性疗法么。这里说的是针对一个复杂系统的一种解决问题的思考方式和策略,大家根据目标、场景、适用人群需要有不同的选择。
桐木:其实前端的发展在这两年已经有了不小的突破了,之前是一些边界上的扩张(服务端、移动端),然后是工程化及生态的完善(模块化、包管理),近期是语言、标准本身的一些进化。
归根结底,前端的发展与设备及交互方式的变革是分不开的。十年前我们访问的网页,和我们现在访问网页,在设备及交互方式上的变化是颠覆性的吗?并不是,我们的设备也就是从PC到了手机,在屏幕大小和交互方式上发生了一些变化,相应的,它们各自的机器性能、Runtime性能也有一些提升。但这些变化都算不上革命性的。
那么接下来十年呢?设备和交互方式会有变革吗?
可能大家已经看到了,VR和AR最近很火。在看得到的未来,我相信变革会因VR和AR的发展而发生,届时前端的很大一部分技能树,可能会完全发生改变,相应的标准也会往前迈进一大步,甚至前端的边界也可能会发生很大的变化。到那时候,称前端工程师为“视觉与交互工程师”或许更为贴切。
不过话说回来,我比较保守,我认为“视觉与交互工程师”这个工种出现的时间不会太近,最近看到的一些VR和AR产品,我觉得成熟度还不够。基于原生API开发的应用都捉襟见肘,更不用说在此之上产生生态和诞生相应标准,并形成类似浏览器这样的UI及交互的统一平台了。前端工程师要成为VR时代的”视觉与交互工程师”恐怕还得等一阵子。
感谢郭蕾对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ,@丁晓昀),微信(微信号: InfoQChina )关注我们。