当前位置:首页 > 科技  > 软件

我们一起聊聊审核平台前端新老仓库迁移

来源: 责编: 时间:2024-07-06 07:42:38 841观看
导读背景审核平台接入50+业务,提供在线审核及离线质检、新人培训等核心能力,同时提供数据报表、资源追踪、知识库等工具。随着平台的飞速发展,越来越多的新业务正在或即将接入审核平台,日均页面浏览量为百万级别。如今审核平

背景

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

审核平台接入50+业务,提供在线审核及离线质检、新人培训等核心能力,同时提供数据报表、资源追踪、知识库等工具。随着平台的飞速发展,越来越多的新业务正在或即将接入审核平台,日均页面浏览量为百万级别。如今审核平台已是公司内容生产链路上的关键一环,是保障内容安全的重要防线,因此稳定性至关重要。ppd28资讯网——每日最新资讯28at.com

过去一年我们曾对前端项目进行框架升级,考虑风险与成本最小化,选择了渐进式升级,利用微前端实现Vue2和Vue3共存,新接业务在Vue3仓库中开发。经过一年的迭代,Vue3项目趋于稳定,沉淀了大部分通用能力。为了降低多仓库维护心智,同时解决核心模块的技术债务,考虑将剩余活跃代码进行重构并迁移至新仓库。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

面向迁移的重构 - 整洁架构在前端的应用

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

案例选择

ppd28资讯网——每日最新资讯28at.com

参考前端埋点报表,选择老仓库中页面维度访问量最高的路由,对线上使用情况进行摸排。日常业务现状是点直融合,直播业务配置化接入需求较多,因为业务形态的差异,定制需求多,现有配置能力无法满足,需扩充。开发现状是通用配置化代码改动频繁,逻辑复杂,开发门槛较高,影响范围大,牵一发而动全身。因此选择配置化详情页作为优先重构并迁移的对象。ppd28资讯网——每日最新资讯28at.com

配置化详情页采用的是业务定制化的低代码方案,包含schema渲染器和任务流两部分。当前已沉淀近百份json schema,托管在内部其他低代码平台上。页面覆盖40多个业务,占据平台约20%访问量和35%独立访客。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

如果将页面看做一个黑盒子,依据唯一标识(路由path和query等)从node服务、平台服务以及外部业务方服务获取数据,基于页面内部规则渲染页面。审核员浏览并进行通过、驳回等操作,提交后将对视频、弹幕等业务资源产生影响。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

schema渲染器基于json schema和接口数据,在平台内生成路由信息与页面内容,负责各种模式的页面分发、物料分发,并提供敏感词、快照、洗数等通用平台能力。ppd28资讯网——每日最新资讯28at.com

代码现状是数据获取、提交操作和页面复杂逻辑分散在vue文件和store中,业务逻辑和UI框架耦合严重,不利于集成自动化测试和框架升级。待办、任务、资源等边界划分不清晰,平铺在“巨石store“中,维护成本极高且代码改动风险大。渲染器和任务流逻辑不够内聚,耦合严重,无法做到关注点分离。因此需要寻找一种合适的架构进行重构,减弱业务逻辑对UI框架的依赖,增强可测试性。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

整洁架构

ppd28资讯网——每日最新资讯28at.com

整洁架构由Robert C. Martin在2012年提出,核心思想是将软件系统拆分为独立的层次,以实现高内聚、低耦合、可测试和可维护。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

一共分为四个层级,环与环之间,存在一个依赖关系原则:源代码中的依赖关系,必须只指向同心圆的内层,即由低层机制指向高级策略。ppd28资讯网——每日最新资讯28at.com

  • 实体层:包含业务领域的核心概念和业务逻辑。
  • 用例层:实现特定的业务用例,将实体层的业务逻辑与具体的应用场景结合起来。
  • 接口适配器层:负责处理与外部系统的交互比如用户界面、数据库、web服务等。将外部系统的请求和数据格式转化为用例层和实体层能够理解和处理的对象。
  • 框架和驱动层:包含具体的框架和工具,比如web框架、数据库驱动等。

