如何打造公司级公共前端团队
ustbhuangyi opened this issue · 10 comments
滴滴公共 FE 团队的实践和产出
1. 团队定位
(1)团队人数、职责
滴滴公共FE团队现在有十多个小伙伴,男女比例为 1: 1
。
主要包含以下几大职能方向:
- H5运营富交互动画案例方向
- WebApp和端交互方向
- 统一支付方向
- 公司通用类 MIS 业务前端研发和服务配置化方向
- 数据可视化和地图方向
- 公司级组件库建设方向
- 统一Nodejs服务(API、微服务、MIS等)
- 跨端体验方向
- 新技术孵化方向
团队职责:
- 全局:站得角度更高
- 公共:抽象得更通用性
- 孵化:新技术在新业务应用落地
(2)所做的事
简单先介绍对外的我们做的比较大的一些事情
全局类:
1、公司统一权限登录移动化和PC改版
2、移动端用户统一登录SDK
**可视化方向:**滴滴国内央视曝光10多次春运迁徙可视化。
**组件化方向:**公司级组件库 - 魔方。
通用服务:
1、TMS 运营和模板平台
2、NPM Private
用户类:
- 微信等渠道内嵌的WebApp 首页
- 端内钱包支付等统一界面相关
- 最近上线的安全行程分享
- H5前端服务化的项目:如滴滴捐献里程活动
(3)团队努力方向
- 公司业务线 FE 信赖的伙伴、公司业务强有力支撑的前端技术团队
- 对前端业内有一定贡献的团队
2. 团队的实践和产出
滴滴公共FE团队做的实践还是很多的,现列举几个比较重大且应用度广的实践。
(1)公司级组件库:魔方
痛点:
每一个系统UI、交互规范、组件技术都不一样,复用性低,依赖第三方开源但技术支持不到位,遇到问题没人服务。
途径:
- 与公司设计团队和交互团队沟通,自上而下,统一 UI 视觉规范、交互规范
- 与业务团队沟通应用技术,先优先大概率群体
- 提供官网和 24 小时双 VIP 技术支持服务
- 不光解决前端、放在更大的视角里面:客户端组件、视觉等
展示:
技术:
- PC 端:Angular + sass + webpack
- H5 端:
第一版:zepto + dmu(优化版的 gmu) + styl + handlebars + webpack
第二版:vue + webpack - 前端规范:
jsbridge: ES6 + (webpack || rollup) + babel
唤起app: 统一的中间页服务 + iframe 请求 schema - 数据可视化:canvas 类库封装 + 统一 theme + 上层配置化
- 地图可视化:底层适配高德和腾讯,采用动态打包(webpack + require.ensure)
关于魔方 PC 端构建流程介绍:
]由于 PC 我们全部依托 Angular 指令来编写,在 WebPack 采用了 ngtemplate-loader
不同环境 2 套配置文件:
webpack.config.js // 开发环境
webpack.min.js // 生产环境打包
区别:
//webpack.min.js
output: {
path: __dirname + '/dist/mofang-widget/' + version,
filename: '[name].min.js',
library: 'mofang',
libraryTarget: 'umd'
},
我们打包之后的目录:
dist/mofang-widget/0.1.1/mofang-widget.min.js
如何配置第三方依赖:
resolve: {
root: path.join(__dirname, 'src'),
alias: {
components: path.join(__dirname, 'src', 'components'),
vendor_a: path.join(__dirname, 'src', 'vendor'),
ui_bootstrap_a: path.join(__dirname, 'src', 'vendor', 'angular-ui-bootstrap'),
ui_select_a: path.join(__dirname, 'src', 'vendor', 'angular-ui-select'),
resource_a: path.join(__dirname, 'src', 'vendor', 'angular-resource'),
sanitize_a: path.join(__dirname, 'src', 'vendor', 'angular-sanitize')
}
}
如何处理 directory 里面的 template:
// 目录结构
components
didi-list
didi-list.html
didi-list.js
// bn-list.js
var templateListUrl = require('./bn-list.html');
// 指令代码:
{
templateUrl: templateListUrl
}
module: {
loaders: [
{
test: /\.html$/,
loader: 'ngtemplate!html'
}
]
}
如何按版本发布:
整体我们依赖 pkg.json 的 version:
var version = require('./package.json').version;
// 方案一:
plugins: [
new webpack.DefinePlugin({
__VERSION__: JSON.stringify(version)
})
]
// 方案二:
callbackLoader: {
getVersion: function () {
return "'" + version + "'";
}
}
关于 iOS 9 Safari iframe src with scheme not working:
具体可以参阅:
http://stackoverflow.com/questions/31891777/ios-9-safari-iframe-src-with-custom-url-scheme-not-working
Webpack 动态加载:
require.ensure([], function (require) {
var qqmap = require('./qq/qqmap');
callback && callback(qqmap);
}, 'qqmap');
require.ensure([], function (require) {
var alimap = require('./ali/alimap');
callback && callback(alimap);
}, 'alimap');
(2)公司级统一运营服务:TMS
痛点:
- 前端修改上线尤为频繁、如何解决资源推送 CDN、达到快速、高效、智能的上线流程
运营类 H5 zip 上传能否支持 - 如何快速 Mock 一个线上 API 配置
- 如何快速生成一个短链、二维码等
- 有一个图片,能不能快速生成一个 H5 页面
途径:
- 搭建一个稳定、可扩展、权限可控、可监控的服务平台
- 支持多元化的服务调用:API 调用和用户界面操作
- 和公司的基础架构及运维合作共赢
技术:
我们采用更定制化的Nodejs服务框架(从 Sailsjs 参考了很多) + mongo + pm2
结合公司发布系统、定制日志监控和脚本化运维规范
架构图:
遇到的技术问题:
1、如何灵活地进行线上线下配置
我们的 DNode 系统里面,默认支持 2 个配置文件
config/env/dev.js
config/env/prod.js
// config/env/dev.js
{
port: 1234
}
// config/env/prod.js
{
port: 8000
}
启动服务的时候,控制参数:
默认走的是 dev 的所有配置
dnode app.js --prod
这样默认就执行了所有 prod 的配置参数
2、脚本化运维 DNode 服务:
整体我们还是依托公司的发布系统,设置后置脚本来部署和安装部分依赖:
build.sh --- 部分安装,配置等
control.sh --- 提供一些方法来控制服务,启动 pm2 的参数和日志路径等
* `./control.sh start`:启动服务,如果服务已经启动会报错。
* `./control.sh restart`:重启服务,要求服务已经启动才能正确执行。
* `./control.sh reload`:优雅重启服务,要求服务已经启动才能正确执行。
* `./control.sh stop`:停止服务
日志监控:
设置固定的日志,依托公司统一日志监控,设置拉取策略和一些采集匹配规则
3、如何处理不同类型的文件上传?
在 DNode 里面我们所有的请求都会安装配置的 middleware 数组顺序,进行流转:
这样的优势:
我们可以在一开始设置一些 requestTimer 的监控 middleware
首先我们检查 request 头是:
if (req.is('multipart/form-data')) {
}
然后我们会通过 formidable
的 2 个方法:
var formObj = new formidable.IncomingForm({
uploadDir: uploadPath,
keepExtensions: true,
multiples: false
});
formObj.parse(req, function(err, fields, files) {
// 这里面我们可以 check file.type 来对不同类型的文件进行不一样的处理:
// 比如 css 文件:
if (files.file.type == 'text/css') {
minCssCode = new CleanCss().minify(cssCode).styles;
}
// 比如 js 文件:
if (files.file.type == 'text/javascript') {
minJsCode = UglifyJS.minify(jsCode, {fromString: true}).code;
}
// 比如 zip 文件:
if (files.file.type == 'application/zip' || files.file.type == 'application/octet-stream') {
}
}
如何限制体积:
我们这边采用的是 skipper
在 bodyParser 的 middleware 里面做了一次过滤。
(3)MIS 服务化、配置化、GUI 化以及前后端分类
痛点:
- 随着业务发展,随之配套的各种 MIS 运营、管控、数据可视化系统,业务需求紧急、前端同学人力投入大、联调效率低
- 前端同学依赖的构建工具和编辑器各异,有时候初始化开发环境都需要1-2天
途径:
- 与后端同学沟通数据接口规范、推行 RESTFul API、沉淀业务组件库
- 联调方式以 wiki 为准、统一出处
- 前后端独立分开部署、后端 API 通过跨域或者反向代理等方式通信
- 成熟的Nodejs服务化:脚手架、配置化、生产测试环境隔离命令脚本化
- 微服务化:权限、登录、邮件等微服务化或者 SDK 化
技术:
Nodejs + 数据存储 + 各种配置系统 + 脚本
(4)WebApp首页公共化
痛点:
滴滴早期WebApp首页是由业务线同学维护,与业务线有一定程度耦合,新业务线接入相对比较困难。
途径:
- 与业务线研发和产品沟通、阅读代码,梳理逻辑和需求。
- 设计一套与业务线完全解耦的前端框架,业务线通过动态加载 JS 实现自身的业务逻辑。框架定义了业务线的生命周期,提供公共接口、通用组件库和统一样式供业务线调用,通过事件机制和业务线通讯。业务线可独立自主上线迭代,而不用公共的参与。
- 提供详细的接入wiki和 24 小时 VIP 技术支持服务。
技术:
- scrat完成打包+构建。
- gmu实现组件化。
- 前端模板handlebar。
- combo服务。
(5)H5 统一登录 SDK
痛点:
滴滴早期的登录每个业务线都会做一套,有开发成本。不利于账号部门收敛和管理各业务线账号,不利于做一些账号安全和组件升级;登录没有打通,新业务线或运营活动接入登录成本高。
途径:
- 账号与账号部门合作,输出公司级别的H5统一登录SDK,统一收敛和管理业务线账号,统一升级。
- 采用Facebook的统一登录方案,登录状态ticket缓存在passport域名下,打通滴滴各个域名的登录态。
- 业务线和运营活动页面接入只需引入一个JS,登录SDK提供login、logout、isLogin等接口,使用简单方便。
- 提供详细的接入wiki和 24 小时 VIP 技术支持服务。
展示:
技术:
- 原生js,没有任何依赖。
- WebPack打包+版本管理。
(6)Npm Private
痛点:
前端项目越来越多,内部产出的工具包也比较多,如何自建一个私有库。
途径:
- 调研市面的解决方案
- 定制化滴滴特色的解决方案
技术:
- 参考更多 sinopia 的一些优势、配置化和全局命令部署
- 申请存储容量稳定的机器作为部署机器
- 完备的官网和使用方法和场景问题
3. 团队学习和应用的技术方向
最近新技术的落地:
- vue、riot H5 组件化推广
- 打包工具 webpack --> rollup 迁移
- 代码化:babel + ES6
- 更多从业务中抽象的微服务
- 更多脚本化运维推广
- 编译器相关探索
- 跨端技术解决方案
4. 如何打造公司级公共前端团队
这个问题其实我每天都在思考,好像一直没有太明确的答案,这里也只是分享一些我个人的见解:
- 技术氛围和培养机制
- 鼓励和提倡技术革新
- 沉淀和解决业务痛点
- 有规划、有目标、有理想
- 客服意识要强
下面我从几个方面具体来谈一谈。
(1)理想中的公共团队
团队永远和人有关系,下面我从几个简单的维度,通过我对几个游戏的理解来分享一下我认为公共团队的人所需要的气质。
1.“飙车”
**敢于超越,专业性要求高:**赛车手和我们一般的开车的同学相比:更专业、对车子的熟悉度更高、追求超越和不愿意被超越。我很多时候推荐团建都是去玩室内卡丁车,而且每次都发现:有一些同学愿意最后和一些跑圈快的一组再比一轮,即使最后,那可能也是其他圈里面最快的。
2.乐高拼图
**能够沉浸在技术里面,去思考问题,最终产出:**乐高一般有几千块零散的拼图、需要沉下心来、而且在脑海中大概有一个架子,不断地去尝试和调整,最终完成一个作品时候,你会很自豪。
3.潜水
**敢于挑战自己惧怕的东西,克服困难,战胜自己:**潜水是我开始最惧怕的一项运动,很早前我不会游泳,但我又渴望翱翔大海,在一段比较长的震痛期后,我完成了浮浅和深浅,看到了很多常人看不到的美丽景色:大海龟、大鲸鲨、暴风鱼群等。
4.写作&分享
**沟通和沉淀才能让知识更记忆深刻:**我自己喜欢翻译和写一写技术总结的文章,已经成为生活中一个不可或缺的习惯。然后再分享出来,得到一些批评和反馈。
(2)Leader个人水平的提高
作为公共团队的 FE Leader,其实我的压力还是比较大的,除了满足业务需求外,你更多还需要告诉团队方向在哪里、我们的计划是否是可以落地的。
- 一般我们会做半年计划:包含长远目标和最近 Q 的目标
- 管理上:参加了公司第一期的黄埔军校 - DMW管理培训以及很多管理相关课程学习
- 技术上:一般我自己会保持比较高的阅读范围和一些国内外优秀的技术群
1、每月一本的技术书籍
2、定期也会和一些比较资深的前辈取取经
3、参加一些业内比较知名的大会,比如最近的Qcon
4、长期保持技术文章沉淀总结分享的习惯
如何更合理地提供解决方案?
我自身也折腾过各种机器和环境部署、数据库,也接触过后端和安卓开发,在研究跨端体验的时候,花了 2 个月看了 iOS 相关的基础书籍和代码。
很多时候解决方案的合理性和全局观,不只是你熟悉业务就可以了,我更倾向让团队的很多同学熟悉前端独立部署、如何和不同的端交互以及他们内部相关的技术组成。而且大部分时候不敢于技术革新的一个很大原因:不了解、不熟悉、没把握。
如何高效地管理写代码和管理时间的分工?
很多时候时间确实是不够用的,而且有时候会参加很多会议和培训等。我管理时间一般的方式如下:
- 工具化管理:TODO LIST的软件 + 一些提醒
- 技术获取:订阅 list 和 pocket 软件收藏
- 一般下午或者晚上会比较晚一点以及周日有时候带着家里或者公司
(3)团队管理
对内外的沟通
- 很多时候,我都会去找业务线的前端小伙伴包含一些 leader 同学去交流沟通,看看他们的反馈和一些问题是否有公共的痛点
- 组内定期沟通:保持每周部分同学的沟通、每周全组周会
代码 review 和风格一致性
- 很多人用过 jira、我推荐 Phabricator
- ESlint 等工具的工程化配置
- 脚手架的统一但不失多元化
创造活跃的技术范
在很多时候,永远需要一个带头人跑的快一点,积极一点,在技术上鼓励创新和不断打磨沉淀优化,鼓励团队的小伙伴通过一些工具和技术手段来解决一些重复性的事情。
除了利用合理、稳定、高效
的技术解决方案来服务日常的业务支撑外,考虑到前端技术的日新月异,我们也沉淀和创造一个统一的技术氛围:
- 公司比较早创办的 DDFE 的前端技术群
- DDFE 前端技术微信公众号
- DDFE Weekly
- DDFE Github blog
5.致谢
公共 FE 团队在任何一个大公司都离不开业务线小伙伴的支持和厚爱,领导的认可和关注。
要感谢的人很多,有很多可能我自己都叫不上名字,不管怎样,真心感谢所有帮助过以及信任着公共 FE 团队的同学,
同样地也再次特别感谢我们团队的每一个亲爱的小伙伴。
一路同行,只因为有你们:huangyi、wangjing、wangjin、suwei、shumei、xiaoqi、yanfen、miaodian、cuijing、yufei、huan总
👍
👍
👍
👍
👍
a misspelled: 至上而下
应为 自上而下
😊
ESlint工具配置有哪些规则可以详细说下吗?@ustbhuangyi
@xianyuxmu
已修改,感谢反馈~
👍