买好车团队中的 Node.js 实践
买好车团队中的 Node.js 实践
前天,我们公司前端团队的几个人一起去大搜车参加了芋头所组织的「搜车 Node Party」。这是我第一次参加与 Node.js 相关的线下聚会,如果不算「杭 JS」的话。
这次聚会的主题全部是与大搜车现行的业务和技术挂钩的:芋头讲述了团队中 Node.js 的技术演进及未来展望;死月分析了几个常用 ORM 的特点并安利了自己的作品; Plusman 分享了日志监控方案和实践。(相关演示文稿可以到芋头所写的总结中下载)
整场下来,虽说没有醍醐灌顶,但对我们团队接下来要做的事情还是比较有借鉴意义的。另外,这场聚会给了我很多信心,让我觉得等我们积累些经验之后,也可以总结出来与其他公司的人分享交流一下。
在这里,我先简单说说我们团队使用 Node.js 的一些场景。若能从头到尾认真地读下去,会了解到我们的技术演进和发展方向。
前端工程化
Node.js 从问世开始,已经渐渐成为前端工程师的必备技能,开发中或多或少都会用到它。虽然不是很重,但我们在团队中也有用到 Node.js ,主要是使用命令行工具处理前端工程问题。
刚来公司时,业务重心还在 B2C 的平行进口车交易网站「买好车」上,前端团队的工作主要就是新功能开发和修修补补,还有就是铺天盖地的活动页。
当时有两个 Git 仓库:一个是 Java 的全栈式框架 Webx ,主站的 HTML 代码都是用 Velocity 模版写的;另一个是所有项目的页面所用到的 CSS 、 JS 和图片等静态资源文件。
项目中前端工程问题比较严重,开发舒适度和效率都比较低。
网络代理
正因为静态资源文件与后端框架相隔离,在开发时无法通过本地文件的相对路径进行引用。我们利用 LivePool 将模板中引用静态资源文件的 URL 代理到本地文件来调试。
这种方式不仅用来支撑日常的项目开发,还用于调试线上 bug 。能够方便、快速地解决线上问题固然使人愉悦,但开发时就麻烦得让人蛋疼了。
每新增一个文件就要先上传到测试服务器才能映射到本地,每修改一点代码就要新开一个终端窗口运行 livepool
……你手指麻不?你不麻?我麻!
活动页面
想当年,活动页真是多到数不胜数,每个活动要做桌面版和移动版两份,有时一天要做两个活动,加起来就是四个页面。
做来做去,活动页的代码有很多地方是一样的,虽说是时效性很高的页面,但总复制粘贴也不是个办法。码农是最讨厌做重复无意义且没挑战性的事情的一种生物,所以他们会想方设法去把那部分自动化处理,解放自己!
为了让双手不那么麻,工头基于 Yeoman 开发了一个活动页的脚手架「generator-mhc-activity」。在我对它进行优化处理之后,只需在终端中敲入简单的命令就能生成桌面端和移动端两个版本的活动页面框架。
自动构建
构建工具在我来的时候就已经有了,用的是 Gulp 。那时只是用来合并、压缩文件,并没有充分发挥它的作用;并且源码都是用标准语言编写的,也无法让它展现出其他价值。
随着公司将重心转移到针对商家的 B2B 业务的「卖好车」,我们有机会尝试引入新的开发方式以提高舒适度和效率。
在新的项目中,分别采用 Sass 和 ES6 编写样式和脚本,连同图片文件一起与后端框架放在同一个 Git 仓库;使用 FIS3 把它们编译成标准语言,并在部署时合并、压缩文件以及进行为文件加指纹等操作。
图片上传
项目里的图片等静态资源文件是存储在 CDN 上的,发布前会用工头写的 Node.js 脚本把那些新增和改动的文件上传上去。
当时脚本写得比较简陋,既没有配置文件又不能传入变量,每次都要手动去把需要上传的文件拷贝出来放到同一个目录下,把脚本中的路径修改为那个目录才能够上传,麻烦至极!并且没有做容灾处理,只能上传到七牛,它的生死存亡直接影响到我们……不幸的是,已经经历过两次这种事情了!
后来,我在原有的基础上做了很多优化,形成一个可配置、支持多个 CDN 的功能较为完善的上传工具——RocketZ。与 FIS3 配合,可以在七牛再抽风时轻轻松把静态资源文件切换到顽兔的备份。
团队定制
当使用的工具多了,就希望有一个工具能够替代它们,也就是包含它们所有的功能。要做到这点,就得根据团队的需求造一个轮子出来。我觉得每个前端团队都需要这么一个专属于自己的轮子,「Bumblebee」就是为此而生。
Bumblebee 的实质就是一个容器,把 yeoman-environment ( Yeoman 的底层)和 RocketZ 包装起来通过子命令调用。只用这一个工具就能使用脚手架和上传图片的功能,既使用简单又减少了记忆、管理等成本,何乐而不为呢?
接下来还想加入安装插件和构建等功能,前提是有时间和精力……
前后端分离
到 5 月份时,请拓爷(花名文拓, Java 架构师)新开了一个项目,用于在现有项目基础上基于 Node.js 做一些事情。
起初,这个项目到底要用来干嘛,并没有很明确的想法。想过用来渲染无动态数据的页面,也想过完全替代 Java ,但想来想去都不太靠谱,最后决定用来做前后端分离。然而,出于种种原因且当时也不算是刚需,只搭了个架子就搁置在那了。时隔两个多月,它的重要性日渐突出,决定捡起来好好做下去!
我对不起组织,请狠狠地鞭笞我……
是什么?
「前后端分离」这个概念网上有很多文章描述,用我的话来简单概括就是:「前端」和「后端」并不应该用设备、平台来划分,而应以关注点和职责来划分——与人机交互及数据展现相关的都算是「前端」,即 Controller 层和 View 层;与业务逻辑及数据存储相关的都算是「后端」,即 Model 层。
前端工程师的本职就是将数据展示在页面上并提供给用户极佳的体验,与其他客户端应用工程师几乎是一样儿一样儿的。所以,进行前后端分离恰恰是将原本应该由前端工程师去做的事情归还了回来——职责回归。
为什么?
在传统的 web 开发模式中,「前端」仅仅是指 MVC 架构模式中的 View 层。在这种模式下,前端的开发和发布进度被后端框架所牵制,感觉像被奴役了一样。每次在仅仅是修改一点点样式或文案还得等后端人员去发布时,心里就会默默地在唱——
起来!不愿做奴隶的人们!
与后端框架耦合在一起,开发效率低且沟通成本高,页面变更的发布缓慢,对于开发和运营来说都不友好。另一方面,简单修改的发布在运营童鞋眼里看来就应该是分分钟的事儿,如果非要拖到晚上等着跟后端一起发布,他们会觉得我们前端工程师「真没用」!
无论从哪方面说,将前端的开发和发布流程独立出来势在必行!
怎么做?
关于怎么去进行分离,简单说来,就是通过 API 将前、后端这两个独立的个体连接起来——后端专注于业务逻辑,将需要展现的数据通过 API 输出;前端专注于数据呈现,通过 API 输入和获取数据。
然而,实际的系统架构和环境较为复杂,实现起来也许没有想象中那么简单,并且不仅要考虑如何去开发,还要考虑如何去测试和部署发布的问题。
目前所想到的需要解决的问题有:同时访问 Java 框架和 Node.js 框架中的页面以及将 Java 框架中的页面平滑迁移到 Node.js 框架中去;在不同环境中对数据的读写操作;集成进内部的一键部署发布系统。
关于我们团队在前后端分离实践方面更多具体的事情请关注今后的文章~ ;-)
不算题外话的话
最近想用 Node.js 做很多事情,如智能家庭系统啦,公司内部的资源信息管理系统啦,还有通过微信机器人控制智能硬件啦……
想法总是源源不断的,就是没什么时间和精力去实施,就等着哪天突然打鸡血了吧!
另外,我觉得过些年「前端工程师」这个职业会消失。
我觉得过些年「前端工程师」这个职业会消失。
===================================
为什么?
土总威武
融了挺多钱的,但流量不高呀,
PR 仍需努力
土总威武
土总霸气
买好车,是不是国内那家做卖车最屌的公司?
这种进口车售后怎么办?
土总威武(我的第一个评论被吃了??
it’s a feature,not a bug
我说的是指那种纯浏览器端的前端工程师,未来的前端工程师就应该像客户端工程师一样。
销售方面的事情我就不懂了。
感觉像是为了圈地盘而做一件事情,方案还是根据业务场景和手上资源来决定
销售方面的事情我就不懂了。
看到了熟悉的名字
确实是存在一些问题需要改善
好赞的文章
据说你们公司的前端水平不错,我是想说,能不能帮忙内推一下。。。
嗯,后来发现了,只是被折叠了,回复数量还是没变
土总威武
你想加入吗?可以啊~
= = 感觉工具链比我这边还不完善。。
前后端分离很有必要,不然发布很蛋疼,不可能前端更改点东西,就要后端一起发布。
考虑前后端分离的时候,最好也考虑下发布分离。
是的,之前无论是前端团队还是整个技术团队都存在很多问题,但经过大家的努力已经改善很多。
发布分离是必须的,这也是要进行前后端分离的主要原因。
我正在探索从开发、调试到部署的一整套方案。过后我会将实践经验总结一下放出来,如果有兴趣的话请关注~
嘿嘿 胡斐人挺仗义的!
前后端分离之后,开发、调试可以分不同环境来搞
本地环境,可以弄一套 mock 服务,接口代理到 mock 服务器,这样前端可以先定义好接口,后端根据接口开发,前端的开发就不受后端依赖了。
测试环境,后端接口提供本地 mock 的数据就好了。
等你的实践方案分享。
不要想太多。
简单讲就是面向 API
在买好车团队的Node.js实践中,我们充分利用了Node.js的高性能、异步I/O和非阻塞事件驱动的特性,以构建高效、可扩展的后端服务。以下是我们的一些关键实践:
-
模块化设计: 我们采用CommonJS规范进行模块化设计,使得代码更加清晰、易于维护。例如:
// userModule.js module.exports = { getUserById: function(id) { // 获取用户信息的逻辑 } };
-
Express框架: 使用Express框架构建API服务,通过中间件机制处理请求和响应,提高开发效率。
const express = require('express'); const app = express(); app.get('/users/:id', (req, res) => { const userId = req.params.id; // 调用userModule获取用户信息并返回 }); app.listen(3000, () => { console.log('Server is running on port 3000'); });
-
数据库交互: 使用Mongoose与MongoDB进行交互,实现数据模型的定义和数据库操作。
const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/buygoodcar'); const UserSchema = new mongoose.Schema({ name: String, email: String }); const User = mongoose.model('User', UserSchema);
-
性能优化: 利用Node.js的Cluster模块实现多核CPU的利用,通过PM2等工具进行进程管理,提高服务的稳定性和性能。
总之,买好车团队在Node.js实践中,通过模块化设计、Express框架、Mongoose以及性能优化等措施,构建了高效、可扩展的后端服务。