优点是可以在没有UI、数据库、web服务器或其他外部基础设施的情况下测试业务逻辑;降低对UI框架的依赖,比如跨端开发时,业务逻辑可以复用,只需要做UI层的适配。相应的,缺点也很明显,过于复杂,数据需要经过多层处理。学习成本较高,容易过度设计,增加复杂性,灵活性较低。适用于大型复杂项目,对于需要长期维护和持续开发的项目,清晰层次结构和明确依赖关系有助于减少代码腐化,更容易适应需求变化。针对我们选择的模块,审核前端配置化页面,比较适合。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

重构

ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

实体层

ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

主要可拆分成待办、任务、资源等实体。待办实体,主要提供待办的基础信息、获取配置等属性和方法。任务实体提供任务的状态、任务耗时、调度配置、任务数据,计时和拉取任务流程等。资源实体提供资源的详情数据、获取详情及数据清洗方法等。待办实体包含了配置详情页所需的核心数据,任务实体高度抽象了核心任务流。在新业务接入过程中,实体层一般不变动,通过依赖倒置划分架构边界。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

// entities/todo.jsexport default class Todo {    todoId    businessId    todoConfig    ...    constructor() {}    async getTodoConfig() {        // 获取配置    }}// entities/task.jsexport default class Task {  dispatch_conf  listData  timeCount  ...  constructor() {}  async getTaskDetail({ getTask, taskFormat, afterGetTask}) {    // 抽象封装核心任务流程  }  // 计时逻辑  startTimer() {}  clearTimers() {}}// entities/resource.jsexport default class Resource {    detail    dataReady    constructor() {}    async getResourceDetail({ getResource, resourceFormat, afterGetResource }) {        // 抽象封装资源模式核心流程    }}

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

用例层

ppd28资讯网——每日最新资讯28at.com

用例层针对洗数、提交等复杂场景,通过调用实体层来实现特定的业务逻辑,是适配器层与实体层的中介。例如封装了基于配置的洗数中间件,列表模式的单个和批量提交,卡片模式的单个和批量提交,快照上报、自动化质检的复杂逻辑。用例层包含了系统的复杂业务逻辑,为单元测试提供了便利,可以独立于UI和外部系统进行测试。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

// usecase/use-single-submitimport { get } from 'lodash-es' // 三方工具库import { ANNOTATION_SINGLE_OPER_PASS_NAME } from '@/constants' // 常量import { workbenchApi } from '@/api'import { setLogData } from '@/utils/xx' // 工具函数export function getSingleSubmitParams({ data, state.xxx }) {  //... 逻辑处理  return params}export function submitAuditSingle({ data, afterTaskSubmit }) {  const params = ...  workbenchApi.submit(params).then((res) => {    if(res.code = xxx){      afterTaskSubmit() // 调用钩子函数    }  })}

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

适配器层

ppd28资讯网——每日最新资讯28at.com

适配器层包含store和UI,调用用例层的代码,主要负责将依赖UI、外部服务、设备等的数据处理为用例层可以使用的“干净数据”。适配器层一般不包括复杂的业务逻辑,因此在框架迁移时仅需关注基本的框架差异,适合自动化代码转换。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

// store/todoConfigDetailimport { getTodoInfo } from '@/struct/TodoConfigDetailStruct/usecase/use-todo'import { getTaskInfo, getTask, taskDispatchListFormat } from '@/struct/TodoConfigDetailStruct/usecase/use-task'import { getSingleSubmitParams, submitAuditSingle } from '@/struct/TodoConfigDetailStruct/usecase/use-single-submit'const todo = ref({})async function init({ $route }) {  const query = $route.query  const todoId = +query.todo_id  ...  set(todo, getTodoInfo({ todoId, ... }))  await get(todo).getTodoConfig()  ...}function getTaskDetail() {  get(task).getTaskDetail({    getTask: async ({ noSeize, drillTaskIds }) => await getTask({ todo: get(todo), noSeize, drillTaskIds }),    taskFormat: async (data) => await taskDispatchListFormat({ data, schema: get(todo).schema })    afterGetTask: (res) => { ... }  })}async function submit(data) {  if (single) {    const params = getSingleSubmitParams({ data, todo: get(todo) })    submitAuditSingle({ params, afterTaskSubmit: () => { ... } })  } else {    ...  }}
// Audit.vueconst todoConfigDetailStore = useTodoConfigDetailStore()const { todo, task, multipleSelection } = storeToRefs(todoConfigDetailStore)const { getTaskDetail, submit } = todoConfigDetailStore

