「时光不负,创作不停,本文正在参加2022年中总结征文大赛」
首先自我介绍,本人花名三桥,前阿里前端技术专家,作为TL带前端团队已经有5年以上经验,带过至少5个不同前端团队。
本人目前在某在线教育公司,作为一名前端TL,深深感受到双减政策带来问题非常多,不过无论大环境如何变化,作为前端人,我们的关注点应该是自身的成长。
接下来,我总结一下2022年上半年我对团队的年中总结,重点围绕前端新业务落地对于效率、质量、协助的思考,以及如何通过前端技术栈解决业务问题。
因外部变化而调整
2021年是整个在线教育行业的转折点,无论是业务、团队、还是个人,都有极大的变化和调整。
双减政策的实施,注定了公司的业务需要调整,作为前端团队同样也要调整和优化。
最明显的变化有几点:
- 业务战线收缩,由以前大范围无限制的营销推广,变成有限的低成本转介绍。
- 人员收缩,注定有些人留下继续奋斗支持公司,有些人因为调整带来不同程度的心情。不过,我一直认为,只要你有足够的优秀,去哪里都能发挥你的能力。
- 团队调整,原本我负责的团队只是负责其中一个业务,逐渐变成负责全公司80%的前端业务。团队职能变化注定每个人负责的事情会更多,同时也都要学会承担更多的责任。
团队职责的变化
双减后的第一年,公司进行了各种各样的优化,作为研发技术的其中一个团队,同样也要跟着公司的业务发展进行。
团队的责任变化
前端团队经过调整后,承担的责任就更大了,主要包括3个方面:
- 交接多个不同领域的前端项目,前前后后至少50+个,包括中后台项目、PC端项目、C端H5项目等等。团队每一个成员都要具备快速熟悉业务和了解项目流程,对团队来说是个不小的挑战。
- 团队人数不变,但业务更多。这样的事情对于团队每个人来说,需要更多的沟通和协调能力,甚至是Owner的能力,不再是单纯的做个页面,调下接口等常规的事情。
- 团队承担着公司接近80%的前端项目,作为TL的我就不能用小团队思维去管理,需要从全局的角度思考团队如何更高效和高质量的交付项目。
团队的使命
所以,我给团队在2022年的上半年制定了一个使命:
跟着组织走,提高项目质量
团队的优先级调整
同时,在上半年业务和产品计划做两条新的业务线,第一是整合现有的业务,主推海外市场;第二是营销新中台。
在过去,公司很多老业务,都是基于传统的纯Vue技术栈来满足业务需求,往往上线后项目质量不高,又或者代码质量不高,给团队后续维护带来很多的问题。
为避免重复历史的坑,刚好上半年也只有新业务需求不多,作为前端TL的我,我们团队就以高质量交付作为目标去完成这样的新业务。
所以团队接下来对于业务需求的优先级定义如下
营销新中台 > 新C端整合业务 > 学科业务 > 基础支撑业务 > 技术优化
新业务落地
上半年,团队的新业务主要围绕整合学科C端和营销新中台两个。一个是C端业务,一个是B端业务。
首先,我对于团队在前端技术栈上的选择,用Vue还是React的要求上是统一的,团队内部也已经达成一致。
- 由于公司的大部分中后台业务都是Vue技术栈,因此营销新中台项目的技术选型,仍然以Vue技术栈为主。
- 对于C端业务,特别是新业务,技术栈必须统一选择React,尽量不用Vue+第三方UI库。
- 对于营销落地页,因为对更新频率有要求,基本上全部H5页面由低代码平台承接。
营销新中台
营销新中台由于是一套新后台系统,我们继续选择Vue技术栈的同时,稍微采取更激进一些的技术选型策略:
TypeScript
+ Vue 3.x
+ Element Plus
+ Eggjs
选择上面几个技术框架,主要基于几个理由考虑:
- 选择Vue3,是因为Vue2的很多常见编码习惯(例如mixin问题),对于大多数前端技术人来说,简单虽好,但实际上业务往往不简单,容易出现因为效率问题,原本1小时可以处理完的问题,需要半天。
- 鉴于在这个时期,公司的服务逐渐迁移到k8s,前端不再局限只有纯JS能力(Jenkins + 构建 + 静态资源),我认为应该把营销新中台定义为一套中后台服务,既包含前端交互,也包含一些归属前端的服务,例如前端接口。因此,我们决定把Node也一并整合在一起。选择Eggjs,是因为接入简单,而且node不需要承接复杂的业务场景。
- 最激进的是我们选择了Element Plus这个还没发布正式版的UI框架。因为我们相信,发布正式版是迟早的事。因此,我们决定在业务刚开始时就直接选择它,并对它进行二次封装,后面会提到。
- 为了提升团队编码质量,确保每个组件输入输出都能够可控、可预知,我们直接用TypeScript来规范大家编码。虽然Vue3已经支持TS,但在编码时仍然会有些地方很别扭,但不妨碍我们对代码的高质量要求。
从技术选型上,虽然已经是大家普遍能接受的搭配,但是对于目标是高质量的项目来说,还远远不够。
关于CMS-UI
在此之前先介绍一个东西,我们团队曾经在部分B端业务场景输出过一套基于Schema化的ElementUI界面生成的小框架,暂且我们叫他为cms-ui。
Schema化ElementUI小框架,什么意思呢?
首先,我们抛开业务,从界面角度分析,一个普通的功能模块,无非就包含下面3块区块Block
:
- 列表和翻页区域(
List Block
、Pagination Block
) - 搜索表单区域(
Search Block
) - 增改弹窗区域(
Form Block
)
其中,第2点和第3点都属于Form表单块。
因此我们针对Element UI这个UI库,进行二次封装,减少业务Page引用Element组件的频率和次数,改为由cms-ui组件根据Schema配置需要,动态提供相对应的element组件引用。
实际上,这种模式的封装,很像近期流行的低代码开发模式,或者是无代码开发模式。但我理解cms-ui既不属于低代码,也不属于无代码。
最重要的是,我们只对elementUI提供了一层简单的封装,对于复杂的表单交互,我们不会过多的封装,仍然需要通过slot方式做二次定制化。这样做,我们希望cms-ui组件只做最简单的事情,而不是复杂化。
所以,我们在业务开发时,除非有用slot定制化组件需求,否则一个增删改查的模块页面只有3个组件:
Simple-Table
(列表和翻页区域)Search-Form
(搜索表单区域)Simple-Form
(增改弹窗区域)
改进版cms-ui-plus
由于cms-ui是基于Vue2
+elementUI
进行二次封装,对于新项目来说并不适用,因此我们就有了升级为Vue3
+Element Plus
的计划。
而这样的封装,对于还在beta版本的Element Plus
来说,屏蔽Element Plus
底层的实现逻辑,业务只需关注实现,对于日后版本的升级来说是非常轻松。
整体设计模型
cms-ui-plus的基础能力
Simple-Table
对业务层提供的能力
- 列元素Schema配置
- 事件(点击、选择)
- 原生组件事件
Search-Form
对业务层提供的能力
- 表单元素Schema配置
- 事件(搜索、组件变化)
- 组件元数据的API配置
Simple-Form
目前只对业务层提供了包含:
- 表单元素Schema配置
- 事件(提交、提交前、取消、组件变化)
一个cms-ui-plus的例子
Example效果
具体实现的代码段,如下
<template>
<SimpleForm
:simpleForms="simpleForms"
@action="handleAction"
ref="sf"
:formData="formData"
@widgetChange="handleWidgetChange"
>
</SimpleForm>
</template>
<script>
import { computed, ref } from 'vue'
import { ElMessageBox } from 'element-plus'
export default {
setup() {
// 表单数据
const formData = ref({})
// Schema
const simpleForms = computed(() => {
return [
{
key: 'name',
type: 'input',
defaultValue: '',
label: '名称',
option: {
placeholder: '请输入名称'
}
},
{
key: 'status',
type: 'radios',
disabled: false,
label: '状态',
defaultValue: 1,
option: {
options: [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 }
]
}
}
]
})
const handleAction = async (type, val) => {
if (type === 'cancel') {
ElMessageBox.alert(`点击了取消按钮`, '标题')
} else if (type === 'submit') {
ElMessageBox.alert(`点击了保存按钮,表单数据为${JSON.stringify(val)}`, '标题')
}
}
const handleWidgetChange = (key, value) => {
console.log('handleWidgetChange', key, value)
formData.value[key] = value
}
return {
formData,
simpleForms,
handleAction,
handleWidgetChange
}
}
}
</script>
使用cms-ui-plus二次封装,我认为对于项目的质量会得到更多的保证,主要几点:
- 规范了表单组件的输入输出,保证每个人做的不同页面,都是统一的函数命名(
handleAction
)、事件命名(handleWidgetChange
)。对于不断加入的新人来说,阅读别人的代码基本上是轻松的。 - 屏蔽了表单或表格内的数据流转逻辑,形成统一输出,减少不同前端使用Element时的不同编码习惯,统一开发模式。
- 全面Schema化,减少单个Vue文件代码量,降低
ElementUI Plus
升级依赖带来的维护成本。 - 更加专注业务开发、业务数据的流转,减少对基础框架的关注度。
经过这半年的版本迭代,目前团队对于这样的开发模式已经驾轻就熟。在团队内部,cms-ui-plus也已经迭代了十几个版本,也从早期Element Plus
Beta版本,升级到正式版。
除了业务方对于功能上无法满足之外,其它因新框架新技术带来的意外问题,几乎为无。
目前这个项目,我目前给他一个85分这样的高分。
最近,我本人一直在思考,既然不像低代码,又不像无代码,那它的开发模式究竟像什么,最后我想到一个点,就是有点像Headless,不如我们给它称呼为:Headless Element UI
。
C端业务整合
第二个新项目,就是C端学科融合项目,主要应用市场是海外。
前面也提到,我们使用到的技术栈是React。其实我们仍然有不同的选择,但最终没有采用。
- 使用公司二次开发的低代码平台。但经过评估,虽然能够满足业务,低代码平台产生的额外代码量可能无法估计,对后续各种问题的解决上带来一定的难度。因此放弃。
- 如果继续使用Vue技术栈,必定会涉及到UI组件库的封装,但目前团队对于Vue的UI组件库的封装能力达不到高质量的标准。况且,此前在其它学科需求上曾经封装过部分React基础UI组件,可以直接复用。因此选择React更佳。
- 为什么不用第三方库。还是维护问题,C端新业务基本上都会有一套UI设计规范,基于第三方UI库适配设计规范,估计脏代码会很多,无法确保高质量交付,还不如自研一套,能够随时维护和可控。因此,我们决定实现了一套UI基础组件库。
基于上述3点,团队对于这样的选择是异常兴奋。因为他们可以在这样的项目中从底层设计到上层业务逻辑中,学到很多东西。
结果,项目最终输出超过10个基础UI公共组件,还有20个以上基础UI业务组件,每个组件的复用率超高。我甚至认为,这套UI组件库稍微优化一下就可以开源出去,作为教育行业的UI组件库标杆,可惜该死的双减。
下图是我们针对React工程项目的分层设计
使用Node是为了解决问题
新项目我们依然继续使用Node作为前端应用基本后端技术栈,在此之前团队已经在一些项目中深入使用过Nextjs这套开发框架。
这次,我们依然继续使用它作为我们的开发规范和模式。
有不少人会问,为什么要选择Node,选择Nextjs,选择SSR?
- 场景不同。我们不考虑CDN静态资源的方案,是由于服务器在国内,用户都在海外。静态资源虽然能加速访问页面,但无法保证接口能够快速访问。
- 我们选择nextjs,就是为了使用SSR,解决接口加速访问的同时,加快首屏访问速度。
- 用Node,我们能解决一些在App内H5鉴权等历史缺陷问题。
- 一切都是为了可监控,把接口放在Node层请求,确保能够把所有接口请求日志都可查询和可追踪。
用配置化减少发版频率
此前团队已经尝试过使用配置化json解决一些产品需求问题,比如一些开关、图片素材、数据展示控制、规则内容、协议等。
这种方案最大的优点是,通过配置化,减轻了前端频繁参与更新发版工作,让团队内每个前端都更专注在业务的设计和实现上。
实际上流程很简单,基本上是这样:
然而,在真正开发的过程中,最大的难度是哪些地方该用配置,哪些地方不需要配置。
幸好团队内部通过和产品不断沟通,基本上做到配置、后端数据、静态数据三者之间的平衡点。
目前项目仍然迭代中,基本上没有线上问题。经过半年迭代,有几次因为产品需要更改一些小地方,只需要在后台更新配置即可解决,无需发版。
使用node解决鉴权问题
前面提到,使用到Node解决一些历史问题。所谓的历史问题,是因为纯Vue或React静态资源页面,无法解决账号鉴权的一些交互问题。例如
- 用户在App内访问时,如果没有登录,必须弹窗原生登录页面。
- 用户在App已登录时,如何快速拿到用户token,并快速展示H5页面。
- 用户切换账号时,H5如何同步账号切换前后的token更新问题。
- 登录态和非登录态时,H5页面展示不同逻辑。
上面的问题,看上去纯前端基本上都可以解决。但往往是牺牲用户体验去解决的,因为很多场景下,必须是在Vue或React创建app前,就要完成账号鉴权的工作,这样必定会影响用户的体验感,因为用户访问页面的白屏时间会根据用户的网络情况而增加。
一个简单的token校验流程如图:
总结
作为第二个较大的项目,第一版开发周期持续了接近2个月,投入不少于5个前端共同协助完成。我认为团队很好的完成该项目的高质量交付。
接下来,团队将会以该项目作为标杆,整理一份template项目模板,作为公司内部的脚手架之一,为日后新项目作储备。
半年的变化
总结一下,团队经过半年的新业务磨合,基本一半人以上都已经具备有一定担当和独立承担需求开发的能力。而我则可以将更多的精力投入到团队的建设和规划之上,把技术判断力这项技能磨练得更加娴熟。
作为公司内可以把控前端业务的负责人,我的责任将会投入到更多不同维度的思考和落地。
- 团队历史债务如何解决?我们采用技术需求来推进。
- 如何配合公司降本的需求?对于前端团队来说,依然可以参与公司层面的降本工作,例如ARMS、迁移k8s等。
- 团队如何发展?从团队发展角度思考,人员分工能否更精准,承担更多责任,还有就是个人成长。
- 团队规范编码?从编码到发布,更加规范整个研发流程。
- 复用成功例子?根据业务场景,思考如何把一些功能或模块,封装成通用的工具或服务。
- 如何真的在监控?思考如何把前端业务监控链路落地,而不是简单的统计JS错误率和PVUV。
另外,今年已经过半,下半年我对团队在使命的定义上更加清晰,主要包括三点:
降本
提效
质量
最后,团队每个成员都相对稳定,没有因为双减政策受到影响,也没有因为所在教育行业的前景而思考自己的前景,他们更多的都是在如何提高自己硬技能和软实力身上。非常期待看到他们未来的发展。
短短一篇总结,虽然还不能很全面的描述,有机会我再跟大家分享作为TL的一些心得体会。