点击上方 前端瓶子君,关注公众号

回复算法,加入前端编程面试算法每日一题群

来源:ES2049 / 黑石

https://juejin.cn/post/6951373058544730125

代码重构有两大难点,一个是「考古」,也就是如何快速梳理出代码的原有逻辑,还有一点就是「发布」,如何让新的代码可以稳定的发布到线上,而不产生故障。下面我们就聊聊我一个朋友的故事,看看他是怎么把代码稳定搞上线的。为了表达更为亲切,你现在就是我那个朋友。

重构代码对很多人来说,绝对是一件脏活、累活。没有可以大幅度提效的方法,难以沉淀有效的体系化的可复用的技术抓手,对业务来说没有明显的增量,精力和时间消耗巨大,没有测试用例,也不一定能得到测试的支持,自测很难做到充分,最后开发完了很难上线,主要原因是害怕!当然并不是我们不自信,是真的恐惧。

一、你为什么不敢发代码?

通过代码还原当时完整的产品逻辑太难了

你重构的代码是谁的?鬼知道是谁的!能让你重构的代码大概率不是你写的代码,而且是远古代码,用的是一种过时的技术栈。当然一般情况下,当年的开发、测试、甚至产品早已不见了踪迹,只能在注释的代码里看见了了数语。言语中透露着无奈,用一个程序员的良心提醒着后来人,「小心前面的脏东西」。看了这些话,你只能收回口中马上要吐出的芬芳,默默离开工位,倒点热水。

image.png

image.png

image.png

从此你会发现,注释不仅能够帮你读懂代码,还能有警示作用,告诉你重构代码的同时,记得把 bug 一并改了。你想要通过注释来梳理出原始需求的愿望宣告失败,接下来你只能死磕了,祈祷千万不要漏掉业务逻辑。

没有自测用例

别以为大公司制度完善,测试都有完整的测试用例,现实会狠狠的夹你脑门。频繁的迭代,功能早已面目全非,老的用例根本不可用,更何况根本找不到老的测试用例。没有用例怎么自测呢?全靠个人想象。

没有测试同学跟进

多一个人多一分力量,让一个有经验的测试参与到功能回归中来,无疑会给你的重构事业吃上定心丸,但真实的情况是,测试同学根本不想参与这种脏活累活。他自己手里的需求还测不过来,怎么会把时间奉献给一个前端发起的重构工作上呢。无增量,无抓手,纯体力,他们同样心知肚明。

没有稳定发布方案

在没有上述保障的前提下,如果你还能硬着头皮上线,就会遇到更大的难题,如何上线?直接全量替换吗?如果线上出问题怎么办?好在前端的回滚是非常迅速的,但是即使再迅速的回滚,从发布完成到发现问题回滚,在提醒用户重新刷新页面,这个过程也足以造成难以估量的后果,尤其是那些高频使用,且极易产生脏数据的场景。这就是没有一个有效的发布方案所导致的常见后果,这个后果还有可能导致你背上故障,这一年加过的班,熬过的夜,掉的头发,什么也换不来,只能催生你换个地方重新做人的念头。

综上因素直接导致开发者极度缺乏安全感,一个不敢上线自己代码的程序员,就像半夜被自己一个月大孩子的哭声吵醒,那时那刻你只想装死摸鱼。更何况你的工作往往不是只有重构这一件事,写写新需求他不香吗?就这样你眼看着一个页面重构了两个星期,迟迟不能收尾,你变得越来越不自信,越来越害怕了起来,不敢面对那些重构了一半的代码,开始恐惧老板的问题:「重构搞的怎么样了?」,你简直不像个程序员。

终于到了年底,你的重构事业还未完成,更可怕的是,这件事还被打上了「承诺型」OKR 的标,于是你痛定思痛,做了个梦。

时间回到年初你刚刚接到重构任务的时候。

二、寻求组织保障

你的重构工作是把 177 个 jQuery 页面用 React 重写一遍。你立马想到,自己一个人一年时间,一定是做不完的,此时此刻,切记不要满口答应,一定实事求是,甚至向着最坏的方向想,让老板充分认识到这项任务的艰巨性,不要抱有太高的期望。最重要的是保证人力的投入,必须有更多的同学一起参与进来,有效的分工才有可能完成这项艰巨的任务。有人参与进来,也只是基础,因为他们极有可能会像上面描述的一样,从兴致勃勃到唯唯诺诺,因此一定要确保时间的投入,必要时把老板也拉进来跟你一起做,老板一旦参与进来,就会更有体感,能体会到大家的不易。接下来,就应了那就老话,「别忘了,你是一个 owner!」做好基础设施建设,让每个同学有趁手的工具,有安全的保障,去除他们的后顾之忧至关重要。因此,你要做下面几件事。