ppd28资讯网——每日最新资讯28at.com

新业务接入一般对实体层和用例层无改动,仅需适配器层增加相应的展示物料,尽可能避免“牵一发动全身”。新架构会有一定的初学成本,但结合审核平台复杂的项目现状和持续接入新业务的节奏,长远来看对于系统稳定性、可测试性有一定帮助,同时降低UI框架依赖性。ppd28资讯网——每日最新资讯28at.com

基于新的架构,可分层进行自动化测试和自动代码转换。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

完善用例层的单元测试

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

用例层为纯函数,不依赖框架、设备、三方服务等。单元测试的技术栈为jest和vue-test-utils,从审核员的基本工作模式入手,针对任务领取、数据清洗与展示、稿件处理三个环节完善测试用例。因为是新老仓库迁移,所以可以将线上环境视为基准进行用例采集。根据业务重要性、线上访问情况,按优先级执行测试。单测能有效降低回归成本,在新业务持续接入的背景下,保障系统稳定性。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

适配器层的自动代码转换 - 基于gogocode将vue2升级为vue3 setup语法

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

调研与分析

ppd28资讯网——每日最新资讯28at.com

在寻求升级方案的过程中,我们对比了两款工具:Gogocode 和 vue2-to-composition-api。以下是它们的简要对比:ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

功能ppd28资讯网——每日最新资讯28at.com

Gogocodeppd28资讯网——每日最新资讯28at.com

vue2-to-composition-apippd28资讯网——每日最新资讯28at.com

缺点ppd28资讯网——每日最新资讯28at.com

默认不支持转换成 Vue3 setup 语法ppd28资讯网——每日最新资讯28at.com

不支持 template 转换ppd28资讯网——每日最新资讯28at.com

转换规则覆盖ppd28资讯网——每日最新资讯28at.com

转换规则列表ppd28资讯网——每日最新资讯28at.com

转换效果ppd28资讯网——每日最新资讯28at.com

特性ppd28资讯网——每日最新资讯28at.com

像 jQuery 一样修改ASTppd28资讯网——每日最新资讯28at.com

将 Vue2 代码转换为 Vue 3 的 Composition API 格式ppd28资讯网——每日最新资讯28at.com


ppd28资讯网——每日最新资讯28at.com

2. jQuery-like API 简化了 AST 修改成本ppd28资讯网——每日最新资讯28at.com

2. 支持在线转换ppd28资讯网——每日最新资讯28at.com

优点ppd28资讯网——每日最新资讯28at.com

1. 支持自定义插件ppd28资讯网——每日最新资讯28at.com

1. 支持转换成 Vue3 setup 语法ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

经过调研,gogocode 是基于 AST 封装的库可扩展空间大,但是默认 gogocode-plugin-vue 不支持转换成 Composition APIppd28资讯网——每日最新资讯28at.com

vue2-to-composition-api 倒是支持 Composition API,但是不支持 template 部分的转换。ppd28资讯网——每日最新资讯28at.com

考虑到我们的项目中有许多自定义的转换逻辑,如 UI 库替换、store 替换等,我们最终决定使用 gogocode 作为主要工具,并结合其他手段来实现 vue2 到 vue3 的全面升级。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

实施与探索

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

基础:升级语法

ppd28资讯网——每日最新资讯28at.com

升级语法是借助 gogocode 的 replace 方法实现的,通过 $$$ 匹配符保留所需要的代码块,将 Vue2 的语法快速替换成 Vue3 的语法。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

// 替换datascriptAst.replace("data() {return {$$$};}", `const $data = reactive({$$$})`);
// 替换propsscriptAst.replace("props:{$$$}", "const props = defineProps({$$$})");
// 替换生命周期scriptAst.replace("created(){$$$}", "onBeforeMount(()=>{$$$})")  .replace("mounted(){$$$}", "onMounted(()=>{$$$})")  .replace("async mounted(){$$$}", "onMounted(async ()=>{$$$})")  .replace("beforeUnmount(){$$$}", "onBeforeUnmount(()=>{$$$})")  .replace("unmounted(){$$$}", "onUnmounted(()=>{$$$})")  .replace("beforeDestroy(){$$$}", "onBeforeUnmount(()=>{$$$})")  .replace("destoryed(){$$$}", "onUnmounted(()=>{$$$})");

