双减后的前端团队在变化中成长

·  阅读 2729

「时光不负,创作不停,本文正在参加2022年中总结征文大赛

首先自我介绍,本人花名三桥,前阿里前端技术专家,作为TL带前端团队已经有5年以上经验,带过至少5个不同前端团队。

本人目前在某在线教育公司,作为一名前端TL,深深感受到双减政策带来问题非常多,不过无论大环境如何变化,作为前端人,我们的关注点应该是自身的成长。

接下来,我总结一下2022年上半年我对团队的年中总结,重点围绕前端新业务落地对于效率、质量、协助的思考,以及如何通过前端技术栈解决业务问题。

因外部变化而调整

2021年是整个在线教育行业的转折点,无论是业务、团队、还是个人,都有极大的变化和调整。

双减政策的实施,注定了公司的业务需要调整,作为前端团队同样也要调整和优化。

最明显的变化有几点:

  1. 业务战线收缩,由以前大范围无限制的营销推广,变成有限的低成本转介绍。
  2. 人员收缩,注定有些人留下继续奋斗支持公司,有些人因为调整带来不同程度的心情。不过,我一直认为,只要你有足够的优秀,去哪里都能发挥你的能力。
  3. 团队调整,原本我负责的团队只是负责其中一个业务,逐渐变成负责全公司80%的前端业务。团队职能变化注定每个人负责的事情会更多,同时也都要学会承担更多的责任。

团队职责的变化

双减后的第一年,公司进行了各种各样的优化,作为研发技术的其中一个团队,同样也要跟着公司的业务发展进行。

团队的责任变化

前端团队经过调整后,承担的责任就更大了,主要包括3个方面:

  1. 交接多个不同领域的前端项目,前前后后至少50+个,包括中后台项目、PC端项目、C端H5项目等等。团队每一个成员都要具备快速熟悉业务和了解项目流程,对团队来说是个不小的挑战。
  2. 团队人数不变,但业务更多。这样的事情对于团队每个人来说,需要更多的沟通和协调能力,甚至是Owner的能力,不再是单纯的做个页面,调下接口等常规的事情。
  3. 团队承担着公司接近80%的前端项目,作为TL的我就不能用小团队思维去管理,需要从全局的角度思考团队如何更高效和高质量的交付项目。

团队的使命

所以,我给团队在2022年的上半年制定了一个使命:

跟着组织走,提高项目质量

团队的优先级调整

同时,在上半年业务和产品计划做两条新的业务线,第一是整合现有的业务,主推海外市场;第二是营销新中台。

在过去,公司很多老业务,都是基于传统的纯Vue技术栈来满足业务需求,往往上线后项目质量不高,又或者代码质量不高,给团队后续维护带来很多的问题。

为避免重复历史的坑,刚好上半年也只有新业务需求不多,作为前端TL的我,我们团队就以高质量交付作为目标去完成这样的新业务。

所以团队接下来对于业务需求的优先级定义如下

营销新中台 > 新C端整合业务 > 学科业务 > 基础支撑业务 > 技术优化

新业务落地

上半年,团队的新业务主要围绕整合学科C端和营销新中台两个。一个是C端业务,一个是B端业务。

首先,我对于团队在前端技术栈上的选择,用Vue还是React的要求上是统一的,团队内部也已经达成一致。

  1. 由于公司的大部分中后台业务都是Vue技术栈,因此营销新中台项目的技术选型,仍然以Vue技术栈为主。
  2. 对于C端业务,特别是新业务,技术栈必须统一选择React,尽量不用Vue+第三方UI库。
  3. 对于营销落地页,因为对更新频率有要求,基本上全部H5页面由低代码平台承接。

营销新中台

营销新中台由于是一套新后台系统,我们继续选择Vue技术栈的同时,稍微采取更激进一些的技术选型策略:

TypeScript + Vue 3.x + Element Plus + Eggjs

选择上面几个技术框架,主要基于几个理由考虑:

  1. 选择Vue3,是因为Vue2的很多常见编码习惯(例如mixin问题),对于大多数前端技术人来说,简单虽好,但实际上业务往往不简单,容易出现因为效率问题,原本1小时可以处理完的问题,需要半天。
  2. 鉴于在这个时期,公司的服务逐渐迁移到k8s,前端不再局限只有纯JS能力(Jenkins + 构建 + 静态资源),我认为应该把营销新中台定义为一套中后台服务,既包含前端交互,也包含一些归属前端的服务,例如前端接口。因此,我们决定把Node也一并整合在一起。选择Eggjs,是因为接入简单,而且node不需要承接复杂的业务场景。
  3. 最激进的是我们选择了Element Plus这个还没发布正式版的UI框架。因为我们相信,发布正式版是迟早的事。因此,我们决定在业务刚开始时就直接选择它,并对它进行二次封装,后面会提到。
  4. 为了提升团队编码质量,确保每个组件输入输出都能够可控、可预知,我们直接用TypeScript来规范大家编码。虽然Vue3已经支持TS,但在编码时仍然会有些地方很别扭,但不妨碍我们对代码的高质量要求。