三、划分重构页面优先级

你通过细致的研究发现,这些页面中,有 77 个页面是用户使用较多的页面,也是相对比较复杂的页面,剩下的 100 个页面,大部分是给开发用的增删改查页面,用户的使用频率不高。于是你做了如下划分: 优先级划分好优先级以后,就要对不同优先级的页面使用不同的稳定发布策略。

  • 复杂高频页面:重兵压上,细致还原原始需求,抠代码,拉测试同学一起整理测试用例,按照测试用例自测,测试同学回归所有功能。但其实这部分页面中,也可以分为两种页面:

    • 编辑页面:这样的页面是风险最高的页面,一旦因为后端接口没有做完整的数据校验,就会编辑出脏数据,或者错误的数据被保存,导致线上运行异常,这种后果将是不堪设想的,即使非常短的时间内回滚,也会造成难以挽回的故障,因此必须要像新需求一样测试到位。

    • 展示页面:这样的页面不会影响运行时,不会产生脏数据,是风险相对低一点点的页面,本着不麻烦合作方的原则,毕竟资源有限,可以让测试帮你出完整的用例,然后你自己自测,或者多找几个同学帮你自测。

  • 高频简单页面:自测,当然最好是能绑架几个经常用这个功能的开发,来帮你点点,但是自己测总是会有可能会有遗漏,因此就需要下面的步骤来保证了。

  • 低频运维页面:选择性重构,因为很多页面基本上不会有迭代,且使用频率较低,基本上不需要重构,即使是有新的需求,也可以在做新需求的时候顺便重构下,以为并不能占用太多时间。

将页面划分完毕后,你会发现重构的工作量降低了很多,因为本着「无需求,勿变更」的原则,很多页面都可以不需要重构。且上述重构完的页面都必须做灰度发布。

四、单测

前端不太喜欢写单测,你大概总结了一下,主要有下面几方面的原因:

  • 当下的收益不高。

  • 相比后端接口的单测,前端单测写起来相对复杂。

  • 前端更多是面向 UI 的编程,但 UI 变动大,难以使用 TDD (测试驱动开发) 的开发模式。

  • 没有写单测的习惯,可能是因为单测增加了工作量,且没有写纯函数的意识,不利于测试。

  • 单测的工具难学又难用。

你发现前端不喜欢写单测,有各种各样的原因,但是当你重构那些复杂页面,尤其是 jQuery 技术栈重构为 React 技术栈的时候,单测真的非常有用。 比如这里有一个编辑页面,包含两部分:基本信息和运行逻辑,在重构运行逻辑时候,你首先要保证的是重构过后的页面在保存的时候,保存的数据结构必须跟之前的接口参数必须一致,所以在重构运行逻辑这个组件的时候就会有很多数据转换逻辑。 可以看到为了保证你的新组件不影响保持原有功能,就要保证原始数据通过新组件的一顿操作最终保留了原来的结构,此时你就可以写单测来保证这个过程。

describe('utils', () => {it('流程图:转换为提交的数据 transformForm', () => {const result = transformForm(canvasData);expect(result).toEqual(settingData);});it('流程图:转换为需要的数据 parseRuleSetData', () => {const [result] = parseRuleSetData(settingData, rules);expect(result).toEqual(canvasData);});it('流程图:反复转换 transformForm - parseRuleSetData', () => {const [result] = parseRuleSetData(visualSettings, rulesData);const newResult = transformForm(result);expect(newResult).toEqual(visualSettings);});
});
复制代码

前端单元测试写起来复杂,其实只是 UI 的单测复杂而已,如果你把代码做好了足够的拆分,拆出更多函数,更多 hooks ,单测就是轻而易举了。

五、测试用例

你在的团队,一直测试资源都不是充足,测试用例似乎一直都是一种可遇不可求的东西,尤其是在敏捷开发的趋势下,产品功能变动快,很少有测试会一直去维护那个最初的测试用例,往往是写过用过就再也找不到了。但测试用例在重构这个场景下,真的非常重要,他解决的核心问题是把测试同学拉到重构的质量保障中,一起梳理老的逻辑。这份宝贵的测试用例,可以成为你自测的依据,也可以为你提供对于同一个功能的不同视角,如果你通过代码看到的是实现细节的逻辑,那测试看到的就是整个链路的流程图。很多中后台系统都有管理态和运行态之分,管理态,前端是非常熟悉的,但是运行态,测试往往更加熟悉。

六、自测