ppd28资讯网——每日最新资讯28at.com

效果如下,通过 replace 替换的方式适合大部分场景,比如 methods、filters、watch 等ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

进阶:处理模板中的变量、函数中的this变量ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

template绑定的变量可能是data,可能是props,还可能是 methodsppd28资讯网——每日最新资讯28at.com

想要替换 template 中的变量,需要先收集 data、props、methods 中的 keysppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

getDataKeys() {  const keys = new Set();  // 只需要第一层的key,所以deep设为1  this.scriptAst.find('data() {$$$}').find('$_$:$_$', { deep: 1 }).each(node => {    if (node.match[0] && node.match[0][0].node.type === 'Identifier') {      keys.add(node.match[0][0].value);    }  });  return Array.from(keys)}getPropsKeys() {  const keys = new Set();  this.scriptAst.find('props: {$$$1}', { deep: 1 }).each((node) => {    if (node.match['$$$1']) {      node.match['$$$1'].forEach((item) => {        if (item.key && item.key.type === 'Identifier') {          keys.add(item.key.name)        }      })    }  });  return Array.from(keys)}// methods 有点小复杂,需要考虑异步函数,普通函数和键值对的写法getMethodsKeys() {  const methodsAst = this.scriptAst.find('methods:{$$$}');  const methods = methodsAst.find('$_$() {$$$1}');  const asyncmMethods = methodsAst.find('async $_$(){$$$1}');  const mapKeys = methodsAst.find('$_$:$$$1', { deep: 1 });  const methodNames = [];  methods.each(node => {    if (node.match[0] && node.match[0][0]) {      methodNames.push(node.match[0][0].value);    }  });  asyncmMethods.each(node => {    if (node.match[0] && node.match[0][0]) {      methodNames.push(node.match[0][0].value);    }  });  mapKeys.each(node => {    if (node.match[0] && node.match[0][0]) {      methodNames.push(node.match[0][0].value);    }  });  return methodNames;}

ppd28资讯网——每日最新资讯28at.com

收集完成后可以开始遍历 template 中的 attr,并替换所绑定的变量了。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

handlTemplate() {    // 替换attr, 例如 <div :value="value"></div>    this.ast.find("<template></template>").find(`<$_$ ="$$$0" >$$$1</$_$>`).each((node) => {      node.match['$$$0'].forEach(attr => {        if (attr && attr.value) {          this.dataKeys.some(keyName => {            const reg = new RegExp(`${keyName}//b`, 'g')            const macth = reg.test(attr.value.content);            attr.value.content = attr.value.content.replace(reg, `$data.${keyName}`)            if (macth) {              return true;            }          })          this.methodsKeys.some(keyName => {            const reg = new RegExp(`//b${keyName}//b`, 'g')            const macth = reg.test(attr.value.content);            attr.value.content = attr.value.content.replace(reg, `methods.${keyName}`)            if (macth) {              return true;            }          })          this.propsKeys.some(keyName => {            const reg = new RegExp(`//b${keyName}//b`, 'g')            const macth = reg.test(attr.value.content);            attr.value.content = attr.value.content.replace(reg, `props.${keyName}`)            if (macth) {              return true;            }          })        }      })      // 替换content,例如:<div>{{value}}<div>      node.match['$$$1'].forEach(node => {        if (node.content && node.content.value) {          // 省略:与上面类似        }      })    })  }

ppd28资讯网——每日最新资讯28at.com

说到 this 替换也是一个繁琐的问题,this.xx, xx 可以是 data,可以是props,可以是 function,还可以是私有属性等。ppd28资讯网——每日最新资讯28at.com

所以我们需要先把组件中的 data、props、methods、mapGetter 中的 keys 都收集一遍,然后再替换 script 中的 this 变量。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

// 正则替换更方便,所以需要放在最后一步替换handlThis(code) {  code = code.replace(/this/.([_$0-9a-zA-Z]+)/g, (match, $1) => {    // 替换function body 中的 data引用    if (this.dataKeys.includes($1)) {      return `$data.${$1}`;    }    // 替换function body 中的 methods调用    else if (this.methodsKeys.includes($1)) {      return `methods.${$1}`;    }    // 替换 vm 私有属性    else if ($1 && $1[0] === '$') {      return `$vm.${$1}`;    } else if (this.computedKeys.includes($1)) {      return $1    } else if (this.propsKeys.includes($1)) {      return `props.${$1}`    }    return `$vm.${$1}`  })  // 替换function body 中的 动态methods调用  code = code.replace(/this/[(.+)/]/g, (match, $1) => {    return `methods[${$1}]`;  })  return code}

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

进阶:动态调用this.xxx该如何解决

ppd28资讯网——每日最新资讯28at.com

async parseOpenDialog(payload) {  const { schema, data } = payload  await this[schema.method](    parseSchema,    data,    dialogParams,    dialogType  )}

按 vue3 新的写法,一般是展开的ppd28资讯网——每日最新资讯28at.com

const parseOpenDialog = async (payload) => {}

但是按这个习惯来转换,就无法做到动态调用this.xxx,我们可以尝试把方法都放在methods对象中,有点类似 vue2ppd28资讯网——每日最新资讯28at.com

const methods = {  parseOpenDialog: async (payload) => {  },  xxx: async() => {  }}

在替换 this 时,将 this 替换成 methods 变成 methods[schema.method]()。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

其他技巧

ppd28资讯网——每日最新资讯28at.com

1 . 原来 vue2 中肯很多属性挂在组件实例上,比如 $route, $router, $emit 甚至自定义的属性等等。下面是 vue3 中获取组件实例的方法。ppd28资讯网——每日最新资讯28at.com

import { getCurrentInstance } from 'vue'const { proxy: $vm } = getCurrentInstance()$vm.xxx = '自定义属性'

2 . 原来使用的 vuex,现在使用的是 pinia。我们需要先收集 ...mapState($_$, [$$$1]),然后使用 storeToRefs 代替ppd28资讯网——每日最新资讯28at.com

// 获取store 使用storeToRefsif (this.storeType === 'pinia') {  this.scriptAst  .find("computed:{}")  .before(`const {${stateNames.join(',')}} = storeToRefs(${this.getPiniaStoreName(key)})`)  .replace("computed:{$$$}", "$$$")}

最终将上述转换能力封装成一个库,通过 npm 安装来实现组件批量升级。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

迁移前后的E2E测试 - 视觉辅助UI自动化测试ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

端到端测试是确保新旧系统平稳过渡的关键步骤。本次迁移依旧遵循渐进式升级的原则,新增v3路由,线上新老路由共存。共分为功能测试、UI测试、性能测试三个部分。功能测试为单元测试的补充,主要验证新老路由下核心操作路径及提交参数的一致性,拦截请求避免对线上造成影响。性能由通用监控大盘进行保障。UI对比测试是本次的重点。ppd28资讯网——每日最新资讯28at.com

新老仓库分别基于Element UI和Element Plus,Element Plus重新设计了组件以适应Vue3,组件尺寸体系调整为更自然的大中小选项。间距优化为更通用的4px体系,主要涉及 padding 和 margin 属性修改、 font-size 等字体和图标大小修改等。因此,虽然大部分组件在外观上保持相似,视觉和布局上可能有一些差异。由于业务组件具备一定复杂性,手写测试用例工作量繁琐,新旧页面组件可能存在差异无法完全复用,方案也不具备通用性。因此考虑使用计算机视觉技术来识别和验证用户界面的元素。ppd28资讯网——每日最新资讯28at.com

基于公司内部的自动化测试平台,测试框架为Playwright,测试语言选择Python以更好的利用丰富的图像处理库。指定CSS选择器,随机选择页面上的元素进行截图和对比,设定阈值进行判断。图像相似度对比可分为传统的基于像素差的方法和基于图像特征的方法。图像特征有SIFT、ORB等特征提取方法和深度学习方法。分别选择一种代表性的算法进行对比和测试。ppd28资讯网——每日最新资讯28at.com

  • SSIM(结构相似性指数),同时考虑图片亮度、对比度与结构信息。用于检测两张相同尺寸的图像的相似性。对于图像的亮度和对比度变化具有较好的鲁棒性。
  • SIFT(尺度不变特征变换),用于在图像中检测和描述局部特征,这些特征对图像的缩放、旋转和部分亮度变化具有不变性。能够检测和匹配不同尺寸下的特征,对图像的仿射变换、噪声和部分遮挡具有较好的鲁棒性。
  • LPIPS是一种深度学习特征,用于量化图像之间的感知相似性,通过比较图像在深度神经网络中的特征表示来工作,这些特征能够捕捉到人类视觉所关注的图像细节。基于一个大规模的人类感知相似性判断数据集,包含484K个人类的判断,涵盖了多种图像变换和失真类型。使用深度特征(例如VGG网络中的特征)来衡量图像相似性,比传统的度量方法更有效。

ppd28资讯网——每日最新资讯28at.com

v2ppd28资讯网——每日最新资讯28at.com

v3ppd28资讯网——每日最新资讯28at.com

SSIMppd28资讯网——每日最新资讯28at.com

SIFTppd28资讯网——每日最新资讯28at.com

LPIPSppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

0.656ppd28资讯网——每日最新资讯28at.com

0.855ppd28资讯网——每日最新资讯28at.com

0.909ppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

0.916ppd28资讯网——每日最新资讯28at.com

0.874ppd28资讯网——每日最新资讯28at.com

0.961ppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

0.658ppd28资讯网——每日最新资讯28at.com

0.857ppd28资讯网——每日最新资讯28at.com

0.881ppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

0.877ppd28资讯网——每日最新资讯28at.com

0.855ppd28资讯网——每日最新资讯28at.com

0.926ppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

0.551ppd28资讯网——每日最新资讯28at.com

0.836ppd28资讯网——每日最新资讯28at.com

0.947ppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

图片ppd28资讯网——每日最新资讯28at.com

0.929ppd28资讯网——每日最新资讯28at.com

0.884ppd28资讯网——每日最新资讯28at.com

0.942ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

实验表明,基于深度学习特征的相似度对比结果更接近用户感知,针对Vue2升级Vue3 UI组件库导致的间距、字体、尺寸等细微差异判断更准确。因此采用LPIPS作为对比算法。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

def compare_images(url1, url2):  loss_fn = lpips.LPIPS(net = 'alex')  img1 = cv2.imread(url1)  img2 = cv2.imread(url2)  if img1 is not None and img2 is not None and img1.size > 0 and img2.size > 0:      img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))      cv2.imwrite(url2, img2)      combined_image = cv2.hconcat([img1, img2])      ex_img1 = lpips.im2tensor(lpips.load_image(url1))      ex_img2 = lpips.im2tensor(lpips.load_image(url2))      d = loss_fn.forward(ex_img1, ex_img2)      if d is not None:          cv2.putText(combined_image,'score: %.3f'%(1 - d.mean()), (20, 20), cv2.FONT_ITALIC, 0.4, (255, 0, 255))      return d, combined_image  else:      return None