从技术选型上,虽然已经是大家普遍能接受的搭配,但是对于目标是高质量的项目来说,还远远不够。

关于CMS-UI

在此之前先介绍一个东西,我们团队曾经在部分B端业务场景输出过一套基于Schema化的ElementUI界面生成的小框架,暂且我们叫他为cms-ui。

Schema化ElementUI小框架,什么意思呢?

首先,我们抛开业务,从界面角度分析,一个普通的功能模块,无非就包含下面3块区块Block

  1. 列表和翻页区域(List BlockPagination Block
  2. 搜索表单区域(Search Block
  3. 增改弹窗区域(Form Block

其中,第2点和第3点都属于Form表单块。

因此我们针对Element UI这个UI库,进行二次封装,减少业务Page引用Element组件的频率和次数,改为由cms-ui组件根据Schema配置需要,动态提供相对应的element组件引用。

实际上,这种模式的封装,很像近期流行的低代码开发模式,或者是无代码开发模式。但我理解cms-ui既不属于低代码,也不属于无代码。

最重要的是,我们只对elementUI提供了一层简单的封装,对于复杂的表单交互,我们不会过多的封装,仍然需要通过slot方式做二次定制化。这样做,我们希望cms-ui组件只做最简单的事情,而不是复杂化。

所以,我们在业务开发时,除非有用slot定制化组件需求,否则一个增删改查的模块页面只有3个组件:

  1. Simple-Table(列表和翻页区域)
  2. Search-Form(搜索表单区域)
  3. Simple-Form(增改弹窗区域)

改进版cms-ui-plus

由于cms-ui是基于Vue2+elementUI进行二次封装,对于新项目来说并不适用,因此我们就有了升级为Vue3+Element Plus的计划。

而这样的封装,对于还在beta版本的Element Plus来说,屏蔽Element Plus底层的实现逻辑,业务只需关注实现,对于日后版本的升级来说是非常轻松。

整体设计模型

simple-form-img.png

cms-ui-plus的基础能力

Simple-Table对业务层提供的能力

  1. 列元素Schema配置
  2. 事件(点击、选择)
  3. 原生组件事件

Search-Form对业务层提供的能力

  1. 表单元素Schema配置
  2. 事件(搜索、组件变化)
  3. 组件元数据的API配置

Simple-Form目前只对业务层提供了包含:

  1. 表单元素Schema配置
  2. 事件(提交、提交前、取消、组件变化)

一个cms-ui-plus的例子

Example效果

image.png

具体实现的代码段,如下

<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二次封装,我认为对于项目的质量会得到更多的保证,主要几点:

  1. 规范了表单组件的输入输出,保证每个人做的不同页面,都是统一的函数命名(handleAction)、事件命名(handleWidgetChange)。对于不断加入的新人来说,阅读别人的代码基本上是轻松的。
  2. 屏蔽了表单或表格内的数据流转逻辑,形成统一输出,减少不同前端使用Element时的不同编码习惯,统一开发模式。
  3. 全面Schema化,减少单个Vue文件代码量,降低ElementUI Plus升级依赖带来的维护成本。
  4. 更加专注业务开发、业务数据的流转,减少对基础框架的关注度。

经过这半年的版本迭代,目前团队对于这样的开发模式已经驾轻就熟。在团队内部,cms-ui-plus也已经迭代了十几个版本,也从早期Element PlusBeta版本,升级到正式版。

除了业务方对于功能上无法满足之外,其它因新框架新技术带来的意外问题,几乎为无。

目前这个项目,我目前给他一个85分这样的高分。

最近,我本人一直在思考,既然不像低代码,又不像无代码,那它的开发模式究竟像什么,最后我想到一个点,就是有点像Headless,不如我们给它称呼为:Headless Element UI

C端业务整合

第二个新项目,就是C端学科融合项目,主要应用市场是海外。

前面也提到,我们使用到的技术栈是React。其实我们仍然有不同的选择,但最终没有采用。

  1. 使用公司二次开发的低代码平台。但经过评估,虽然能够满足业务,低代码平台产生的额外代码量可能无法估计,对后续各种问题的解决上带来一定的难度。因此放弃。
  2. 如果继续使用Vue技术栈,必定会涉及到UI组件库的封装,但目前团队对于Vue的UI组件库的封装能力达不到高质量的标准。况且,此前在其它学科需求上曾经封装过部分React基础UI组件,可以直接复用。因此选择React更佳。
  3. 为什么不用第三方库。还是维护问题,C端新业务基本上都会有一套UI设计规范,基于第三方UI库适配设计规范,估计脏代码会很多,无法确保高质量交付,还不如自研一套,能够随时维护和可控。因此,我们决定实现了一套UI基础组件库。

基于上述3点,团队对于这样的选择是异常兴奋。因为他们可以在这样的项目中从底层设计到上层业务逻辑中,学到很多东西。

结果,项目最终输出超过10个基础UI公共组件,还有20个以上基础UI业务组件,每个组件的复用率超高。我甚至认为,这套UI组件库稍微优化一下就可以开源出去,作为教育行业的UI组件库标杆,可惜该死的双减。

下图是我们针对React工程项目的分层设计

image.png

使用Node是为了解决问题

新项目我们依然继续使用Node作为前端应用基本后端技术栈,在此之前团队已经在一些项目中深入使用过Nextjs这套开发框架。

这次,我们依然继续使用它作为我们的开发规范和模式。

有不少人会问,为什么要选择Node,选择Nextjs,选择SSR?

  1. 场景不同。我们不考虑CDN静态资源的方案,是由于服务器在国内,用户都在海外。静态资源虽然能加速访问页面,但无法保证接口能够快速访问。
  2. 我们选择nextjs,就是为了使用SSR,解决接口加速访问的同时,加快首屏访问速度。
  3. 用Node,我们能解决一些在App内H5鉴权等历史缺陷问题。
  4. 一切都是为了可监控,把接口放在Node层请求,确保能够把所有接口请求日志都可查询和可追踪。

用配置化减少发版频率

此前团队已经尝试过使用配置化json解决一些产品需求问题,比如一些开关、图片素材、数据展示控制、规则内容、协议等。

这种方案最大的优点是,通过配置化,减轻了前端频繁参与更新发版工作,让团队内每个前端都更专注在业务的设计和实现上。

实际上流程很简单,基本上是这样:

流程图-配置.png

然而,在真正开发的过程中,最大的难度是哪些地方该用配置,哪些地方不需要配置。

幸好团队内部通过和产品不断沟通,基本上做到配置、后端数据、静态数据三者之间的平衡点。

目前项目仍然迭代中,基本上没有线上问题。经过半年迭代,有几次因为产品需要更改一些小地方,只需要在后台更新配置即可解决,无需发版。

使用node解决鉴权问题

前面提到,使用到Node解决一些历史问题。所谓的历史问题,是因为纯Vue或React静态资源页面,无法解决账号鉴权的一些交互问题。例如

  1. 用户在App内访问时,如果没有登录,必须弹窗原生登录页面。
  2. 用户在App已登录时,如何快速拿到用户token,并快速展示H5页面。
  3. 用户切换账号时,H5如何同步账号切换前后的token更新问题。
  4. 登录态和非登录态时,H5页面展示不同逻辑。

上面的问题,看上去纯前端基本上都可以解决。但往往是牺牲用户体验去解决的,因为很多场景下,必须是在Vue或React创建app前,就要完成账号鉴权的工作,这样必定会影响用户的体验感,因为用户访问页面的白屏时间会根据用户的网络情况而增加。

一个简单的token校验流程如图:

简单token鉴权流程-导出 (1).png

总结

作为第二个较大的项目,第一版开发周期持续了接近2个月,投入不少于5个前端共同协助完成。我认为团队很好的完成该项目的高质量交付。

接下来,团队将会以该项目作为标杆,整理一份template项目模板,作为公司内部的脚手架之一,为日后新项目作储备。

半年的变化

总结一下,团队经过半年的新业务磨合,基本一半人以上都已经具备有一定担当和独立承担需求开发的能力。而我则可以将更多的精力投入到团队的建设和规划之上,把技术判断力这项技能磨练得更加娴熟。

作为公司内可以把控前端业务的负责人,我的责任将会投入到更多不同维度的思考和落地。

  1. 团队历史债务如何解决?我们采用技术需求来推进。
  2. 如何配合公司降本的需求?对于前端团队来说,依然可以参与公司层面的降本工作,例如ARMS、迁移k8s等。
  3. 团队如何发展?从团队发展角度思考,人员分工能否更精准,承担更多责任,还有就是个人成长。
  4. 团队规范编码?从编码到发布,更加规范整个研发流程。
  5. 复用成功例子?根据业务场景,思考如何把一些功能或模块,封装成通用的工具或服务。
  6. 如何真的在监控?思考如何把前端业务监控链路落地,而不是简单的统计JS错误率和PVUV。

另外,今年已经过半,下半年我对团队在使命的定义上更加清晰,主要包括三点:

降本 提效 质量

最后,团队每个成员都相对稳定,没有因为双减政策受到影响,也没有因为所在教育行业的前景而思考自己的前景,他们更多的都是在如何提高自己硬技能和软实力身上。非常期待看到他们未来的发展。

短短一篇总结,虽然还不能很全面的描述,有机会我再跟大家分享作为TL的一些心得体会。

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改