拿到测试用例,你就可以自测了,但是这里有个坑,就是如果你完全依赖测试同学给你的测试用例。只要保证测试用例验证通过就行了,这种想法会出大问题,因为负责这块功能的测试可能是个新手,可能并不是一直负责这块功能的测试,他们的测试用例可能只是浮于表面的。所以你需要把通过代码考古发现的测试用例里没有的逻辑,暴露给测试同学,并补充到测试用例里。并且如果发现有一些看不懂的逻辑,就应该搞懂他,那些你不懂的死角,往往上线后就会有大问题,不要心存侥幸。自测非常重要,但是往往你会觉得开发完了,就算是把这个事做完了,然后就去忙别的事了,并没有好好的自测,心想还有测试呢,等他们提问题,我再改吧。这是一种很普遍的程序员心理,其实很难避免,毕竟事情有很多。这个时候你可以找同组的开发同学帮你点一点,先解决那些显而易见的问题,也算是一个认真负责的程序员了,不要让测试同学给你提太多低级 bug。

七、回归测试

能有测试同学帮你做功能的回归测试真是一件可遇而不可求的事,一定要珍惜,拿出你的大块时间配合好。这其中最重要的就是多交流,测试同学也不一定知道所有的逻辑,在做回归测试的时候,就需要开发和测试反复核对每个逻辑死角,弄清楚,才敢上线。当然,能够有测试帮你回归的功能都是极易引起故障的功能,这里就有一个技巧就是如何拉测试参与你的重构中来。像这样重要的功能如果测试知道里面的逻辑,你可以怀着请教的心态去问对方,如果对方并不了解,那你就可以讲给他听,一个负责任的测试,应该都非常想了解自己负责系统的重要模块的来龙去脉。

八、灰度发布

即使你做了再多的测试,都有可能有没有考虑到的遗漏点,这个时候灰度就非常重要了,灰度就必须要有灰度工具才行。重构一般是以页面或者区块为粒度按照人来进行的。所以你的灰度工具必须要包含这些功能:

  • 配置用户或者用户组

  • 配置老路由和新路由

  • 配置灰度状态提示

  • 新老页面的自动打点

灰度配置页面,新老动态路由的参数需要保持一致,这样才能把参数传递下去。 展示灰度提示,并提供一个快速「返回旧版」的按钮,为了更快速解决问题,可以给出开发者联系方式。 当用户访问老路由的时候,按照灰度配置验证当前用户是否在灰度中,如果在灰度中,则立即跳转到新的路由,并显示灰度提示。如果重构的是页面中的区块,则可以提供灰度命中的方法,在页面调用区块的部分做判断。

灰度策略可以按照以下用户级别分布进行:

  • L1:所有项目开发,测试,设计师,内部运营人员

  • L2:核心用户,建立钉钉群,观察用户反馈,及时解决用户问题。

  • L3:适当加入更多用户,直到全量后,删除灰度策略的配置。

发布后,注意观察打点数据:

image.png

打点的时候需要注意,要按照动态路由来打点,并分成命中灰度的,点击使用旧版的,不在灰度内的三个维度来看数据,同时每天调整灰度用户,这样就能保证页面是有人用的。如果有很多用户使用了返回旧版的功能,那你就得找找这些用户了解下情况了,到底是有 bug 还是交互不舒服,一对一的解决用户问题,在反复去优化你的页面,慢慢扩大用户灰度范围,直到老的路由访问数据 PV 为 0。

九、全量上线

全量上线并不是灰度所有人,而是真正下线老的页面,并删除老的代码,只有到这一步才算重构完成了。

十、总结

经历千难万险,你终于把重构好的页面上线了,经历了这个过程,感慨良多,只求以后再也不要做重构了,好好做需求不香吗?后头看看整个过程,要想重构的页面上线,不仅要下苦功夫,还要克服人性的一些弱点,要做到这几点:

  • Double Check:让其他人参与进来,多一个人就能帮你发现更多问题。重构面前,不要相信自己,相信伙伴。

  • 逻辑无死角:不要还有不懂的代码,不清楚的逻辑,按照程序员的第六感,不确定的都会出大问题。

  • 集中注意力:重构不能碎片化进行,要集中大块时间来做,并一做到底,不然过个几天,你自己的代码都会不认识。

  • 一跟到底:开发完成不是重点,全量上线,并下掉老的页面才是结束。

致敬每一位重构路上的勇士。

最后

欢迎关注【前端瓶子君】✿✿ヽ(°▽°)ノ✿

回复「算法」,加入前端编程源码算法群,每日一道面试题(工作日),第二天瓶子君都会很认真的解答哟!

回复「交流」,吹吹水、聊聊技术、吐吐槽!

回复「阅读」,每日刷刷高质量好文!

如果这篇文章对你有帮助,「在看」是最大的支持

》》面试官也在看的算法资料《《

“在看和转发”就是最大的支持