ppd28资讯网——每日最新资讯28at.com

依据业务流程,分别访问新老路由,对页面指定元素进行截图、对比和拼接,输出测试截图和完整的测试报告。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

采用视觉辅助UI自动化测试,更接近用户真实感知,大大降低测试用例复杂度,提升测试效率,无需关注繁杂的DOM元素层级。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

上线

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

以页面配置的形式按待办进行灰度,跳转至新路由。单元测试已集成至项目流水线中,MR和发布前触发。灰度过程中手动执行E2E用例,以自定义环境变量的形式指定页面路径、元素选择器、相似度阈值等。测试通过后修改页面配置,引流至新路由。通过用户故障群和页面反馈入口响应用户反馈,结合前端埋点报表观察线上使用情况和确定灰度策略。通过完善单元测试、E2E测试和制定合理的灰度策略,针对特定模板的迁移已顺利完成,期间未收到线上故障反馈。ppd28资讯网——每日最新资讯28at.com

后续迁移策略将以老仓库中改动较频繁文件优先入手,测试用例先行,借助自动代码转换工具快速平稳迁移,线上埋点数据做辅助。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

收益

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

活跃代码陆续迁移,结束多仓库并行,减少维护心智。之前我们的常态是新老仓库并行,开发一个完整的业务功能时要在ts和js,选项式API和setup语法之间频繁切换,心智负担较重。活跃代码陆续迁移至vue3新仓库,结合新的框架特性和实用工具,能够更专注于业务逻辑本身。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

