张耀春,滴滴公共前端团队负责人,2009年接触前端,5年多博客撰写经历。国内较早接触Node.js,2013年开始应用React、Angular、Polymer到业务组件中,2014年曾参与翻译《Professional Node.js》一书。最近探索和应用的新技术:rollup、riot、vue等,领导团队一起钻研新技术的书籍预计于今年8月底出版。
作为公司级的公共前端团队,应该如何对团队进行定位,在实践过程中应注意哪些问题,如何打造这样的团队?本文对滴滴公共前端团队的实践进行了总结,希望能带给读者一些启发。
>>>> 一、团队定位
1. 团队情况
滴滴公共前端(FE)团队现在有十多个小伙伴,男女比例为 1: 1。
主要包含以下几大职能方向:
H5运营富交互动画案例方向
WebApp和端交互方向
统一支付方向
公司通用类MIS业务前端研发和服务配置化方向
数据可视化和地图方向
公司级组件库建设方向
统一Nodejs服务(API、微服务、MIS等)
跨端体验方向
新技术孵化方向
团队职责:
全局:站得角度更高
公共:抽象得更通用性
孵化:新技术在新业务应用落地
2. 团队实践
作为公司级公共前端团队,滴滴公共FE团队的实践主要从以下几方面进行:
(1) 全局类:①公司统一权限登录移动化和PC改版;②移动端用户统一登录SDK。
(2)可视化方向:滴滴国内央视曝光10多次春运迁徙可视化。
(3) 组件化方向:公司级组件库——魔方。
(4)通用服务:①TMS运营和模板平台;②NPM Private。
(5)用户类:①微信等渠道内嵌的WebApp首页;②端内钱包支付等统一界面相关;③最近上线的安全行程分享;④H5前端服务化的项目:如滴滴捐献里程活动。
3. 团队努力方向
(1)努力成为公司业务线上的前端开发人员所信赖的伙伴、公司业务强有力支撑的前端技术团队。 (2)对前端业内有一定贡献的团队。
>>>> 二、团队的实践和产出
滴滴公共FE团队做的实践还是很多的,现列举几个比较重大且应用度广的实践。
1. 公司级组件库:魔方
(1)痛点
魔方主要为了解决的痛点是:每一个系统UI、交互规范、组件技术都不一样,复用性低,依赖第三方开源但技术支持不到位,遇到问题没人服务。
(2)途径
为了解决问题,我们通过以下途径,综合考虑,开发了魔方。
与公司设计团队和交互团队沟通,至上而下,统一UI视觉规范、交互规范。
与业务团队沟通应用技术,先优先大概率群体。
提供官网和24小时双VIP技术支持服务。
不光解决前端、放在更大的视角里面:客户端组件、视觉等。
(3)展示
以下是魔方的截图,可以通过这些截图,看到魔方所提供的主要服务。
(4)技术
魔方所用到的技术,包括以下几点:
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)
(5)魔方PC端构建流程
由于PC我们全部依托Angular指令来编写,在WebPack采用了ngtemplate-loader。
不同环境两套配置文件:
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-workingWebPack 动态加载:
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
(1)痛点
TMS为了解决的痛点如下:
前端修改上线尤为频繁、如何解决资源推送CDN、达到快速、高效、智能的上线流程 运营类H5 zip上传能否支持
如何快速Mock一个线上API配置
如何快速生成一个短链、二维码等
有一个图片,能不能快速生成一个H5页面
(2)途径
我们采取了以下途径:
搭建一个稳定、可扩展、权限可控、可监控的服务平台
支持多元化的服务调用:API调用和用户界面操作
和公司的基础架构及运维合作共赢
(3)技术
我们采用更定制化的Nodejs服务框架(从Sailsjs参考了很多)+mongo+pm2,结合公司发布系统、定制日志监控和脚本化运维规范。
(4)架构图
详细的架构如下图所示。
(5)遇到的技术问题
①如何灵活地进行线上线下配置
我们的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的配置参数。
②脚本化运维DNode服务:
整体我们还是依托公司的发布系统,设置后置脚本来部署和安装部分依赖。
build.sh --- 部分安装,配置等
control.sh --- 提供一些方法来控制服务,启动 pm2 的参数和日志路径等
* `./control.sh start`:启动服务,如果服务已经启动会报错。
* `./control.sh restart`:重启服务,要求服务已经启动才能正确执行。
* `./control.sh reload`:优雅重启服务,要求服务已经启动才能正确执行。
* `./control.sh stop`:停止服务③日志监控:
设置固定的日志,依托公司统一日志监控,设置拉取策略和一些采集匹配规则。
④如何处理不同类型的文件上传
在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化以及前后端分类
(1)痛点
随着业务发展,随之配套的各种MIS运营、管控、数据可视化系统,业务需求紧急、前端同学人力投入大、联调效率低。
前端同学依赖的构建工具和编辑器各异,有时候初始化开发环境都需要1~2天。
(2)途径:
与后端同学沟通数据接口规范、推行RESTFul API、沉淀业务组件库。
联调方式以Wiki为准、统一出处。
前后端独立分开部署、后端API通过跨域或者反向代理等方式通信。
成熟的Nodejs服务化:脚手架、配置化、生产测试环境隔离命令脚本化。
微服务化:权限、登录、邮件等微服务化或者SDK化。
(3)技术
Nodejs+数据存储+各种配置系统+脚本。
4. WebApp首页公共化
(1)痛点
滴滴早期WebApp首页是由业务线同学维护,与业务线有一定程度耦合,新业务线接入相对比较困难,会暂用业务线同学本身已有的开发任务。
(2)途径
与业务线研发和产品沟通、阅读代码,梳理逻辑和需求。
设计一套与业务线完全解耦的前端框架,业务线通过动态加载JS实现自身的业务逻辑。框架定义了业务线的生命周期,提供公共接口、通用组件库和统一样式供业务线调用,通过事件机制和业务线通讯。业务线可独立自主上线迭代,而不用公共的参与。
提供详细的接入wiki和24小时VIP技术支持服务。
(3)技术
scrat完成打包+构建。
gmu实现组件化。
前端模板handlebar。
combo服务。
5. H5 统一登录 SDK
(1)痛点
滴滴早期的登录每个业务线都会做一套,有开发成本。不利于账号部门收敛和管理各业务线账号,不利于做一些账号安全和组件升级;登录没有打通,新业务线或运营活动接入登录成本高。
(2)途径
账号与账号部门合作,输出公司级别的H5统一登录SDK,统一收敛和管理业务线账号,统一升级。
采用Facebook的统一登录方案,登录状态ticket缓存在passport域名下,打通滴滴各个域名的登录态。
业务线和运营活动页面接入只需引入一个JS,登录SDK提供login、logout、isLogin等接口,使用简单方便。
提供详细的接入wiki和24小时VIP技术支持服务。
(3)展示
(4)技术
原生JS,没有任何依赖。
WebPack打包+版本管理。
6. Npm Private
(1)痛点
前端项目越来越多,内部产出的工具包也比较多,如何自建一个私有库。
(2)途径
(3)技术
参考更多sinopia的一些优势、配置化和全局命令部署
申请存储容量稳定的机器作为部署机器
完备的官网和使用方法和场景问题
>>>> 三、如何打造公司级公共前端团队
这个问题其实我每天都在思考,好像一直没有太明确的答案,这里也只是分享一些我个人的见解:
技术氛围和培养机制
鼓励和提倡技术革新
沉淀和解决业务痛点
有规划、有目标、有理想
客服意识要强
下面我从几个方面具体来谈一谈。
1. 理想中的公共团队
团队永远和人有关系,下面我从几个简单的维度,通过我对几个游戏的理解来分享一下我认为公共团队的人所需要的气质。
(1)“飙车”
敢于超越,专业性要求高:赛车手和我们一般的开车的同学相比:更专业、对车子的熟悉度更高、追求超越和不愿意被超越。我很多时候推荐团建都是去玩室内卡丁车,而且每次都发现:有一些同学愿意最后和一些跑圈快的一组再比一轮,即使最后,那可能也是其他圈里面最快的。
(2)乐高拼图
能够沉浸在技术里面,去思考问题,最终产出:乐高一般有几千块零散的拼图、需要沉下心来、而且在脑海中大概有一个架子,不断地去尝试和调整,最终完成一个作品时候,你会很自豪。
(3)潜水
敢于挑战自己惧怕的东西,克服困难,战胜自己:潜水是我开始最惧怕的一项运动,很早前我不会游泳,但我又渴望翱翔大海,在一段比较长的震痛期后,我完成了浮浅和深浅,看到了很多常人看不到的美丽景色:大海龟、大鲸鲨、暴风鱼群等。
(4)写作和分享
沟通和沉淀才能让知识更记忆深刻:我自己喜欢翻译和写一写技术总结的文章,已经成为生活中一个不可或缺的习惯。然后再分享出来,得到一些批评和反馈。
2. Leader个人水平的提高
(1)制定计划
作为团队负责人,其实我的压力还是比较大的,除了满足业务需求外,你更多还需要告诉团队方向在哪里、我们的计划是否是可以落地的。所以我会制定一些计划来提高个人的水平。
一般我们会做半年计划:包含长远目标和最近目标。
管理上:参加了公司第一期的黄埔军校 - DMW管理培训以及很多管理相关课程学习。
技术上:一般我自己会保持比较高的阅读范围和一些国内外优秀的技术群,参加一些技术活动,例如以下几点。
每月一本的技术书籍。
定期向一些比较资深的前辈取取经。
参加一些业内比较知名的大会,比如最近的Qcon。
长期保持技术文章沉淀总结分享的习惯。
(2)如何更合理地提供解决方案?
我自身也折腾过各种机器和环境部署、数据库,也接触过后端和安卓开发,在研究跨端体验的时候,花了两个月看了iOS相关的基础书籍和代码。
很多时候解决方案的合理性和全局观,不只是你熟悉业务就可以了,我更倾向让团队的很多同学熟悉前端独立部署、如何和不同的端交互以及他们内部相关的技术组成。而且大部分时候不敢于技术革新的一个很大原因:不了解、不熟悉、没把握。
(3)如何高效地管理写代码和管理时间的分工?
很多时候时间确实是不够用的,而且有时候会参加很多会议和培训等。我管理时间一般的方式如下:
工具化管理:TODO LIST的软件+一些提醒。
技术获取:订阅list和pocket软件收藏。
3. 团队管理
(1)对内外的沟通
很多时候,我都会去找业务线的前端小伙伴包含一些Leader同学去交流沟通,看看他们的反馈和一些问题是否有公共的痛点。
组内定期沟通:保持每周部分同学的沟通、每周全组周会。
(2)代码 review 和风格一致性
很多人用过jira、我推荐Phabricator。
ESlint 等工具的工程化配置。
脚手架的统一但不失多元化。
(3)团队学习和应用的技术方向
团队技术的提高离不开学习和应用新技术,最近新技术的落地有以下几点:
Vue、riot H5 组件化推广
打包工具 WebPack --> rollup 迁移
代码化:babel + ES6
更多从业务中抽象的微服务
更多脚本化运维推广
编译器相关探索
跨端技术解决方案
(4)创造活跃的技术氛围
在很多时候,永远需要一个带头人跑的快一点,积极一点,在技术上鼓励创新和不断打磨沉淀优化,鼓励团队的小伙伴通过一些工具和技术手段来解决一些重复性的事情。
除了利用合理、稳定、高效的技术解决方案来服务日常的业务支撑外,考虑到前端技术的日新月异,我们也沉淀和创造一个统一的技术氛围:
公司比较早创办的DDFE的前端技术群
DDFE前端技术微信公众号
DDFE Weekly
DDFE Github blog
>>>> 四、致谢
公共FE团队在任何一个大公司都离不开业务线小伙伴的支持和厚爱、领导的认可和关注。
滴滴公共FE团队的发展,离不开所有给予我们帮助和信任的朋友,也离不开团队每一位亲爱的小伙伴的努力工作。
一路同行,只因为有你们:huangyi、wangjing、wangjin、suwei、shumei、xiaoqi、yanfen、miaodian、cuijing、yufei、huan总。
对滴滴前端技术感兴趣的同学,可以关注DDFE:
『前端之巅』群『滴滴公共FE团队技术开放月』分享活动预告:
第二期:WebApp实践经验分享;
第三期:公司级组件库以及MIS系统的技术实践分享。
参与『前端之巅-滴滴公共FE团队技术开放月』,请关注『前端之巅』公众号,回复“滴滴”。
长按二维码关注
前 端 之 巅
紧 跟 前 端 发 展
共 享 一 线 技 术
不 断 学 习 进 步
攀 登 前 端 之 巅