不重构一次,都不敢说自己详细了解业务了

2,197 阅读18分钟

写在前面:先说一说最近的办公状态吧,北京的疫情不得不居家办公了,居家办公的日子里,少去了通勤的时间,因此可以利用通勤的时间做点有意思的事情,跑跑步,做个“刘畊宏女孩”。有时间的时候自己还可以做做饭,消磨下时间;当然也有缺点啦,生活和工作融合在一起了,有的时候忙的可能会通天工作,让人感觉到疲惫感,不过好在疫情慢慢变好啦~
这是一篇文字叙述类文章,有些枯燥 切入正题,让我们正式的说一下今日的主题:重构

为什么要重构

有句话说的特别好,当一个项目能够正常启动和运行的时候,就不要改动了,否则会收到意想不到的“惊喜”。重构即是在现有代码上保持功能的一致性情况下,进行功能的代码重新编写。
重构 其实是对内部结构的一种调整,目的是不改变软件可观察性行为前提下,提高其可理解性,降低其修改成本;
接下来从以下几个角度去看下项目是否适合重构

重构改进软件的设计

如果没有重构,现有代码内部设计会逐渐变的腐败变质,维护成本开发成本都变得很高,当为了修改功能进行改动代码时,如没有理解架构的整理设计,代码在修改后会变的越来越乱,代码结构的流失有积累效应,就会越来越难其保护设计,代码腐败就会越来越多;代码量减少将使未来可能修改的程序越来越方便,

重构使软件更容易理解

编程的核心在于“准确的说出我想要的”,然而本身仓库代码并非自己一个人在维护,还有其他的源码读者,所以可读性对于代码本身而言是非常重要的,而代码的可读性不仅仅影响着对后续代码功能改动,也对业务理解有直接关系,其他更改人会根据代码进行业务理解;如果从代码层面无法进行浅聊业务的理解,后续改动人将更加越来越来困难。

重构能够帮助找到bug

代码较为乱会导致代码存在问题时,无从下手,对代码进行重构,就可以深入理解代码的行为,并立即把新的理解反馈在代码中,搞清楚程序运行的同时,揪出来代码的中的问题,定位问题成本就减少

重构提高编程速度

重构的代码在于软件内部的质量,需要添加新功能时,内部质量良好的软件让我可以很容易找到在哪里修改,良好的模块划分只需要理解代码库中的一部分,就可以做出修改,引入bug的可能性就会变少,通过投入精力改善内部设计,增加了软件本身的耐久性,从而可以保持长时间的快速开发;

image.png

小总结

  • 代码复杂度、耦合程度很高,改一处而引发全身
  • 进行新功能增加以及功能迭代时,开发成本很大
  • 定位问题,设计原理已经不复存在,维护成本很大
  • 现有技术使用较为落后,重新选型后,能够提高本身已经的设计理念,同时使代码变得更好理解

关于我的重构考虑

  • 历史包袱过重,无法从代码层面进行很好的业务理解,
  • 代码、文件耦合度很高,相似功能散落在各个文件中,极难维护
  • 技术组件使用成本以及学习成本很高,本次重构多为大表单场景,表单校验等功能目前已有使用的较为繁琐;
  • 接口层面和前端层面存在大量的字段转换,导致排查问题时较为困难
  • 改动成本较大,不敢随意改动历史代码,同时开发一个新需求开发时常增多;

重构过程

何时重构

