成为一名前端架构师

12,662 阅读18分钟

前言

你是一位经验丰富的前端开发,你的经验和能力在不断成长。有一天,公司决定任命你为前端架构师。你踌躇满志决定大展身手,然而,一个问题困扰了你。

什么是前端架构,前端架构师的职责是什么?

今天,让我们从多个角度来看看什么是前端开发,什么是前端架构。

前端开发是什么

首先,让我们来回顾一下近年来前端开发所走过的一些历程,了解什么是“前端开发”。

三驾马车

HTML、JS、CSS是前端的三驾马车,是前端最重要的组成部分。

HTML是前端的入口,一切从浏览器加载HTML文档开始。随后浏览器解析HTML文档,并加载相应的JS与CSS文件并解析执行。

CSS负责修改文档的展现样式,JS则通过侦听用户行为、修改文档内容以及修改元素展现样式来提供丰富的内容展现以及用户交互行为。

DOM & BOM

DOM(文档对象模型)和BOM(浏览器对象模型)是浏览器提供给JS的一系列接口。JS可以通过这些接口与浏览器/文档交互,例如添加用户交互监听、修改文档内容等等。

DOM包括与文档相关的接口,例如查找元素、遍历文档、修改文档内容等。BOM则提供了许多其他的功能,例如添加定时器、获取当前页面地址等等。

ECMAScript

ECMAScript是JS的标准,JS是ECMAScript的实现与扩展。从ES6版本开始,大量新特性的加入与演进,标志着JS的发展进入了一个新的时代。

对于一个新特性而言,将经历以下几个阶段:stage0(内部提议)、stage1(正式提案)、stage2(规范草案)、stage3(候选,部分浏览器已经实现该功能并获取用户反馈)、stage4(就绪,进入下个版本的ES规范)。

ES6+的出现为JS引入了许多优秀的语言特性,例如let/const提供了更好的变量/常量申明方式,Promise/async/await解决了回调地狱问题,class提供了更好的面向对象范式,ES modules提供了模块化的新标准。除此之外还有Proxy、Symbol、Map/Set等等特性同样值得关注。

浏览器

浏览器是前端的主要载体。浏览器主要包括用户界面、渲染引擎、JS引擎、网络、数据持久层等组件。

nodejs

nodejs使用了JS的语法规范,并在其上提供了包括网络/文件IO在内的系统交互能力。官方的nodejs是构建在Chrome v8引擎上的JS运行时。

npm最初是针对nodejs设计的依赖管理工具,而如今npm/yarn已经统一了web与nodejs的包管理。

web2.0

web2.0代表着门户网站向网站应用的转型。网站应用提供丰富的交互而且仅静态的信息展示。UGC(用户生成内容)的大量产生也是web2.0的标志之一。

这一时代标志性的技术包括jQuery、AJAX和前后端分离。

jQuery大大降低了浏览性兼容性带来的开发成本,同时sizzle提供的以css selector查询元素的方式大大提高了前端开发效率。随之而来的是构建在jQuery之上的前端组件库的大量出现,大大丰富了前端交互的可能性。即使随着新API的出现和浏览器兼容性的提升,如今jQuery已非主流,但其链式(fluent API)、集合操作、事件代理、构造函数重载等设计模式的灵活应用仍然值得我们学习与借鉴,更不用sizzle和jQuery对于前端发展的巨大推动。

AJAX允许前端向后台发起异步请求并更新数据,打破了原本必须向后台提交表单并最终请求新页面的模式。在之后的日子里,SPA(单页面应用)应运而生。

而在AJAX之后,web socket和web RTC进一步扩展了浏览器与服务器的通信方式。前者赋予了web实时通信的能力,而后者提供了实时语音/视频的功能。

随着前端库的大量出现、前端交互变得越发复杂,前后端分离的概念开始兴起。从整体的架构视角来看,这对应的是软件分层架构(表现层,业务层,持久层等等)的出现。如同康威定律所述,人员架构也在相应变化:前端开发、后端开发、DBA等等。

页面模板的编写慢慢从后端开发手中交到了前端开发手中,在此时,包括handlebar、mustache在内的基于字符串拼接的前端模板库出现。

HTML5 & CSS3

HTML5代表HTML规范的5.x版本,与2008年发布正式版,与2014年最终定稿。由于其发展历程与移动互联网高度重合,H5一词渐渐成为了“移动web网页/网站/应用”的代名词。

