我在税友这两年(上)

欧雷 发表于

0 条评论

在 2020 年 12 月末时,我入职了税友的数据智能相关部门。这算是一个中台部门,其主要职责是为其他前台业务部门提供内容推荐、智能营销、智能客服等服务。

经过两年多一点的锤炼,带着些许无奈和遗憾(但谈不上失望),我离开了。在此期间,我在技术、专业上的成长可以认为一无所获,但在人性与社会性方面令我有了更多的思考。

工作成果

这个部门虽说不是一个纯粹的业务部门,但对于前端这个职业来说它就是业务部门——发展瓶颈是一样的。

入职后的前几天,在大致了解了部门及前端的整体情况后,我的目标明确了——先搞基建,解决前端内部问题及与上下游协作问题;然后尝试部门内向架构或产品转型,这样就不存在前端职业发展瓶颈的问题了。

团队中算上我总共有三个前端,在我来之前已经积累了很多技术债:规范缺失,抽象不足导致的强耦合和大量重复代码,程序设计方面的问题等。

作为团队中最「老」的前端,结合现状与我个人的目标,在心里初步定下了前端团队的大概发展方向:

  1. 规范化、标准化——让开发流程变得更正规、有序,让项目维护和开发起来更容易;
  2. 配置化、低代码化——提高业务从需求到交付的效率;
  3. 自动化、智能化——提升部门内部的整体效率。

前两个是解决前端内部问题,最后一个是解决上下游协作问题。

在将我的想法付诸实践之前,几乎都会叫上相关人员(有时包括架构师、团队负责人)开会讲解一下并达成共识。即便如此,在推进落地时仍会遇到一些阻碍。

团队约定

「约定」、「规范」、「标准」,虽然表达形式不同,相互之间的语义也有些许差别,但它们的核心相同——都是「共识」。

制定规范、标准的意义,并非是将某个资深人员的知识与经验或社区所谓的「最佳实践」作为权力工具,像规矩一样奴役他人;而是针对常规问题如何尽可能优雅且合理地解决达成共识,减少在处理相关问题时的选择,提高作业与协作效率并降低内耗。

团队成员间所达成的共识,也是一种内化的知识,会形成共通的上下文在日常工作中起到指导作用,从而规避问题。

在 2021 年的 3、4 月份,我陆续起草了《编码风格》、《目录结构划分模式》、《代码审核规则》和《技术方案评审规则》,并与团队成员讨论确定。

单靠人的记忆、自觉与监督,一方面会造成个人的精神能量消耗,另一方面还是会或多或少地影响效率。并且,后加入的每个新人都得去理解并记忆一遍,重复磨合的过程。

在有了规范、标准后,完全可以将共识尽可能地固化进开发工具中——知识的记载方式从文字书写的文档转移到直接关系到产物的开发工具中,省略掉人脑处理的步骤,能够有效降低沟通协作成本以及对人员素质的要求。

当前存在的开发工具,也就只能将《编码风格》的部分规则转化为 formatter、linter 类工具的配置,如 Prettier、ESLintStylelint 等。

那些无法固化进开发工具中的,在执行时若是严格要求的话,会增加很多沟通时间,且很容易发生摩擦;倘若不去严格执行,当初为何要花费时间和精力去制定那形同虚设的规范、标准?

在这里,代码审核是强制的,是开发流程的一部分,并且在最初的那段时间我是较为严格地遵照规范、标准去看,因此在配置化开发普及之前几乎每个变更都要消耗我至少 20 分钟的时间去仔细地阅读代码并给出修改意见或建议。

又由于他们过往养成的习惯一时半会儿很难改变,对每个人进行代码审核时都会提出很多修改意见或建议,大多是规范、标准里已经有的,部分是程序设计类的。

一开始时,因不遵从规范、标准而产生的问题实在太多了,一次代码审核中会有很多个,这时我就面临了一个难题——

在第一次时把所有问题都指出来,这很容易很简单,但指出了之后不全部修改或以后反复出现呢?是来回拉锯使团队氛围变差直到某个人妥协?还是就不去严格要求完全按照规范、标准去做?

