什么是前端工程化

2024-07-25 pv

之前写过一篇文章:JavaScript 模块化演进🔗,讲的是 JavaScript 语言模块化的历史演进。

模块化的诞生,是为了解决大型软件项目有效管理的问题:不断更新的版本,广泛的依赖关系,不同项目组之间的协同。如果没有一个良好的模块化机制,一个项目在从小到大演进的过程中,很容易失控。

《人月神话》这本书,介绍的就是软件项目管理之道。用整整一本书阐释并尝试解决这个问题,一方面说明这个问题的确存在,而且相当棘手,另一方面,软件工程领域也积累出一些应对之道,或者说,最佳实践(Best Practise)。

相比于眼下前端丰富的技术栈和工具链,模块化可能只是其中很小的一部分。

前端工程化,是一个更加庞大、更加丰富的范畴,借用工程上的思路和方法,用尽可能低的成本,提高前端开发的效率和质量

我的第一版个人网站,写于 2016 年。那时候还是 jQuery 和纯 CSS 的天下。记得当时主流浏览器对 HTML5 的支持都还不算友好。

个人的小项目,开发量不大,网站用户少,质量要求不高,对于工程化的需求并不迫切。

不过今时不同往日。

纷繁复杂的库,项目之间的依赖,项目成员数量的激增,对于大型项目而言,无论是从成本还是产出角度,工程化都是必要的

因此对于一名普通的开发者,有必要了解,前端工程化是为了解决什么问题,以及如何解决的

1. 工程化

按照我的理解,工程化的核心,就是标准化

标准化,一方面意味着稳定,另一方面,意味着成本可控。

《薛兆丰的经济学讲义》里,讲过一个很有意思的话题:在经济学里,什么叫做优质产品?

答案令人意外。既不是最便宜的,也不是质量最好的,而是最“稳定”的

因此,肯德基,麦当劳这种连锁餐饮,提供的产品可称之为优质。因为你在全国任意地方,走进去,点一份汉堡和可乐,味道几乎一样。

稳定的背后,有着一套严密的流水线支撑:标准的供应链,标准的储存方式,精确的烹饪时间和温度,统一的出餐顺序。

标准化,不仅有助于形成规模优势,更重要的是降低了员工的不可替代性

任正非讲过:用机制的确定性,对抗人的不确定性。

否则那么多家门店,那么多员工,每天如此多的出餐,想做到“稳定”,几乎不可能。

这一套理念,迁移到软件工程领域,同样适用

虽然我本身是一个开发者,但在我看来,整个研发成本结构里,成本最高,且质量最不稳定的,就是开发者本身。我自己,虽然已经写了很多年代码,但还是经常写出 Bug。

这几乎不可避免。人固有一种,往熵增方向的惯性。

好在,得益于“摩尔定律”指导下计算机硬件的发展,开发中的机器成本几乎可以忽略不计。所以最经济的办法,就是尽可能的将开发工作流程化,自动化,让机器多做一些事

对于公司决策层,他们是有相当强烈的意愿推进并落实这件事的。

因为无论你是谁,遵循这样一套工程体系,就能生产出 Bug 更少,且可维护性更好的代码。人的不确定性被极大地降低。

所以有时候程序员自嘲为“码农”,精确而优雅。

这种体系的构成,主要有三个部分:标准化流程,标准化工具,标准化产出

2. 前端工程化

前端工程化,就是工程化在前端开发和部署领域的一套实践。

这几年提及的频率比较高,因为现在前端工程的复杂度太高了。

十年前,没有工程化的概念,也没有这个必要,因为前端工程相对简单,目录简单,功能简单,开发人员少,项目依赖也少。

现在不同了。伴随浏览器功能和效率的不断提升,移动端的普及又带来跨端开发的需求,与用户的交互更多用 Web 的技术呈现。现在的前端开发,已经细化为一个独立、专业的工种,以应对与日俱增的开发需要。

工程大了,人多了,如何有效管理就成为一个亟需解决的问题。

前端工程化应运而生。

2.1 标准化流程

前端开发流程大致如下:

Loading graph...

这很像是标准作业流程(Standard Operating Procedures, SOP)

所有的产品经理,开发者,QA,运维,都处在这套框架下,严格遵循流程,各司其职,降低协调成本。

大流程里会有更加细化的小流程。

比如方案设计,会有文档模板,组织评审,复盘更新。

编码里,有统一的代码组织结构,静态代码分析,格式化。

测试有单元测试,集成测试,压力测试,端到端测试。

交付有灰度发布,功能验证。

即使是一个新人,在流程的保证下,写出的代码也不至于太差。

2.2 标准化工具

标准化的流程需要标准化的工具保证。

这是程序员最擅长的领域,让一切能够自动化的工作,尽可能自动化。

由于 CI/CD 的存在,很多工作,像测试,部署,都可以委托给提前搭建好的流水线(Pipeline)。流水线上会自动执行诸如编译、代码分析、格式校对、单元测试等。这一块已经是一个非常成熟的生态了。

开发者只需要专注于功能实现,并准备好测试用例,其他的交给机器。

这就是我十分推崇 CI/CD 的原因,让机器工作,人类思考

2.3 标准化产出

标准化产出,是标准化流程和工具的必然结果。

产出的标准化,意味着部署、迁移、回滚变得极为方便

对于后端服务而言,目前通常部署在云原生环境下,Docker 镜像即为标准化产出。

对于前端工程,有成熟的打包工具,像 Webpack 等,按照固定配置打出的包,也可理解为是标准化的。