HTML5规范为web带来了许多新特性,包括更多语义化的标签,更丰富的表单项,canvas/WebGL,多媒体(web、audio)、地理定位、数据存储(localstorage、web SQL)、多线程(web worker)等等。

而与2010年正式推出的css3规范同样带来了media query、圆角、渐变、阴影、变形、动效/动画等一系列新特性。

为了应对纷繁的手机屏幕尺寸,media query与box-sizing、rem分别推动了响应式和自适应两大设计理念的发展。同时为了应对兼容性不一的问题,类似Modernizr、html5shiv这样的工具也应运而生。

HTML5与css3的诞生使得移动web开发如虎添翼,多媒体、富交互时代正式来临。

依赖管理

随着前端代码越发庞大,一个交互复杂的页面很可能包含大量依赖。要管理并理清这些依赖(js、css)并不容易。

面对这一问题,bower和require.js应运而生。

bower是面向web的包管理工具,通过bower我们可以追踪项目依赖库,并在新环境下检出项目时一键安装所有依赖。最终随着npm/yarn统一了web和nodejs的包管理,bower慢慢退出历史舞台。

在bower处理包管理的同时,require.js则致力于理清依赖关系。require.js通过异步加载依赖(js/css)使得树状的依赖最终收敛于根节点,树上的每个节点只需要关心自己的依赖。如果一个节点被复用,依赖子树会一起复用,而无需再检查依赖。最终页面所需要关心的,则仅剩依赖的根节点以及require.js本身。

编译/转译

在前端领域,编译/转译的概念首次得到关注或许该归功于coffee script和less(sass、stylus)的出现。

两者最终会被转换为js和css,而在此之前它们为语法添加了许多实用的功能,大大提高了开发效率。

除了coffee script和less之外,语法检测工具(eslint、tslint、csslint等)、代码压缩/合并工具等等也是建立在相同的技术基础之上。

如今作为后继者的babel、typescript和postcss等等已经成了前端开发中不可或缺的工具。

如果你对这一话题感兴趣,acorn.js或许是个不错的学习起点。

而以提高JS性能为目的而诞生的wasm,也是当下前端领域的热门话题之一。其产出是JS解释器所对应的字节码而非JS。

前端工程化

随着grunt、gulp等工具的出现,前端工程化在历史舞台闪亮登场。

针对不同部署目标对代码(js、css、html)进行压缩与合并,替换指定占位符,为生成的js、css文件名添加hash,并最终输出到指定目录,等等这一系列操作已经成为了前端开发中的标准流程。

随后出现的webpack提供了更契合时代的依赖管理模式、方便的开发环境(热更新、接口代理)等等功能,并逐渐成为最主流的前端开发工具。

webpack4.x的出现,以及各种脚手架工具/项目的普及,使得配置前端工程化这一部分的工作对大多数前端开发而言变得透明。

随着http2和ES module的普及,前端打包理念是否会发生新的变化?

单页面应用

说到单页面应用,首先要提到的是history API。

单页面应用的一大基础便是由前端操控的路由行为。在history API出现之前,JS代码可以改变URL中hash的部分并监听hashchange事件,这已经使得单页面应用变得可能。而history API的出现,则使得单页面应用的路由实现有了更好的用户体验,SPA成了前端开发口中的热门话题。

其次要说的则是mv*框架。

backbone便是先驱之一。backbone将前端代码抽象为模型(Model/Collection)与视图(View)层,视图层可以操控模型,而模型通过事件(Events)与视图层交互。backbone的路由(Router)基于hash API。

纵使backbone基于jQuery、需要自己操作DOM更新、相比于MVVM和MVP模式过于笨重,却任然不能掩盖昔日辉煌与历史地位。

angular通过藏检测机制由框架层负责DOM操作与更新,使得开发者不必先掌握原生DOM API或是jQuery的使用便能开发前端应用,将经历集中于业务逻辑、数据交互与用户交互。而angular大而全的特点则是有人喜欢有人厌。

React和vue的出现,为前端框架提供了更多选择。React引入了virtual DOM、jsx、immutable、高阶组件(HOC)、css in js、React Native等众多概念与玩法。vue则胜在易学易上手以及博览众家所长,同时提供了vuex、vue-cli、vue loader、scoped css等实用工具。

混合开发

关于前端最后一个话题是混合开发。

随着智能手机的普及,能否合并安卓与ios的开发成本成为了许多人关注的焦点之一,而混合开发如此的初衷,也注定了这条路的曲曲折折。