根据团队的实际情况,我逐渐选择了适当放水而不强求的策略,只要核心逻辑和一些关键点没什么问题就行。若选择死磕并强硬推行,最后除了我与他们之间的关系僵化,落得负面评价之外,还能得到什么呢?

在团队成员基本能力达标的前提下,这类问题的根本是——在软件生产中人到底是不是「人」?

也就是说,如果人在生产过程中只是暂不存在或暂未成熟的某个零件、部件、仪器的临时替代品,那这个人不能把自己当「人」看,就仅仅是个螺丝钉而已,该做的就是没有自己思想地去绝对服从,严格按照规范、标准去做事。

但要是把人当「人」看,在没有完善的开发工具进行保障时,靠人去严格且完美地执行规范、标准几乎是不可能完成的事情。

所以说,在有了规范、标准后不能花费过多的时间和精力去教育他人,甚至是妄想改变他们;反而应该抓紧时间去改造并完善开发工具,将规范、标准固化进去之后,大多问题就会迎刃而解——让人做「人」,开心工作!

综上所述,规范化、标准化是配置化、低代码化及后续步骤的前提。

配置化改造

所谓的「配置化」,就是利用 Handie 所提供的抽象与扩展等能力,通过相对简明的声明式 JS 对象替代原来主要靠写 UI 组件实现的功能——装配式的视图编排与逻辑编排。

基于 Handie 进行配置化开发的好处有很多,包括但不限于:

  • 与常规的 UI 组件相比,简明的 JS 对象减少了大量不必要的字符,使代码可读性变得更好,令注意力更加集中,进而加速代码审核过程并更容易发现问题所在;
  • 内置业务向的模块系统,可以更方便地约束和查看业务模块间的依赖关系;
  • 促进高内聚、低耦合的模块抽象与拆分,以及表现与逻辑的分离,并提高模块的可复用性和可插拔性,进而提升整个应用的可维护性;
  • 核心逻辑可以认为都是表现层技术栈无关的,能够极大地降低表现层技术栈迁移成本;
  • 反向促进 UI & UX 设计及 HTTP 接口的规范化、标准化;
  • 为「设计即代码」和「后端统一建模」等链路级低代码化做铺垫,也就是如何通过产品或 UI & UX 设计以及后端数据定义直接生成前端页面相关的配置。

「缺点」当然也有,其中影响比较大的是:

  • 对习惯于主流前端开发方式的人来说有一定的门槛,一是要理解一些 Handie 设计上的抽象概念,二是要一定程度上转变思维方式;
  • Handie 相关的文档严重缺失,对使用者的自主学习造成很大影响;
  • 暂时没有配套的专用调试工具,在开发功能和定位问题时需要一些技巧和对 Handie 构成的了解。

在税友的这两年多一点的时间里,有大概一年左右是在支撑业务需求的同时进行部门前端项目业务代码的配置化,涉及到两个较大的遗留项目和几个新建项目,Vue 和 React 的都有。

新建项目实施起来没什么难点,改造遗留项目才有些许挑战,就拿最大的构建在 Vue 之上的遗留项目来说——

这个项目有几十个业务模块且模块间依赖混乱,频频看见业务层面的循环依赖;另一个不受我待见的地方就是使用了中心化状态管理(这玩意儿何时能从业界消失),加大了改造难度。

让一个前端项目腐化成这样,常见的目录结构划分和「页面驱动」的思维方式是重要影响因素,因而要先对项目的目录结构动刀子。

在《聊聊中后台前端应用:目录结构划分模式》中我提到了「野生」、「分层」和「模块化」这三种模式,常见的目录结构划分就是「野生」模式。

在进行目录结构改造时,先用到的是「分层」模式,因其思想与「野生」模式大相径庭,整个项目的目录结构发生了颠覆性变化。在改造的同时也对业务层面的模块和依赖关系做了梳理,加深了对业务的了解。