核心模块重构,“巨石store”轻量化,提高可维护性和可演进性,分层结构保障核心逻辑稳定性。原本配置能力扩充时需要在复杂的数据流中“走迷宫”,耦合严重,通用代码影响范围大,常常出现A业务需求上线导致B业务不可用的情况。利用整洁架构进行分层设计后,新增一种审核模式仅需在适配器层新增对应物料和action,用例层新增用例。无需修改实体层和其他业务相关的用例、通用页面、物料等。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

业务逻辑的重新梳理,弥补测试用例空缺。领域提取是对业务逻辑的重新梳理,前端能加深业务理解。稳定性至上的模块很长时间缺少测试用例,造成对开发人员的经验、能力依赖极大。完善核心链路的测试用例能有效降低回归成本,保障系统稳定性。ppd28资讯网——每日最新资讯28at.com

工具沉淀,组内复用。自动代码转换工具和基于AI能力的前端E2E测试方案为后续组内其他项目的框架升级和迁移提供了便利。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

总结与展望

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

在2023年开始渐进式升级Vue3后,我们经历了很长一段时间的多仓库并行。在新业务不断接入、开发新成员加入的背景下,这样的模式无疑提升了开发门槛和维护心智。本次活跃代码的陆续迁移结束了多仓库并行的现状,同时在整个实践过程中我们为审核平台这个大型复杂项目前端引入了整洁架构的思想,为后续的开发维护提供了一种新的思路。沉淀了一套自动化vue2代码转vue3 setup的工具,可为后台项目的框架升级提供便利。同时借助AI能力提升前端E2E测试的效率,利用计算机视觉辅助前端UI自动化测试。有几点心得:ppd28资讯网——每日最新资讯28at.com