首先说说cordova。cordova在webview的基础上将原生与web的互通机制分装为jsbridge,并通过插件机制扩展其能力。虽然这是很有趣的尝试,然后web本身性功能(性能、功能)上的缺陷限制了cordova应用的发展。

不过原生(或非原生)应用通过内嵌webview提供部分高可变内容,或是提供部分非核心业务页面来降低开发成本,仍是APP开发中重要的一部分。

对于功能问题,一个很有趣的尝试是native script,其通过反射机制使得JS代码可以自由调用原生功能。

而对于性能问题,react native则给出了自己的方案。React引入的virtual DOM的设计使得JS可以通过调用封装好的原生代码来创建原生界面,从而提高了渲染性能。同时React Native构建在JS/web基础上的本质,使得其保留了动态下发内容的能力。

最初被设计来挑战JS的dart语言终于在Flutter开花结果。Flutter通过Dart VM、Skia绘图引擎等来实现跨平台开发,为了提高重绘性能,其重绘算法与virtual DOM的Diff算法如出一辙。

electron通过将浏览器(Chromium)、nodejs运行时一同打包的方式为web提供了开发桌面应用的能力。Atom编辑器、VSCode便是通过Eletron开发的。

PWA(渐进式WEB应用)则是通过Manifest(实现添加至主屏幕),service worker(实现离线缓存/缓存管理),Push & Notification(消息推送)来弥补web应用的一些使用缺陷,使用户获得更好的体验。

混合开发还有一个有趣的话题,是小程序。小程序具备了web应用轻快的特点(甚至更轻更快),易传播易更新,同时又提供了优于web应用的性能、功能体验。

小程序的本质是webview,在通过原生扩展webview功能的同时,小程序也对web开发中涉及内容下发的不确定因素(例如DOM操作、eval、new Function、功能受限的Rich Text等)进行了一定限制。同时小程序用原生的页面栈管理替代了web的路由管理,提供了更友好更接近原生的页面跳转体验。

为了帮助web开发者更方便的开发不同环境下的web/小程序应用,构建在React/Vue之上的工具,例如taro、uniapp也陆续出现,这要感谢编译/转译技术在前端领域的进一步普及。

随着w3c推出小程序(MiniAPP)白皮书,小程序作为混合应用一次成功的尝试,能否走得更远?

前端架构是什么

架构包含非常广泛的概念与内容,有许多不同的维度。初次肩负起架构设计或许会让人感到不知从何处开始。

接下来,请允许我来聊聊,关于作为一名前端架构师,你需要负责思考的问题。

技术选型

技术选型或许是大家最熟悉也最容易开始工作的部分。

你喜欢angular、react、vue还是其他框架?路由库、网络请求库、数据层用什么工具管理?使用或是定制化哪一套UI库?

你会使用less、sass还是postcss?是否需要为多语言和换肤功能引入额外的工具?

你和你的小伙伴是否是ts铁粉?项目中是否需要引入wasm?兼容性预期是什么,应该如何配置babel、是否需要引入特定的polyfill?

你将面对的是一个PC网站的开发,移动web应用,或是一个electron桌面项目?响应式和自适应如何选择?如果你开发的是小程序,你会选择taro、uniapp/mpvue或是选择不使用这些工具?

你的应用是否需要与APP整合?直接使用webview还是选择使用cordova?如果你开发的是一个跨平台APP,你将选择RN、weex还是flutter?如果是一个web应用,是否需要通过PWA来支持离线使用?

技术选型只是第一步。请切记,我们需要考虑的不仅仅是技术本身的优劣(很多时候不同技术本身就难以分出胜负),你还要考虑你和你的团队对于技术的熟悉程度和学习成本,并带领他们掌握你所选择的技术栈。

代码规范

你需要制定一系列规则来使团队的代码风格尽可能一致,当面对大型和长期维护的项目时,这点往往比想象得重要。

你可能需要借助一些工具,例如jslint、tslint、csslint、prettier等等。你还需要考虑使用BME命名、OOCSS、scoped css、css in js还是其他什么方法来避免CSS冲突。

当然这只是问题的一部分,还有许多问题或许无法通过工具来限制。例如,对于数组命名,使用arrlist还是复数单词(sheep这样的单词是否会让人感到困扰?)?文件目录如何组织?点击事件是否统一以on开头?

作为架构师或是Team Leader,你需要保持定期code review的习惯来保证团队正在以好的习惯书写代码。

