在前端整体进入组件化开发时代后,手写各种 UI 组件成为了许多前端工程师入门后的第一课。而对于工作了几年的资深工程师来说,手写组件已经不再是问题,但对于如何帮助团队提升整体开发效率以及个人接下来的技术成长方向却开始变得非常迷茫。
想要摆脱对未来的迷茫,最好的方法就是向后看,看一路走来前端开发是如何从服务端主导的静态网站一步步发展到现在由客户端主导的单页应用。只有了解了过去前端分别在不同的阶段解决了怎样的问题,才能更好地看清楚未来要向哪里去。
在前端界大名鼎鼎的 jQuery 诞生于 2006 年,那时还没有 Google Chrome,微软刚刚发布了直到现在还在令许多前端开发者头疼的 IE 7。
jQuery 作为试图抹平不同浏览器之间 API 差异的先锋进入了人们的视野,并在之后很长的一段时间内占据了 Web 开发领域统治性的地位。那时开发一个网站并不需要先配置一个复杂的脚手架,只需要新建一个 HTML 文件即可,开发者们也远未意识到未来前端开发究竟会复杂到什么样的程度,以页面为单位的开发方式在当时看起来并没有什么问题。
那时还没有人提出组件的概念,基于 jQuery 的 UI 组件都被称为 jQuery 插件(plugin),代表着在任何浏览器环境下都可以即插即用。
项目的开发速度完全取决于页面数量的多少及布局的复杂程度,所有的变量都挂载在全局之下,引用的各个插件之间相互独立,这样的开发方式似乎并没有给开发者们留下多少可以优化的空间。
随着 Ajax 等技术的普及,客户端 JavaScript 的代码量也越来越大,开发者们开始无法忍受全局变量带来的命名冲突,各个插件之间虽然相互独立但多个插件之间的依赖关系却也变得越来越复杂。这时前端开发对于模块化的需求变得非常强烈,于是便涌现出了 RequireJS 和 Sea.js 两大专注于解决前端模块化问题的类库,以 Sea.js 发布 1.0 正式版的时间为参考,那时是 2011 年 7 月。
解决了命名空间和文件依赖的问题,前端终于可以轻装上阵。配合着日趋成熟的各种 UI 插件库,这时前端项目的开发速度有了第一次质的提升。
摆脱了全局变量的限制,越来越多的前端插件被沉淀了下来。页面数量虽然依然被作为衡量开发量的一个重要指标,但在开发流程中各个模块之间已经开始了协作,开发一个新页面的工作量也不再完全等于页面本身。与此同时,npm 的出现也让这些沉淀下来的前端插件有了栖身之处,却也为今天前端类库小而分散的现状埋下了隐患。
在前端模块化进行得如火如荼的同时,由谷歌开发的 AngularJS 也于 2010 年 10 月发布,这是第一次 JavaScript 框架试图接管所有的 DOM 操作。不过由于在当时过于超前的设计和后续断崖式的升级,AngularJS 一直没能打破 jQuery 在前端开发界的统治地位,直到 2013 年 Facebook 发布 React,jQuery的份额才被分了一点出来。
专注于 View 层的 React 虽然提出了 JSX 这样不符合传统前端开发习惯的新概念,但基于虚拟 DOM 的重绘效率确实要比 AngularJS 的脏检查高出一个数量级。这着实吸引了许多前端开发者的目光,也让前端开发真正进入了组件化时代。
摆脱了 DOM 的限制,组件与组件之间的数据传递第一次变得如此轻松,这让开发功能强大的大型复杂组件及沉淀能够覆盖大部分底层需求的 UI 组件库变为了可能。
过去的几年中,以 ant-design、material-ui 等为代表的优秀的开源前端组件库如雨后春笋般冒了出来,MVVM 框架配合其生态内的组件库成为了现代前端开发的标配。与此同时,前端工程化的浪潮也汹涌袭来,以 Babel、webpack 和 TypeScript 等为代表的 JavaScript 增强工具帮助 JavaScript 摆脱了脚本语言的定位,JavaScript 也开始成为编写大型工程项目的可选项。
但这时开发者们突然发现,以前只需要打开 Notepad++ 就可以轻松写前端的日子不在了,开始一个前端项目变得异常复杂。在组件库的帮助下,虽然项目的复杂度被大幅降低了,但花在写代码上的时间却一点也没有减少,用组件拼出一个个页面的世界似乎并没有想象中那么美好。
时间来到 2017 年,作为前端组件库界标杆的 ant-design 先后发布了 ant-design-mobile 及 ant-design-pro,淘宝系也发布了飞冰(以下称为 ice)。
其中 ant-design-mobile 是一套专注于移动端混合应用开发的前端组件库,现在又推出了 React Native 的版本。曾经在前端开发界流行过一段时间响应式设计的风潮,即一套代码适配所有终端。但慢慢大家发现,一套代码支持所有终端终究只是一个美丽的梦想,移动端和桌面端之间页面尺寸及操作交互的巨大差异,导致二者都需要更专业的解决方案来应对。
ant-design-mobile 想要解决的是移动端的问题,而 ant-design-pro 想要解决的则是企业中后台管理系统搭建这样一个问题。这些被抽象出来后针对中后台系统优化的组件并不能够直接用于搭建前台项目,但牺牲了通用性所换来的专业性也代表着前端在向着细分领域的专业化解决方案靠拢。ice 与 ant-design-pro 类似,所不同的是 ice 还集成了项目的脚手架部分,致力于实现一套纯 GUI 的前端开发模式。
这里我们先按下这些垂直领域的解决方案是否能够解决相应的问题不表,但我们从这些事例中可以看出的趋势是清晰的:区别于之前大力建设作为前端基础设施的组件库,前端的下一个方向就是要在这些基础设施之上同时向多个细分领域进军,如上面提到的移动端、企业中后台,又如富文本编辑、数据可视化等这些对于专业深度要求更高的领域。
随着我们对未来的认知越来越清晰问题也随之而来:在这么多的细分领域中应该专攻哪一个呢?
对于这个问题我们很难给出一个确定的答案,因为每个人所擅长的领域都不尽相同。但有一点可以确定的是,对于资深工程师来说,除了抽象 UI 组件的能力,对业务组件的良好抽象也是一个非常值得去培养的能力。有人可能会提出异议:“我每天写的不就是业务组件?业务组件因为其本身复用价值比较低所以不值得去抽象难道不是前端开发界的共识吗?”
如果你也有着同样的困惑,那么你很可能走入了一个认知误区,即业务组件等同于商品详情页这样具体的需求。事实并不是这样,对业务的抽象代表的是页面的布局、应用的鉴权、产品的国际化等这些更高维度上的问题,只有解决好了这些问题,配合上基础组件库才可以真正做到保质保量地完成一个又一个前端项目,最终推动公司业务向前发展。
截止到今天,千点工程师们在谈起 Web 应用开发时已经很少再会提起如 JSP(JavaServer Pages)、ASP.NET(Active Server Pages)等这些传统的服务端 Web 应用开发方案,有一些追求潮流的公司像 jQuery、Bootstrap 等这些直接处理样式及交互的工具库也逐渐摒弃了。随着 React、Angular 及 Vue 这些 MVVM 框架的流行,使用组件去组合页面逐渐代替了 Web 应用过去以页面为单位的开发方式,各种各样的组件库也应运而生成为了支撑现代 Web 应用开发的中坚力量。
传统企业管理系统(ERP)
抛开一直在走下坡路的面向用户的客户端应用不谈,长期占据 Web 应用开发需求主流的各种企业管理系统却从来都没有沉寂过,只是因为这些内部应用的使用者通常来讲不过是内部员工而已,人们对这些管理系统的期待与忍耐度都已经被培养到了一种近乎变态的地步。
但事实上对于企业管理系统开发方式的改良从未停止过。随着互联网在办公领域的深度普及,几乎所有的传统企业都在将老旧的 CS(client/server)架构的内部系统迁移至更方便灵活的 BS(browser/server)架构。但令人遗憾的是,很多这样的升级只是将原来 C# 写的代码转换成了 JavaScript 而已,相较于现在各种交互流畅、动画炫酷的面向终端用户的应用,大部分企业管理系统的设计与交互依然停留在 Win97 时代。
顺势而起的潮流
积重难返的企业管理系统同样是一片充满了变革机遇的绿洲,但有机遇的地方就会有挑战。企业管理系统作为一个已经存在了几十年的传统行业,一直以来都没有人能够总结出一套较为通用的解决方案,这也从侧面说明了解决这一问题要面临着多大的挑战。相较于注重展示的面向终端用户的应用,企业管理系统的核心在于对工作流程的抽象,这一部分根据企业的不同,其复杂度也不尽相同。这导致了抽取不同系统之间的共性变得异常困难,经验或者说知识很难沉淀下来。另一方面,再小的企业管理系统也都是“麻雀虽小,五脏俱全”,通用布局、用户登录、权限管理、菜单路由、消息通知、操作反馈、多语言支持等等这些模块一个都不能少。这样分散且琐碎的组成形式,让解决企业管理系统开发这个问题不仅需要强大的技术背景支持更需要耐心与细心。
当然,目前在这个领域也有着许多优秀的先行者,我们一起来看几个开源的企业管理系统。
react-admin
ngx-admin
blur-admin
ant-design-pro
对于上面提到的这些优秀的开源项目,许多开发者所抱的态度很多时候都是又爱又恨。在网络讨论中,一个经常被人拿来讨论的问题是,互联网大厂的工程师和传统公司的工程师之间有什么区别?但其实除了工程师之间存在着不同外,互联网大厂设计师与传统公司设计师之间的区别才是最为巨大的。
在传统公司中绝大部分的设计师都是项目导向的,这导致设计师很少有时间去思考和沉淀所做过的东西。素材库、图标库、设计理念及交互方式等这些本该有确定答案的部分几乎都是缺失的。造成这一结果的除了设计师自身的原因之外,“罪魁祸首”其实是公司内部的管理机制,即外行领导内行。许多非软件开发行业出身的项目经理经常简单粗暴地认为两个系统之间长得像就是偷懒,一个系统用了栅格式布局,另一个系统就非得是列表式,这不仅造成了巨大的资源浪费,更带坏了许多设计师的设计思想,将设计系统变成了设计广告,力求标新立异,推陈出新。
说回企业管理系统,许多认可这些开源项目的开发者在新项目开始时遇到的第一个问题就是,设计师已经给出了第一版的设计稿,如果我现在要拿上面这样大而全的解决方案去实现的话要怎么才能跟设计师交代呢?如果要深入内部去把这些开源项目不符合设计要求的部分都改成自己这边的实现,是否还不如另起炉灶再做一个?
是的,在非一线的互联网公司中,困扰程序员的关键往往不是技术,而是不同部门之间因为各自背景、诉求、视野等不同而产生的不协调。大而全的方案看起来很美,但实践起来却困难重重。
为了解决大而全的方案在实践中不够灵活的问题,我们是不是可以将其中包含的各个模块解耦后,独立发布出来供开发者们按需取用呢?让我们先来看一段理想中完整的企业管理系统应用架构部分的伪代码:
在上面的这段伪代码中,我们抽象出了多语言支持、基于路由的权限管理、登录鉴权、基础布局、侧边栏菜单等多个独立模块,可以根据需求添加或删除任意一个模块,而且添加或删除任意一个模块都不会对应用的其他部分产生不可接受的副作用。这让我们对接下来要做的事情有了一个大体的认识,但在具体的实践中,如 props 如何传递、模块之间如何共享数据、如何灵活地让用户自定义某些特殊逻辑等都仍然面临着巨大的挑战。我们需要时刻注意,在处理一个具体问题时哪些部分应当放在某个独立模块内部去处理,哪些部分应当暴露出接口供使用者自定义,模块与模块之间如何做到零耦合以至于使用者可以随意插拔任意一个模块去适应当前项目的需要。
在本节中我们从前端的发展到企业管理系统的历史讲起,一起探讨了组件库并不能够很好地解决企业管理系统这样一个需要更高层抽象的问题,并由此引出了组合式开发的概念,即将不同的核心模块分别抽象再根据项目需要最终组合在一起的开发方式。