【第1582期】为什么 Node 是小菜前端团队的核心技术栈
前言
为业务赋能,把盘子做大。今日早读文章由宋小菜@Scott授权分享。
正文从这开始~~
任何可以用 JavaScript 来写的应用,最终都将用 JavaScript 来写。 — 阿特伍德定律
这篇文章向大家介绍下小菜前端的基建在一步步走过来的过程中,NodeJS 是如何使用的及扮演了哪些角色,它对于工程师个人,团队能力,公司研发效率,业务支撑,技术的探索与突破等等到底有什么实际的意义,以及为什么是它而不是 Python/C++/PHP/Java 成为了前端团队的核心技术栈。
被 NodeJS 加速的框架演进速度
2019 年的前端与 2009 年的前端早已是君住长江头我住长江尾,短短十年,人是物非,React/Vue 一统天下,Webpack 标配江湖,单纯看近 2 年的 【Npm Trends】:
或者参考近 10 年的【Google Trends】:
热度一定程度反映了社区活跃,和占用市场的体量,可以发现 AngularJS 也是经历了过山车,市场被 React/Vue 不断侵蚀,那再把 jQuery 加进来看下:
令人瞠目结舌,即便 React/Vue(绿色和紫色) 如日中天的今天,在整个网络的搜索热度上,也远远低于 jQuery 和 NodeJS,尤其是 jQuery,虽然它的热度在持续降低,但依然是整个互联网中不能忽视的重要组成部分,
虽然早期与 jQuery 同时代还有很多其他框架类库,比如 ExtJS/Mooltools/Dojo/Yui/Kissy 等等等等,但它们的体量比起 jQuery 都差之甚远不再比较,如果大家把近十年听到的看到的框架罗列起来,几十上百都不成问题,生命周期能超过 5 年却寥寥无几,尤其是在 2012 年 NodeJS 在全球推广到一定规模后,框架的诞生迭代替换更为快速,所以从框架的生命力来看,jQuery 目前为止依然是赢家,那它跟 NodeJS 有什么关系呢?
NodeJS 的持续变热,jQuery 也在持续走冷,一部分原因就是 NodeJS 生态基建能力,在之上不断的生长出来新的框架与解决方案(不限于 AngularJS/React/Vue),也在不断的蚕食 jQuery 的市场,倘若没有 NodeJS,自然也不可能有新框架的繁荣之态,今天大有可能依然是 jQuery 在一统江湖。
在今天,无论是 Angular/React/Vue/Webpack,从开发体验、单元测试到打包编译,脱离了 NodeJS 生态,都无法正常运转,NodeJS 就是整个上层建筑的物理基础和配套设施,我们从宏观上了解了 NodeJS 对于前端框架进化和保障的重要性。
接下来,就结合小菜前端在 NodeJS 上的建设与大家聊聊它的重要性,2 年来,我们重度使用 NodeJS 陆续参与了十几个重要的工具/产品/系统的建设,下面挑选四个有代表性的分享给大家:
小菜前端第一次尝鲜 NodeJS - APP 热更新服务
写一些 NodeJS 自动化脚本,代码校验甚至利用 Express/Koa 搭建一些简单的服务,这些都不能算做真正意义使用 NodeJS,我们也抛开 ReactNative/Webpack 等前端开发打包编译需要依赖 NodeJS 这样的场景,我们第一次真正意义使用 NodeJS, 就是对 ReactNative APP 开发的热更新系统,代号神奇博士,服务端框架用的 ThinkJS 框架,那时候是 2016 年中,Scott 还没有入职小菜。
这样一个热更新发布系统可以让客户端 APP 动态更新到增量的代码包,最原始的更新流程如下图:
在热更新系统中,需要针对 iOS/Android 的 IPA/APK 包进行特定操作系统的资源拆包,增量包/原生包存储,包版本管理,权限管理等功能,这些事情是不太可能让服务端童鞋比如 Java 童鞋替你做的,只能前端自己做,也只能用 NodeJS 才能快速的开发出来。
系统上线后,整个公司的 App 发版频率从一个月一两次(审核还会被打回)提升到一周三四次,效率至少提升 10 倍,而且用户的更新体验得到质的提升,对于业务/运营/产品/用户都有极大的价值。
这时候我们概念里面的 NodeJS 可能更像是一个特定场景的功能玩具,并没有深挖它的重要性和可能性,虽然尝到了甜头,但往后的一年多没有再持续挖掘。
小菜前端第二次尝鲜 NodeJS - APP 打包平台
Scott 是从 2011 年开始接触和使用 NodeJS,从 2013 年后技术栈以 NodeJS 为主,开始尝试搭建比较复杂的系统,非常清楚它的优势和短板,在 2017 年下半年开始带前端团队的时候,收到了很多的反馈和投诉,主要分为两类: APP 更新失败的问题(在非常高的迭代节奏下) 和前后端协作的接口/联调问题,针对 APP 更新下失败的问题,我们先来还原下当时的开发状态,大家如果也有多人协作 RN APP 的开发,可以参考接下来我们的做法,相信对你有用。
我们的 APP 当时一共有 5 个 - 宋小菜(对外)、宋小菜司机(对外)、宋小菜供应商(对外),宋小福(对内)、采秘(对内),所有的 APP 都是 RN 开发,都有 iOS/Android 两个版本,其中对外的是商业开发版本,要发布到苹果商店和推送到特定渠道,对内的都是企业包,不对外公开,我们通过公司自己的网站托管应用供员工安装。
这些 APP 之间的业务也有一定的联系,通常开发宋小菜,也会联动要修改宋小福或者采秘,在本地开发的时候,需要在每个包里面,区分连接的是日常测试环境,还是线上生产环境,还要区分是可以打印出日志的 debug 包,还是非 debug 包,并且最终上线前,再由每个同学在本地 Mac 上打出一个包上传到热更新平台,这个流程里面会出现大量问题,我曾经画了这样一张图给服务端的同学解释为什么前端打包 APP 到上线会经常出问题:
这样就会有很多组合,有的包是要频繁打的,有的偶尔来几发,打包的时候要区分:
是哪一个 APP
是打 iOS 还是 Android 的包
是正式环境,还是日常测试环境
打的包要不要开启热更新功能,不开启就不会走线上热更新流程
这个包要不要实时连到本地打一些 log 出来,也就是是否 Debug
是在哪个同学电脑上打的包
这样硬组合就可以打出 64 个不同的包,意味着可能需要把配置文件修改 64 次,另外,每个同学电脑上的 Mac 操作系统版本会有不同,XCode/Gradle 也可能版本不同,更不用说 Node 以及 NPM 所安装的三方包,甚至本地预装的开发者证书也时有不一致的情况,于是整个团队陷在了打包/包正确性/一致性/是否能打出来一堆问题形成的泥坑里,艰难的对外解释,艰难的互相配合,针对这个问题,我们思路是让这一切可以傻瓜一点自动化,让团队共用一个打包环境,以它打的包为准,于是我们启动了大伯伯打包平台,采购了一台高配 Mac Mini 部署在内网,把所有的配置项都通过界面来管理,简要流程如下:
界面一开始很朴素,长这个样子:
这个系统上线 1 年来,我们已经打了 1000 多个包,因为打包而出现环境错误问题 0 次,极大的解放了团队效率和提升打包的正确性,更重要的是对于团队也沉淀了一些基于 Node 使用的技能,坚定了大家使用它的信心:
小菜前端第三次尝鲜 NodeJS - 报表快速制作平台
无论是 toB 还是 toC 公司,把数据库里的数据拎出来,无论直接导出为 Excel,还是通过接口输出到前端页面中展示,都是硬刚需,小菜也不例外,而且小菜的业务早些年变化特别高频,每次变化都要提一堆报表需求来监控调整前后的业务变化是否符合预期,如果没有了报表就跟算命一样全靠猜,然后这样一个普通不能再普通的需求,却让小菜整个产品技术团队头疼了好几年。
在紧张的业务开发项目中,让前后端各自抽出资源来对接一个个的报表字段,再通过接口 - 页面的联调和发布,是一件非常浪费资源的事情,后端感觉自己像是一个写 SQL 的和接口胶水代码的,前端感觉自己就是个纯粹 Table 报表页面仔,而且经常资源交叉冲突导致报表优先级降低甚至拖很久不能给到业务方,所以公司做了整整 3 年,总共才产出了 50 多个报表零散的扔在 ERP 系统里面,针对这个问题,前端启动了一个项目 - 大表哥报表平台,用来解决报表产出效率的问题,实现 SQL 到页面的自动生成,后端工程师,甚至会 SQL 的产品经理和运营都可以到平台上,按照约定的规则粘贴一些 SQL,或者基于编辑页面组装一些 SQL 的子语句,咔咔!报表生成,这个系统上线 1 年来,生产力一下子得到释放,总共产出了 400 多张报表:
公司的员工浏览报表每天都有一两千次,直接导出 Excel 就导出了 1 万 6 千多次,已经是公司内部最成功的一个工具产品,服务于全公司所有部门,报表展示大概长这样:
一个报表的制作界面大概长这样:
通过对 SQL 的各种查询词的组件封装,可以从界面快速生成一个可在数据库执行的复杂 SQL 语句,或者反向贴入符合规则的 SQL,自动拆解成报表的表头(字段的中文名称),自动映射到组件(日期、排序、筛选、二级跳转的子报表等等),包括整个报表的需求提出、描述、认领、上下线、制作和发布这样的工作流等等也全部用 NodeJS 实现,这次尝鲜不仅奠定了 NodeJS 在前端团队绝对的位置,也实质性的在支撑业务这里拿到很好的结果,更让我们感到欣喜的是,在报表系统里面使用 GraphQL 是多么的便捷,同时前端部门独立支撑数据相关的业务产品这条路变得可行,NodeJS 的角色从工具也延展到了业务。
小菜前端第四次尝鲜 NodeJS - 前后端数据聚合服务
如果说前面几个,都是与服务端团队解耦的,是前端可以独立完成的,那么这一次,则是跟服务端在职能上和系统上都有强耦合的地方,是跨团队研发层面的尝试,这次发生在 2018 年 2 月份,也就是在前两次尝鲜后,我们又一次比较大胆的突破。
背景依然是前端的页面与后端的接口这里,关于这个后面会专门有一篇详细与大家聊聊前后端合作研发上我们的思考,这里我简述一下,前后端的合作方式通常是数据接口,也就是数据格式和字段约定,一个吐数据一个消费数据,吐什么样的数据取决于消费什么样的数据,消费的数据则来源于产品流程上的 UI 展示形式,一份概念里统一的数据,是有可能被分拆成两个 UI 块展示和复用,可能会让接口颗粒度更小拆成 2 个,或者共用一个大的,频次高一些的 UI 改版也会导致接口的通用性变得很弱,最终产生一堆大而全的重体积接口,进而对前端维护页面和用户的加载产生较大的影响。
而且接口里面永远是黑盒,在前端是看不全接口的能力了,一旦文档没有跟上,接口的输出与 UI 的使用便会脱节,为产品运行的带来了更强的不稳定性,所以我们会希望接口都是纯粹的,用到多少字段就输出多少字段,用到什么格式就输出什么格式,同一个页面的数据,尽量一个接口返回而不是三四个接口返回,但这显然对服务端提出了更高的要求,也是很多公司从前端产品层面试图推动后端团队时候无功而返的最大阻力。一个人群中,大部分人都倾向于不作出改变,在没有看到太多对自己带来的好处之前,而短期成本与长期红利之间大部分会选择短期,因为它容易预见。
我们的解决办法是,用 NodeJS(EggJS) + GraphQL 搭建一个系统,它负责三件事:
负责对前端输出所需数据(单接口,要什么给什么,无冗余可组合)
负责去拿所有的服务端微服务接口数据(HTTP 协议或者 RPC 协议)
提供一个可以在线连接接口、约束字段以及实时 Mock 的编辑系统
对它的要求是可在线编辑,可联调测试,可数据热发布与热回滚,这个系统上线后,我们接管了 2 款 App 的接口需求,前端拼装页面和组合数据时候变得更灵活自如,同时正向逆向的数据监控,让我们对数据更有把控力,对于服务端来说,也可以更加不关注 UI 如何,更关注业务领域的搭建与标准数据接口的封装,它的界面长这个样子:
还有接口地图、数据关系网络、接口字段监控、Mock 系统等等不再一一截图,这个 NodeJS 搭建的系统的复杂度还是蛮高的,上线后我们专门组织了一场技术分享 - 杭州第一届 GraphQLParty,让它开源的群众呼声很高,我们觉得还需要更多 NodeJS 的专家进来把系统进一步完善后,才真正能达到开源的标准,目前依然是在公司内部使用。
综上,小菜前端基于 NodeJS 既有 Eat Your Own Shit 的内部场景的问题解决,也有直接服务于前端产品的工具,也有直接把数据当做业务来支撑公司决策的业务产品,还有专注在前后端研发效率的数据聚合层的全方位尝试,从内到外从前到后,而这些系统的尝试,又为前端团队沉淀了非常多的服务端能力,系统设计能力,甚至带来跨语言栈的变化,童鞋们的技术能力也都大幅提升,所以 NodeJS 越来越成为前端团队的核心技术栈,目前第五次大规模的 NodeJS 使用我们聚焦的是运维健康体系的搭建,相信在你的团队,基于它做深度使用,只要能贴合你团队的痛点,公司业务的痛点,解决掉问题带来价值,那么这些尝试或者说试错都是值得肯定和鼓励的。
关于本文
作者:@Scott
原文:https://juejin.im/post/5ca321f76fb9a05e5d09bb8a
最后,他曾分享过
【第684期@同说】let_Scott :4 年前端狗,2 年 CTO
【第1315期】GraphQL 基于 SPA 架构的工程实践