完美重构、敏捷重构、系统稳定性难以平衡。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

图片图片ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

既然下定决心对年久失修的代码进行重构,我们一定是追求极致优化和整洁的。但是需求现状是不断有新特性进来,战线拉的太长必将导致抹平差异的成本增加,因此敏捷性也很重要。同时底线是关注系统的可靠性和稳定性。这三者一定程度上存在矛盾,需平衡:ppd28资讯网——每日最新资讯28at.com

  • 任务拆分,基于埋点数据选择最重要或最紧急的链路进行重构,而非追求大而全,先落地架构,后扩充功能
  • 测试用例先行,重构必将引入风险,用例先行能最大程度保障核心功能的稳定迁移
  • 制定合理的灰度策略,新增路由,以页面配置形式进行灰度,优先uv较低的页面验证,并保证及时的反馈渠道
  • 持续优化,重构应成为一种思想,在迭代中持续优化

整洁架构非银弹,容易过度设计,学习门槛较高。ppd28资讯网——每日最新资讯28at.com

  • 按模块重构,而非项目
  • 针对新架构,制定长期维护计划,组织团队培训,降低学习成本

ppd28资讯网——每日最新资讯28at.com

多仓库迁移路线:数据为支撑,测试用例先行,借助自动代码转换工具和视觉辅助UI自动化测试,制定合理的灰度策略并建立及时的故障反馈和响应渠道。对于大型复杂项目或模块,先进行面向迁移的重构,也能起到事半功倍的作用。ppd28资讯网——每日最新资讯28at.com

ppd28资讯网——每日最新资讯28at.com

