重构「屎山」?你可能永远也不该做这件事!

8,311 阅读7分钟

前言

在不久的过去,我在知乎看到这样一句话:「 驾驭屎山的唯一方法,不是重构,而是 不重构 」 。
我觉得说的很有道理。但并没有将它当作准则,还是进行了整个项目完全重构的操作。

重构

重构起因

最终我还是决定重构,重构的原因基于以下几个方面。
原因有四:

  1. 领导的支持,愿意为此付出成本,且付出时间
  2. 该项目由 项目A 完全 copy项目B ,且 项目B 只用到了 项目A1/4 的功能
  3. 该项目与其他项目使用 技术栈 差异过大,导致无法统一相同类型项目的 项目架构
  4. 该项目在 新增/修改 功能时,由于代码过于古老,导致十分痛苦

重构过程

其实准确的说并不应该说是重构「屎山」,更像是重写「屎山」。

  • 将需要的页面整理,拆解成一个个任务。
  • 将整个项目底层重新搭建,摒弃未引入的库,重写了路由、请求封装、utils工具、文件结构、代理、 ....
  • 将一个个页面通过新框架重写

重构上线

待到整个项目重构完成,上线时。出问题了 emmm.... 问题列表:

  1. 有一个已经被引用的页面未整理到,导致该页面无了
  2. 有一个页面 title 写了个错别字(续 写成了 绪)
  3. 有一个页面的数据请求接口,应该是 GET ,且我也发送了 GET 请求,但旧代码请求类型是 POST 导致接口请求失败 PS:在 问题3 出现之前,我就遇到了本该是 POST 的接口请求类型是 GET 的问题。但万万没想到 GET 类型会出现 POST 接口请求。

遇到 问题1 时,我尽快将页面加上
遇到 问题2 时,抓紧调整错别字
遇到 问题3 时,我抓紧改掉了
但出了这么多问题,如果有更严重的问题系统是无法接受的,我果断回滚了代码

我现在便卡在了这里,问题都解决了但不敢上线了,因为 问题3 的页面我实际上在测试环境请求过很多次,没有出现该问题。我担心会有其他未测出的 bug。

我对问题本身并不关心,最关心的是为什么出现了问题后,我不敢上线了。
最后总结出以下几条:

  1. 领导希望的是项目不出现任何问题的情况下 无缝切换
  2. 产品已经在线上 平稳运行 ,如果重构出现任何问题,都难以接受
  3. 相较于新产品而言,用户对 bug 的乍现容忍度更低
  4. 没有测试
  5. 没有分步上线,进而导致问题的集中爆发

总结

为了保证我们的重构 没有惊喜 的完成,我们需要清楚以下问题:

  • 是否需要重构?
  • 为什么要重构?
  • 应该如何重构?

是否需要重构

如果早明白这个道理,我一定不会贸然重构!!

if (项目过于庞大) {
    return 千万不要重构!!
}

if (大块的代码你搞不明白是做什么用的) {
    return 千万不要重构!!
}

if (你在该公司待不到 1 年) {
    return 不需要重构
}

if (你们需要为 KPI 服务 && 重构对 KPI 无益) {
    return 不需要重构
}

if (你的领导不希望你重构) {
    return 不需要重构
}

return 你大概率不需要重构

大多数情况下,普通开发者不要考虑重构的问题。
当你在考虑重构问题时,你应该慎重考虑以下几方面:

  • 对公司是否有益
    • 大多数情况下,重构对公司的益处都是不大的,因为难以保证由 「屎山1.0」 进步成 「屎山2.0」
  • 对自身是否有益
    • 大多数情况下,重构所带来的收益远远不如拿出该时间 学习新知识巩固旧知识
  • 成本和收益是否成正比
    • 大多数情况下,重构的成本和收益是不成正比的
  • 如何保证后续的效果
    • 提前指定规范,并保证 重构过程中 + 后续维护中 严格遵守规范中的规定

为什么要重构

当一个系统在线上稳步运行时,重构总需要有充分的理由,这个理由不能是 "为了扩展性、维护性" ,大规模重构消耗掉的资源不是短短这么两个短句就可以支撑的。
你至少要保证对以下几点中的一点严重不足时,才考虑这件事:

  • 性能不足
    • 现有的代码不能在线上平稳运行,不能保证用户的体验
  • 扩展能力
    • 现有的代码基本无法扩展,在新需求来临时,难以完成
  • 维护成本
    • 现有代码在维护上有致命的缺陷,导致你们团队对重构的需求激增

否则:

  • 在重构前,其他人无法准确预估你的工作量
  • 在重构时,其他人在出现问题后没办法接受
  • 在重构后,其他人察觉不到重构带来的好处 且:
  • KPI 玩完

应该如何重构

在重构一个已经在 平稳运行 的项目,我们不能将一段时间完全留给重构,重构应该和 业务需求 平步进行,且 业务需求 在前,研发需求 在后。

我们重构至少遵循以下原则:
在重构前,保证项目兼容性、保证对代码的充分理解、保证对任务的拆分、保证规范的确立;
在重构中,保证不影响 业务需求 开发、保证分步上线;
在重构后,保证测试完整覆盖、保证严格按照规范进行维护。

这些都是为了我们的重构过程中不出现 惊喜 ,这里的 惊喜 是中性词,你的重构过程中不应该出现任何 惊喜 ,无论好坏。

重构前

在项目重构前,我们必须:

  • 为了保证项目重构后的 兼容性 进行调研
  • 为了保证项目重构后的 稳步运行 进行深度代码阅读
  • 为了保证项目时效,对 重构时间 进行准确的预估
  • 对重构的上线过程模块规模细化,避免一次上线模块过多、过少
  • 制定好重构后的项目的 编码规范
  • 准备好 新域名、新仓库 ,方便项目分步上线

重构中

在项目重构中,我们必须:

  • 保证重构前后页面的一致性、功能的一致性
  • 合理安排好时间,保证不影响业务需求开发
  • 做好单元测试
  • 分步上线
  • 做好线上测试

重构后

在项目重构后,我们必须:

  • 保证测试的完整覆盖,避免出现未测试的代码,出现令人惊喜的 bug
  • 针对制定好的 规范 进行项目的维护,避免从 「屎山1.0」 进步成 「屎山2.0」

总结

本次重构出现的问题算是比较经典的问题,代表了在重构整个项目的生命周期中出现的典型问题。

问题1:不必要的重构

本次重构说到底还是一次不必要的重构,重构的结局是没有收获任何好处,反而得到了一堆问题。
隐性的好处是:

  • 在后续的更新中,可以统一的抽离出同一场景下用到的相同内容至 npm
  • 在新的前端同学入职后,可以更快的上手这一场景下的所有项目

问题2:采用全部写完一次性上线的方式进行

全部写完一次性上线的好处是:

  • 不需要一个新的域名、新的仓库进行中间替换 缺点是:
  • 导致每个模块的测试不够细致,从而忽略掉了部分问题
  • 导致问题大规模爆发,从而导致情绪波动,从而引发连锁反应

问题3:模块缺失

对已用模块收集不够细致,从而导致上线时模块缺失

问题4:页面了解不够

由于对页面了解不够深入,导致测试时,漏掉部分后台入口,从而导致问题的发生。