经过一波改造后,项目的层次结构明显变得更清晰了,但觉得业务模块的内聚性还是差那么一点儿意思,一番琢磨之后最终升级为「模块化」模式。

「分层」模式与「模块化」模式
「分层」模式与「模块化」模式

改造完目录结构,该将刀口转向业务代码了。虽说改变目录结构不是配置化改造的前置条件,但对其更为有利。

理所当然,业务代码改造要比目录结构调整麻烦很多,但我一点儿也不慌,毕竟不是第一次改造大型遗留项目——之前在京东汽车后市场相关部门时就做过「京东云修」的前后端分离

两者之间虽有不同,但也没什么不同,所要遵循的基本原则都一样:全新的功能用新方式实现,已有的功能得渐进式替换,不能影响业务主流程,这就意味着新旧方式或代码会同时存在。

在进行业务代码配置化改造时,先处理了数量最多且模式化程度最高的列表页,大多情况直接用内置的表格视图部件就行,实在无法满足需求就利用 Handie 的扩展能力自定义一个项目级或业务模块级的视图部件。

接着就是表单对话框,因为这个应用中页面形式的表单很少,做法同上。有个别几个难啃的骨头,直到我离职也没完成配置化改造……

配置化改造这件事儿,要说难,对我来说技术层面上不算难,几乎就是体力活儿;比较有挑战的地方在于让其他前端人员走出舒适区,理解并接受甚至习惯于采用配置化开发这种方式去完成日常工作。

总而言之,Handie 所起到的一个重要作用,就是固化一些规范、标准和模式,降低沟通协作成本并减少摩擦。

关于由 Handie 驱动的前端项目的目录结构及业务代码编写方式是怎样的,可见源码仓库中的示例:https://github.com/future-js/handie/tree/master/demos/vue

跨组件库验证

在 2021 年 7 月中到 11 月底,我被「外派」到一个业务部门的项目组中去支援开发,这段经历给我最大的收获是进一步验证了 Handie 的模块化和跨组件库的能力。

由于在之前写的文章中提过,这里就直接引用过来——

我开发的长得像电子表格的配置工具,姑且叫它「底稿电子表格」,在两个相互独立的应用中都用到这个功能,虽然它们都是基于 Vue 的,但用的 UI 组件库不一样,分别是 Element 和 ViewUI。

大部分人遇到这个场景可能要头疼了——在两个应用中用 Element 和 ViewUI 各实现一遍功能?这显然不可能,后期维护成本会高得离谱!并且,如果再要集成进其他应用中呢?用其中一个 UI 组件库去开发那个模块,然后在集成的应用中再额外引入那个 UI 组件库?别想了……怎么保证模块的样式与应用的风格统一并且低维护成本?

由于在项目中引入了 Handie,所以我一点也不头疼——归功于 Handie 及其配套是基于接口编程的,在开发底稿电子表格模块时只考虑 API 的调用、拼接就好了,什么 UI 组件啊请求服务的,都在集成的应用中注入进去。

上图中红色部分是 Handie 及其配套与我自研的电子表格库;蓝色部分是具体的业务应用;绿色部分是底稿电子表格这个被集成的模块,它单独存放在一个 Git 仓库里,作为 NPM 包被业务应用依赖。

小结

篇幅有限,本文就只略微详细地阐述我这两年来在税友除了正常支撑日常业务需求之外,做了哪些让我自己认为值得一提的事情;关于工作体验相关的,留到下篇文章再叙。

我在工作中所做的这些事,使配置化开发在部门前端项目中的占比达到约 80% 左右,从最终的代码量来看,确实让 UI 组件的复用率变高且总代码量变低了。

那么,这给我带来技术、专业上的成长了吗?可能有些人觉得有,但我认为基本没有。话说,「技术、专业上的成长」到底是指什么?

创作不易,若本文给你提供了价值,还请不吝欧雷充电

左为微信,右为支付宝;充电累计 ¥88 以上可在付款时备注或邮件告知昵称和需要被链接的网址,会列在「赞助」页。其他方式与具体规则请见「资助」。