当你想好要重构的时候,就是真的要重构了,重构必然要花费大量的时间去投入,因此要协调相关资源去支持,同时也要为自己的本次重构进行设计;把重构融合到工作过程中,在现实的工作中,自己发起重构然后就干是不现实的,通常的重构其实很大程度是伴随工作的; 重构分为小型重构大型重构

  • 小型重构 通常是指当前功能较小的时候,但是添加新功能点已经无法在已有代码的基础上进行修改,迭代功能发生了巨大的变化,因此需要重新设计
  • 大型重构 其实更好理解,工作量大,且涉及的周期比较长 重构绝对不是因为看不惯别人写的代码等而轻易下的结论,是经过长时间的思考和平衡,最终决定的结果
  • 预备性重构:让添加新功能更容易,此时动手添加新功能钱,会对整个代码进行检查,如果对代码结构进行微调,就会有很大的工作量,不进行重构,也是copy已有代码进行复制过程,如果要修改,就必要修改好几处同一代码,历史代码的实现内聚佳偶多
  • 帮助理解的重构:使代码更容易 ,代码结构较为糟糕的情况下,条件逻辑都比较换乱,而重构,则可以把理解的转移到代码本身;简化复杂逻辑的实现模式,立竿见影,让代码更清晰一点
  • 捡垃圾式的重构 并非所有的代码和业务逻辑都是复杂混乱的,因此当当前某个逻辑实现是相对比较复杂时候,那此时可以重构某个业务逻辑;
  • 有计划的重构和见机行事的重构 其实上面三种重构模式就是见机行事的重构,并不需要安排一个时间点去单独做这个部分,而是在添加新功能时,顺手更改了历史的业务逻辑;而有计划的重构则是让复杂的代码在每次的需求中自然而言去做到优化
  • 长期重构 有些大型的功能重构可能要花上几个星期,例如要进行模块的重构,需要进行抽离,这个过程无非是耗时的,不仅仅要考虑向后兼容问题,同时也需要考虑时间人力成本等问题
  • 复审代码时重构 好多公司其实都会有code review,这个过程可以改善开发状况,代码复审有利于在开发团队中传播知识,也有助于让比较有经验的人把知识传播给欠缺经验的人,并且帮助更多人理解大型软件系统中更多的部分 以上的部分,其实是看了马丁· 福勒的《重构》有感,接下来就是本人在重构阶段,认为要做的非常重要的事情啦~

重构计划

当准备重构时,需要做的事情还是很多的;重构主要分为了以下几步 image.png 以上步骤其实都在在重构过程中不可缺少的步骤,进行重构不仅仅是需要进行现有功能的开发,很重要的是上线后,不会影响线上功能,接下来就从步骤中逐一介绍要做这件事的目的,其中技术设计 & 开发自测这两部步骤于开发人员非常重要的。

梳理老项目业务 / 技术

其实梳理的目的很简单,如果你自己本身就对业务不熟悉,那么你去说要重构简直是“痴人说梦”,就算你提出了,没有很好依据支撑你的重构想法,是根本不会通过方案的;因此梳理老项目业务是一个必要且重要的过程;

  • 由粗到细,就像填坑一样,首先使用大石头进行填充,其次是用小石头逐渐填,梳理业务也是如此,要明确有大概方向,然后再通过历史文档或者代码层面去进行细节填充;梳理完后能够很熟悉掌握流程,其中如果梳理过程中存在疑问,一定不要想当然是这样子的,要进行确认,梳理业务有助于帮助我们做正确的事情,只有方向对了,我们做的事情才有意义;
  • 梳理技术,一个要重构的项目,在技术使用上难免会存在一些痛点,而重构则是很好的一次技术选型,使用方便的框架/技术能够让我们在开发中如鱼得水;梳理技术则是为重构添砖加瓦,现有技术痛点,能够让我们更好的在新项目中规避
  • 梳理公共方法 散落的黄豆,你需要花费好多时间才能去各个地方捡起来,而这些黄豆就如同代码仓库里面的方法,有的方法功能一致,却因为业务不同,导致后来散落在各个地方,而梳理公共方法,则是将黄豆拣起来的过程,在新项目中聚合此类方法;
    • 路由统一跳转在我们重构业务中,有一些挂在链接上的通参,需要在页面跳转的时候携带上,在历史仓库中,就很限制,每一个跳转的路由上都加了参数,改动点大概10多处,而这个逻辑,完全可以在跳转前置流程进行修改,业务代码中就无需关注这个参数的添加
    • 请求拦截器 & 响应器,我们都知道axios有拦截器和响应器,但是在一些app内,通常是使用端内的jsb fetch 进行整合的,而此时是没有拦截器和响应器的,一些公共的处理方式可能会写在各个业务上,不好维护,因此可以在新项目中进行此类公共实现的设计
    小总结:梳理老项目的业务/技术,其实就是为了我们新项目的技术设计做好最坚实的基础,同时也是我们进行重构的理由;