对我们而言,迁移的结束只是起点,基于更整洁的架构和更先进的前端框架,未来仍有很多发力点:ppd28资讯网——每日最新资讯28at.com

  • 对于迁移过程中沉淀下来的新架构,需不断优化和改进,以适应复杂的业务场景。
  • 在更多的业务场景下评估迁移后的性能改进,确保用户体验得到提升。
  • 持续审查并解决在迁移过程中发现的技术债务。
  • 持续建设自动代码转换工具,赋能团队内其他项目。
  • 视觉辅助UI自动化测试的方案,进一步抽象,给到不熟悉自动化测试的团队成员“开箱即用”。
  • ...

本文链接:http://www.28at.com/showinfo-26-99167-0.html我们一起聊聊审核平台前端新老仓库迁移

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: AI 引领佛山智造 数聚禅城开拓创新 2024 华为开发者大会佛山分会场圆满落幕

下一篇: Go语言助力安全测试:24小时内发送5亿次HTTP/1.1请求

标签:
  • 热门焦点
  • 小米平板5 Pro 12.4简评:多专多能 兼顾影音娱乐的大屏利器

    小米平板5 Pro 12.4简评:多专多能 兼顾影音娱乐的大屏利器

    疫情带来了网课,网课盘活了安卓平板,安卓平板市场虽然中途停滞了几年,但好的一点就是停滞的这几年行业又有了新的发展方向,例如超窄边框、高刷新率、多摄镜头组合等,这就让安卓
  • 十个简单但很有用的Python装饰器

    十个简单但很有用的Python装饰器

    装饰器(Decorators)是Python中一种强大而灵活的功能,用于修改或增强函数或类的行为。装饰器本质上是一个函数,它接受另一个函数或类作为参数,并返回一个新的函数或类。它们通常用
  • 从零到英雄:高并发与性能优化的神奇之旅

    从零到英雄:高并发与性能优化的神奇之旅

    作者 | 波哥审校 | 重楼作为公司的架构师或者程序员,你是否曾经为公司的系统在面对高并发和性能瓶颈时感到手足无措或者焦头烂额呢?笔者在出道那会为此是吃尽了苦头的,不过也得
  • 中国家电海外掘金正当时|出海专题

    中国家电海外掘金正当时|出海专题

    作者|吴南南编辑|胡展嘉运营|陈佳慧出品|零态LT(ID:LingTai_LT)2023年,出海市场战况空前,中国创业者在海外纷纷摩拳擦掌,以期能够把中国的商业模式、创业理念、战略打法输出海外,他们依
  • “又被陈思诚骗了”

    “又被陈思诚骗了”

    作者|张思齐 出品|众面(ID:ZhongMian_ZM)如今的国产悬疑电影,成了陈思诚的天下。最近大爆电影《消失的她》票房突破30亿断层夺魁暑期档,陈思诚再度风头无两。你可以说陈思诚的
  • 新电商三兄弟,“抖快红”成团!

    新电商三兄弟,“抖快红”成团!

    来源:价值研究所作 者:Hernanderz 随着内容电商的概念兴起,抖音、快手、小红书组成的&ldquo;新电商三兄弟&rdquo;成为业内一股不可忽视的势力,给阿里、京东、拼多多带去了巨大压
  • 微博大门常打开,迎接海外画师漂洋东渡

    微博大门常打开,迎接海外画师漂洋东渡

    作者:互联网那些事&ldquo;起猛了,我能看得懂日语了&rdquo;。&ldquo;为什么日本人说话我能听懂?&rdquo;&ldquo;中文不像中文,日语不像日语,但是我竟然看懂了&rdquo;&hellip;&hell
  • AMD的AI芯片转单给三星可能性不大 与台积电已合作至2nm制程

    AMD的AI芯片转单给三星可能性不大 与台积电已合作至2nm制程

    据 DIGITIMES 消息,英伟达 AI GPU 出货逐季飙升,接下来 AMD MI 300 系列将在第 4 季底量产。而半导体业内人士表示,近日传出 AMD 的 AI 芯片将转单给
  • DRAM存储器10月价格下跌,NAND闪存本月价格与上月持平

    DRAM存储器10月价格下跌,NAND闪存本月价格与上月持平

    10月30日,据韩国媒体消息,自今年年初以来一直在上涨的 DRAM 存储器的交易价格仅在本月就下跌了近 10%,此次是全年首次降价,而NAND 闪存本月价格与上月持平。市
Top