以及,你是否需要统一团队的工具配置,例如IDE配置、git配置(例如使用LF还是CRLF作为换行符)、是否需要使用nrm来管理npm源并使用nvm来确保统一的node/npm版本?

UI规范

除了代码规范之外,如果有机会和设计师一起来制定一系列UI/UX规范,这会令你的项目长期受益。

确定主题与配色,typography(排印)规范(包括字体、字号、行高)。

你还要与设计师一通设计一套常用的组件以及交互方式,以确保你的界面在设计上遵循亲密性、对比、对其、重复的规则(《写给大家看的设计书》),同时给用户带来及时、一致、可控可预期的交互体验,例如”确定“统一使用绿色按钮,”取消“统一使用灰色按钮并在弹窗的左侧,蓝色文字代表连接与跳转,”删除“按钮使用红色并且每次点击会弹出二次确认框。

品质,来源于对细枝末节的把控。

公共代码

你需要管理你的公共代码,无论是UI组件还是非UI功能。

即使是只考虑单独的项目,也应该将具有复用可能意义的代码放到单独的目录下管理。

为了使用公共代码库,你需要搭建私有npm仓库,还是使用git submodule的形式?你的库是针对web还是nodejs设计的,对于web,你将通过webpack还是cdn的形式引入代码?如果不同形式都需要兼容,那以下形式的代码你应当非常熟悉了:

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = global || self, global.VueRouter = factory());
}(this, function () {
  //
}));

文档

正如之前所言,你需要带领你的团队掌握新技术并高效高质量的开发项目,并提炼可复用的代码与组件,许多内容都需要文档化。

对于非UI组件,JSDoc是一个不错的文档工具。对于UI组件,storybook绝对是一个神奇,你可以通过它创建一系列可展示、可交互的组件示例,并且让其他人可以直接拷贝实例代码。

对于非来源于代码的文档,你可能需要借助静态网站生成器(static site generator)或是博客工具来书写文档,vuepress、wordpress、conflurence、石墨文档等等都是不错的选择。

为你的团队提供可参考的代码模板是个好主意,对此你可以使用例如hygen(jondot/hygen)这样的工具。当我需要添加一个列表页面时,我会用模板生成初始代码,其中包含了分页加载、弹窗交互、筛选查询等等代码的模板,保证我添加的页面有一致的代码风格和交互行为。

分支管理

你需要为团队设立一套分支管理规范,如果对此你还不了解,搜索”gitflow“你可以找到需要有用的资料。

除此之外,是否所有提交到主分支的代码合并都需要提交pull request并通过code review?如何与CI/CD流程整合?commit message和提交频率是否要加以规范?merge还是rebase?

演进能力

对于架构而言,演进能力同样重要。将webpack从3.x升级到4.x,将vue从2.x升级到3.x,或许每次升级都会成为阵痛,但我们不能停滞不前,否则项目会慢慢变成一个难以维护的老顽固。

好在微前端理念能帮助我们处理升级和重构所带来的麻烦。single-spa是目前最流行的微前端框架之一,qiankun(umijs/qiankun)在其之上为多项目结构提供了可行的实施方案。

通过微前端架构,我们可以逐步替代项目中的代码,引入最近的技术,而不必因为畏惧而停滞不前,或是每次都翻江倒海一翻。

自动化:部署 & 测试

作为架构师,你需要认真了解你所使用/搭建的脚手架和webpack,熟悉每一项配置(module、optimization、plugins...)的意义与使用。

除此之外,你需要了解git hooks、docker,懂一些shell script,以便和运维团队一起整合CI/CD流程。

你需要通过自动化测试以及代码覆盖率检测来保证项目稳定前进,并制定合适的适应度函数来观察项目的健康程度。可选的工具包括jest、instanbul等等,如果你需要编写e2e测试,那你可能还需要熟悉headless chrome。

如果你决定添加自动化测试,或是遵循TDD/BDD的开发理念,这很好,不过请做好准备,这可是一项会持续牵扯团队开发经历的大工程。

大前端

从更大的视野来看,你可能还需要了解许多其他的内容:

BFF(Backend for Frontend)、SSR(服务端渲染)、nodejs、graphql、grpc、消息队列(mq)、授权与认证(oauth/JTW...)、nginx、数据库(SQL、mongoDB、redis、elastic search、TiDB/cockroachDB、TSDB、graphDB...)、日志管理、docker & k8s、微服务、service mesh(istio...)、serverless...

做好准备啦吗 :)