前端技术设计

以下列举了本次重构的大概方向 image.png

  • 仓库建设:仓库建设部分包含了两部分代码仓库选项代码目录设计,仓库的选择其实就是技术栈选择,代码目录设计也是一门技术吧,好的目录结构其实也是后续代码清晰度的一种体验,因此需要前置设计好各个目录结构
  • 基础模块:基础模块其实还是很多的,一些基础模块的设计可以让我们后续开发中效率翻倍嘿嘿
    • 基础方法
      • 基础工具方法:这部分包含其实还是很多的,比如:通用的数据转换方法数据判断方法,还有一些适合于自己业务的公共方法
      • 请求方法 目前前端应用最多的就是axios,因此此模块的设计就非常重要,通常在请求方法中会处理一些公共的请求和拦截处理,如增加全局的接口参数,处理返回的数据code等,如1xx、3xx、4xx、和5xx等,除此之外还有一些业务上的,比如,后端返回code =2000时,去登录,都可以在拦截器中设计
      • 其他方法,泛类,比较多,所以需要根据项目进行设计
    • 组件
      • 基础通用组件;基础组件的丰富性能够让项目在开发过程中非常方便,无需额外的开发时间;相对而言,基础组件对于pc和移动端是不同的,pc端如果有使用一些框架如arco-design,这部分就无需额外费力气;而移动端h5主要在于设计规范,有通用的组件库自然是省力气的事情,如果没有,就需要对组件单一的进行列举;常用的基础组件无非就几种 button、dialog、toast、loading、表单类等
      • 基础业务组件:划分基础组件和基础业务组件,其实就是通过其他人能不能用进行区分,比如,基础组件是拿出去后其他人也可以用的,而基础业务组件通常是针对于当前业务功能,而具有特色的展示,其的属性和业务息息相关
  • 业务模块:业务模块设计部分,则是需要根据设计图进行详细划分,看看能否在目前重构业务中找到一些通用的方法
    • 业务通用方法:通常是业务层面使用的方法,比如模块1和模块2都是用了一个处理函数,就可以将方法抽出;一些提交时候参数处理等
    • 业务通用组件:和基础业务通用组件不相同的是,业务通用组件通常是包含了业务逻辑了,只不过两个模块业务逻辑相同,为减少后续开发和维护成本,可以将其抽离出基础业务模块
    • 业务通用hooks:说hooks其实有些偏了,通常我会在hooks中聚合一些通用接口处理,如果某个数据获取等等;主参数接口的数据获取;有些页面可能是用了同一接口和数据,所以相对而言这样处理有利于减少相似的数据获取代码编写
  • 项目其他配置
  • 监控:监控是非常重要的流程,因为监控为我们在项目上线后的流程提供了第一视角查看,如果存在错误,我们能够及时定位并发现;及时止损。
  • 打点:通常是业务层面打点
  • 构建 & 部署: 不同公司的基础建设能力不一样,这里就不过多赘述了,根据公司进行选择即可
  • 灰度:灰度的设计其实是为了让我们项目上线后减少损失,如果用户量级过大,可能会造成较大的资损,因此逐步放量是重要的流程
  • 容灾:有备无患的过程,当项目出现问题时,我们应该怎么处理,这里分优先级的错误,根据优先级不同,处理的方式设计也不同;

技术设计部分是必要的,也是相对比较困难的,因为他需要你站在更全的视角去思考问题,不仅仅是解决于目前代码仓库中的现状,也是从项目本身角度出发,去衡量重构成本和收益是否能够成正比,设计设计过程中去发现问题,找到更好的解决方式
    技术设计本身是一件有趣的事情,因为在这个过程中,你不仅仅可以进行思考技术使用,同时还需要进行技术方法的判断,针对同一个功能实现方式,就有很多种方法,你需要在这个过程中找到最优的方案,这个过程是一个整合思维的过程;按部就班,一步一步来,一个点一个点进行发散,就可以轻松去完成;

重构开发

