大型网站重构指南 第1部分:定目标、代码评估

753 阅读7分钟

近期 ichati.cn 进行了一轮系统重构,其中涉及了大量的重构技巧,所以我认为很值得写一篇文章对近期一些工作进行总结。

我先承认,这篇文章有一些标题党了。

传统意义上的大型网站,可能需要几十万用户、数千并发。但 ichati.cn 目前并没有这么大的体量。ichati.cn 目前高峰期只有几百并发。所以按照传统意义来评判的话,ichati.cn 最多算做是中型网站。

但这一点小的瑕疵并不影响文章的质量,因为 ichati.cn 的重构工作仍然会按照大型网站的标准来进行。

重构的步骤

我先列举一下我们的计划,因为重构这件事耗费的时间比较久,不是一时半会就能搞定的。它是一件持续性的事情。

所以 8 个步骤只是我们预期的计划,并不是最终结果的复盘。更多会根据实际情况来调整。

  1. 定目标。
  2. 代码评估。
  3. 根据具体工作分析任务量。
  4. 编写足够的测试。
  5. 重构。
  6. 增量迁移。
  7. 复盘与文档。
  8. 持续监测和优化。

接下来我会逐步来讲解每一步。

定目标

我有个朋友在某大厂做总架构师,前段时间离职了。离职原因是带着团队搞重构,结果大家劳心费力花了三个月,QPS 增长了好几个点。但是由于运营团队不给力,用户体量没有任何增长,甚至还略微下降。

他们领导大怒,认为我朋友搞出来的结果对业务增长毫无帮助,甚至是浪费资源、开倒车。把我朋友转岗到另一个部门,给他的前下属当副手,明着穿小鞋。我朋友自持技术水平很高,自然无法忍受这种屈辱,一怒之下离职了。

现在职场的情况大家多少都应该感觉得到,我朋友找工作也是一波三折,最后好不容易找了份工作,薪水却只有上一份工作的 60%。

事后朋友和我们谈论起这件事,仍然不认为自己有错。但我认为他和他领导都有错,但他的错占了大多半。他没有在合适的时候做合适的事。

无论对错,我朋友之所以落得这个境地,是因为他没有明确的目标,或者说他的目标和他领导的目标并不匹配。他的目标可能是想提升系统 30% 的 QPS,而他的领导目标可能是用户增长 30%。

所以,在重构之前,我认为应该首先明确目标。

重构的理由有很多,而这些理由,基本上就是组成目标的重要部分。我简单罗列如下:

  1. 代码质量很差。比如可读性很差、代码过于复杂,导致的后果是改动功能很吃力。
  2. 系统性能很差。比如接口经常无响应,或者慢接口过多,页面打开白屏好几秒。
  3. 系统扩展性很差。比如模块、组件设计不合理,耦合性过高、灵活性很差。新增加功能模块非常吃力。和代码质量很差有些类似,但这点更多是从大的层面上看的。
  4. 技术债务太多。比如因为业务压力大,上线时间紧,采用了很多临时性的技术方案。比如有很多冗余模块、表和字段。比如用了一些不靠谱但勉强能用的第三方库。这对后续功能的开发和系统的维护都会造成负面阻力。

当然重构的理由还不止于此,要根据实际情况进行。

其实我认为重构这件事应该是日常工作之一,而不应该单独拿出时间来做。但是由于各种各样的原因,迫使我们必须单独来做。

必须让大家都看到的我们系统真的很糟糕才行。

比如在老的模块上增加一个小功能,原本需要 3 天,重构后只需要 2 天。

比如原本系统稳定性是 99.1%,重构后可以提升到 99.5%。

比如将代码质量从原来的 40 分做到到 60 分。

比如将 QPS 从原来的 500 做到 1000。

比如将首屏加载从 99% 3 秒提升到 99% 2 秒。

但是一定要和不懂技术的老板或者业务侧老板讲清楚,这些重构工作几乎不会对 PV、UV、DAU、MAU 这些运营数据产生关系。

总之,在定目标阶段,尽可能地把所有的指标进行量化。避免团队的目标不一致性,特别是领导。

当然 ichati.cn 不需要特别量化这些指标,因为我就是 Boss。以上内容更多是根据我过去的工作经验总结出来的教训,相对更加通用。

代码评估

在重构工作之前把整个系统摸透,是非常有必要的。

参与重构的技术人员必须对系统现有的技术架构、技术栈、业务流程非常熟悉。

然后分析出来哪些是烂代码、哪些代码存在潜在隐患、哪些代码是瓶颈和改进点。

因为我们必须对系统足够了解,才能有效地改进系统。

这个过程可以先使用代码静态检查工具对代码进行分析。ichati.cn 的代码主要是 TypeScript,所以可以使用 ESLint 先对代码规范进行检查,修复一些合理的 warn。

然后使用静态分析工具进行更深度的检查,生成更加详细的报告。这里 ichati.cn 使用的是 SonarQube。

再之后使用性能分析工具来对系统进行性能分析。ichati.cn 的后端是使用 Nodejs 开发的,使用了很多个工具配合分析。包括 Nodejs 自带的 Profiler、开源的 OpenTelemetry、Datadog 的 APM 等。前端则主要是 gtmetrix、Lighthouse 以及 WebPageTest。

为什么使用了多种工具来分析呢?原因就在于同一款工具可能会有自身特定的重点功能。使用多个工具,可以更加全面和深度地分析结果。同时还能起到交叉验证的效果。

有了初步的评估后,再通过开会做 CodeReview 和代码审查。

因为各个模块的开发者可能是不同的人,所以大家齐思广议才能尽可能地发现问题和改进点。

这时要把会上讨论出来的问题进行归纳总结。并针对各个问题进行更深度地分析。最后能够产出一份类似重构指南或者最佳实践的文档。

因为同样的问题,可能每个开发者都有自己的解决思路和方式。我们应该统一系统的实现。这样可以提高整体的代码质量。比如处理时间的格式化,有人喜欢用 moment.js,有人喜欢用 dayjs。比如数据库字段名,有人喜欢用 xxxflag、有人喜欢用 isxxx。有人喜欢用 try catch 块来捕获错误,有人喜欢返回错误码或者错误对象。

总之,系统的各个开发环节,都有无数的细节和决策,会因为每个人的偏好和经验而产生分歧。重构指南的作用就是规范和统一这些细节。

在一些大厂都会有相应的规范,比如 Google 有 《Google Java Style Guide》、《Google JavaScript Style Guide》;Microsoft 有 《Microsoft C# Coding Conventions》、《Microsoft TypeScript Coding Guidelines》;阿里就有《阿里巴巴 Java 开发手册》;腾讯有 secguide。

不过像我们 ichati.cn 这种小团队,就没有这么多技术积累和最佳实践了。但我们也会尽量用一些方式来促进技术的积累和最佳实践的制定。比如直接采用开源项目的规范进行适当的二次改造,并在实际落地的时候根据实际情况进行持续改进和反思。

篇幅所限,本文暂时结束。

后面会持续更新。

写文章这事儿其实和重构是类似的,很难一次性到位,而是持续工作、循序渐进。