2.4 小结

前端开发草莽的时代已经过去了。

领域、分工的细化和专业化,意味着行业的成熟。

3. 工具链

工具链主要有四个部分:

  • 环境
  • 安全网
  • 转换工具
  • 开发后工具

3.1 环境

前端工程师写的代码,都是跑在浏览器上。得益于浏览器提供的跨平台性(Cross-Platform),开发者无需考虑跨平台的问题。

尽管如此,开发时的环境,通常都是 Node.js,或者 Bun,可以理解为运行在本地(Local)的 JavaScript 解释器。因此开发环境代码,到生产环境代码,需要一次转换,工具后面会提到。

包管理系统,原生的是 npm,不过现在 pnpm 和 yarn 使用较多。

3.2 安全网

安全网是一个比喻。

它描述的是一系列辅助工具。

  1. Linters。这是一种静态代码检测工具,可以检查语法错误、类型错误等,通常会提供丰富的配置选项。ESLint 几乎是 JavaScript Linter 的工业标准。还有其他语言的,比如 stylelint,可以检查 CSS 的问题。
  2. 版本控制。无论对个体开发还是团队协作都尤为重要,常用的工具有 Git 和 GitHub,有些企业内部会使用 GitLab,原理类似。
  3. 代码格式化。这一类工具不是用来检查错误,而是格式化代码的。不同开发者有自己的风格喜好,关于 Tab 还是 Space 的争论由来已久。团队开发则需要一套固定的工具和格式,否则很快便会陷入混乱,不利于后期维护。Prettier 是一个非常流行的代码格式工具。个人观点,代码格式很难说有什么最佳实践,如果非要说有,那就是保持前后一致
  4. 类型检查。TypeScript 几乎已经是 JavaScript 类型检查器的事实标准。

3.3 转换工具

转换工具(Transformation)是一种将开发环境的代码,转换成生产环境运行的浏览器兼容(Browser-compatible)代码的工具。

在前端开发中,主要使用的是三种语言:HTML、CSS 和 JavaScript。

转换工具提供的功能也主要有三个。

  1. 代码转义。使用最新语言特性的代码,无法运行在老的浏览器上。因此需要一次翻译。
    • Babel。一个 JavaScript 编译器,将最前沿的 JavaScript 语言特性翻译成老的风格。
    • PostCSS。与 Babel 类似,不过是用于 CSS 语言。
  2. 语言翻译。有时候会用其他语言开发,然后通过工具翻译成 Web 兼容的语言。
    • Sass/SCSS。CSS 的一种扩展,允许使用变量,嵌套规则,函数等。
    • TypeScript。上文已经提过,是 JavaScript 的超集(Superset),为 JavaScript 提供类型支持。TypeScript 编译器负责将 TypeScript 翻译成 JavaScript。
    • React/Vue。都是前端开发框架,提供更多功能,通过自定义语法,基于原始 JavaScript 构建功能。其背后的实现更加复杂。
  3. 优化。通常由打包器 (Bundlers)实现。例如通过 Tree-shaking 算法去除无关代码,或者 minifying 去除空格,让生产代码更小,优化网络传输。
    • Webpack。最流行的打包工具,插件生态丰富,缺点是略有些复杂,效率低。
    • Vite。一个更加现代的构建工具,因其速度,简洁和丰富的特性著称。

3.4 开发后工具

开发后工具是用来确保你的代码发布后能持续稳定运行。主要涉及测试和部署。

  1. 测试。这是一种保证代码质量最简单、成本最低,同时也是效果最好的方式之一。严格来说,没有测试用例的代码,不应该发布到生产环境。
    • 测试框架。常见的有 Jest, Mocha 和 Jasmine。
    • 自动化测试系统。Travis CI, Jenkins, Circle CI 和 GitHub Actions 等。
  2. 部署。部署系统允许你发布网站,可以是静态,也可以是动态。常见的流程是,推送变更到远程仓库,触发编译,运行自动化测试,没有问题的话就部署到生产站点。
    • 相关工具。GitHub Pages, Vercel 和 Netlify 都是常见的部署工作流,本网站即构建在 Netlify 之上。
  3. 其他。还有一些工具可以使用,Code Climate 可以收集代码质量指标,webhint browser extension 可以检测跨浏览器兼容性,GitHub bots 提供了更多关于 GitHub 的功能,Updown 则提供运行时间监控。

4. 总结

曾经有位朋友跟我讲过:

软件工程的核心是控制复杂度

良好的工程化,带来的不仅是效率,还有确定性。对于一个团队组织而言如此,对于个体亦然。

说实话,有时候在这样的规则下工作,编程,时间久了会觉得有些乏味:毕竟流程是死的。

看法的转变来自我个人网站的重构。前一版网站,组织混乱,没有统一的代码风格,网站能跑就假装没有 Bug。新一版网站,我加了很多流程:类型检查、代码格式化、单元测试等。的确,写的时候会有些拘束,比如测试覆盖度不达标不允许上线,但流程走完,人会很踏实。

我将其称之为:有约束的自由

当然,工程化能保证的只是下限,作为开发者,更重要地是思考,如何不断地突破自己,写出更加优雅健壮的代码,持续不断地交付给用户价值

工程化,说到底,只是工具。

(完)

参考

  1. 维基百科-标准作业流程🔗
  2. Understanding client-side web development tools🔗
在 GitHub 上编辑本页面

最后更新于: 2024-11-20T09:44:17+08:00