你为什么不敢重构代码?相关推荐

  1. 领导让我重构代码_领导不是由代码构成

    领导让我重构代码 The team leader is a key figure in a team of developers. It is a difficult role, involving ...

  2. Winform打砖块游戏制作step by step第5节---重构代码,利用继承多态

    一 引子 为了让更多的编程初学者,轻松愉快地掌握面向对象的思考方法,对象继承和多态的妙用,故推出此系列随笔,还望大家多多支持. 二 本节内容---重构代码,利用继承多态 1. 主界面截图如下: 2.  ...

  3. 设计模式重构代码_Duplicated Code (重复代码)如何处理?

    不知道大家在使用 Idea 开发工具有没有使用 Alibaba Java Coding Guidelines 插件,阿里巴巴基于<阿里巴巴 Java 开发规约>手册内容,研发了一套自动化的 ...

  4. 你为什么不敢重构代码?听高手亲授秘笈!

    任何一个傻瓜都可以写出计算机可以理解的代码,唯有写出人类容易理解的代码,才是优秀的程序员. --Martin Fowler <重构> 面对运行缓慢的老系统:前任程序员遗留下乱成一团的代码块 ...

  5. 重构代码的tricks

    js的设计模式是针对于整体代码的设计是否合理,给出了一些具体的解决办法. 而重构代码就是依赖于设计模式而实现的一个必要手段,可以说设计模式就是重构代码的目标,但他的手段却不仅仅只有设计模式这些大而全的 ...

  6. Android仿人人客户端(v5.7.1)——Auth授权认证(整理流程,重构代码)

    转载请标明出处:http://blog.csdn.net/android_ls/article/details/8748901 声明:关于仿人人项目,我是边看人人官方提供的API,边思考,整理好思路, ...

  7. 码妞:领导让我重构代码,怎么办?

    码个蛋(codeegg)第 645 次推文 作者:akiyama 博客:https://juejin.im/post/5ccecb006fb9a0322758cd22 什么时候进行重构? 任何时间都可 ...

  8. Ta-Lib源码解析(三):蜡烛图指标 (Candlestick Indicator) #(附Python重构代码和示意图)(补充中)

    TA_Lib指标目录 3.(蜡烛图指标)Candlestick Indicator 一. 前言 二. 单K线模型 CDLBELTHOLD(捉腰带线) CDLCLOSINGMARUBOZU (收盘缺影线 ...

  9. 简易的动物园管理系统之Java8流式API的重构代码(使用 门面设计模式)

    文章目录 前言 之前的文章 本次的源码 AnimalTypeEnum SexEnum Animal AnimalFactory BaseAnimal Bird Cat Dog Fish AddAnim ...

最新文章

  1. wordpress中文乱码处理方法
  2. 用TensorFlow基于神经网络实现井字棋(含代码)
  3. c++学习笔记之多文件操作
  4. 【ES6专栏】全面解析ECMAScript 6模块系统
  5. 2021-09-30
  6. 使用CAtlRegExp正则表达式检查浮点数输入
  7. 交换二叉树中所有结点的左右子树的位置
  8. 雨滴桌面时间插件_真香!这 3 款软件,让你的电脑桌面清爽又高效!
  9. Day5 - 前端高频面试题之计算机网络相关
  10. Notepad++查看、编辑二进制文件——安装附加组件HexEditor实现
  11. 我的Delphi开发经验谈(本人修改版) 收藏
  12. 桌面计算机里没有桌面显示不出来怎么办,电脑桌面显示不出来图标 所有软件都可以正常工作 怎么解决?...
  13. Tenorshare UltData(苹果数据恢复软件)v8.5.3官方版
  14. SAS数据步与过程步,数据步语句
  15. 如何安装OpenCVE
  16. dedecms织梦后台不显示模块管理和辅助插件
  17. c语言普及组复赛题目大全,NOIP 2016普及组复赛C/C++详细题解报告
  18. 前端学习从入门到高级全程记录之12 (CSS高级技巧)
  19. 雅思作文未来计算机的应用,雅思写作大作文范文 雅思写作讨论双方观点 人工智能artificial intelligence...
  20. 2017年度个人计划

热门文章

  1. cart细胞高效制备流程
  2. python远程使用ants中的配准命令和N4biasfiledcorrection注意点
  3. 队列详解及java实现
  4. ORA-01858 :在要求输入数字处找到非数字字符
  5. Swift 替换字符串
  6. python-点击消除
  7. Win10 20H1及以上文件误删恢复
  8. ios safari 开启无痕浏览(隐私模式)报QuotaExceededError: DOM Exception 22异常解决办法...
  9. java获取空气质量在线监测分析平台(PM2.5真气网)数据
  10. GitChat·前端 | 从软件工程角度看大前端技术栈