重构开发的过程是关键点了,基本开发流程就是仓库搭建->基础仓库配置->业务代码开发 image.png 重构开发可能是一个漫长且工作量较大的过程,因此需要进行模块的开发图,详细到具体的组件范围,开发时长等;包括当前开发点的优先级,明确优先级后,能够快速开发重要功能,减少重构进度中的卡点问题;

image.png

重构自测

自测是项目中非常重要的一部分,进行联调前的自测是否全面将直接影响到联调的进度,进入测试时候,自测的全面性会直接/间接影响到测试进度,相对于较为重要项目,有可能某一个卡点问题都会成为阻碍测试的点,严重的情况下可能会影响到整体的项目流程;对于我们而言,自测分为功能测试兼容性测试(仅h5)

功能测试

功能测试相对而言,只要熟悉业务逻辑,其实基本上就能够缕清自测思路,就 ** 相关内容而言;功能测试的重点有3个;

  • 根据业务逻辑,页面数据内容展示是否正确、页面数据是否正确
  • 动态内容:表单校验、每个表单项校验项目,表单提交、有条件按钮展示
  • 对比功能:新功能和老功能的页面对比,单一check(必要流程) 每个重构业务不同,因此选择最适合自己的方向即可; image.png

兼容性测试

兼容性测试分为三个部分,手机机型测试环境(app)app环境(boe/ppe), 其中手机机型测试环境app是必要的前置自测流程,

  • 手机机型: ios 、android(低版本ios/andriod)
  • 测试环境:代码需要兼容的环境app,如内嵌到哪个app中,都需要进行逐一测试
    • 不同主题展示(按钮颜色,弹框的边框类型)
    • 包含了部分功能测试(如birdge使用)
  • 测试环境:根据公司的现有测试计划进行查看;

自测总结

  • 罗列自测case: 列出重点自测内容,为自测规划方向
  • 专一性测试: 明确本次测试重点,如进行
    • 功能测试
      • 此时无需过多关注兼容内容,如有卡点的兼容内容影响功能测试,可马上修改,重新进入功能测试环节
      • 自测时充分借助接口mock工具,模拟各个状态,进行页面展示及按钮功能测试,由于是mock接口,进行表单提交需要check提交数据格式
      • 功能测试,可借助模拟器进行测试,可提高效率;
      • 发现代码逻辑上存在问题,可进行及时改动
    • 兼容性测试(一定要用真机)
      • 可同时打开两个手机,进行ios/android的某个端测试,此时可将mock数据尽量更改到可以查看更多兼容测试部分;
      • 遇到问题,可以先进行记录,然后在逐一解决处理 ,待某个app全部看完后进行一次更改,然后统一回测,减少边测边调时间

分享自己罗列的问题点文档 image.png

  • 双环境测试: 本地启动 + 打包后 用于校验打包后展现形式 完成了这些后,基本上其实自测的就很充分了,希望大家的测试也是一番风顺呀

重构总结

  • 有长远观念 不仅仅是为了现有业务的,更是要有长远观念,保障系统在未来也是可维护性
  • 做正确的事情 要计划设计每个技术点实现,保证大体方向是对的,这样不会事倍功半;
  • 做重要的事情,在文章也是很常见,我的所有问题文档以及规划文档都标注了优先级,其实大项目重构是一件特别繁琐的事情,因此需要进行优先级排序,先做重要且紧急的事情
  • 保持好心态,很重要的一个部分,因为在设计开发中,肯定会遇到各种各样的难题,会变得焦虑烦躁,这个时候保持好心态尤为重要;
  • 善于总结,每个人的成长都不是突然性的,不仅仅在重构,在其他的学习开发中,都要学会总结,追究到底,保持对知识的兴趣;     从重构到上线,经历了大概一个多月,上线完成后,竟然有一段时间的后遗症;比如我在超市买个西瓜,我就会想到我在调试的页面过程中遇到的种种,我逛个淘宝,来回切换页面的时候,都会想到端内容器的webview打开模式之类的;哈哈哈哈哈,后来调整后,慢慢的就从重构的紧张范围中跳出来了。感恩~
    关于重构;推荐给大家一本书吧《重构-改善基友代码的设计(第2版)》个人感觉还挺有意思的嘿嘿