602743bb8cf6c84d3dd03dc1f0732ee7.gif

【编者按】本文主要分享一些开发者在软件开发行业中遇到的复杂代码库所带来的问题和挑战。本文列举了造成复杂代码库的常见原因:过分抽象、过度通用化、虚假的测试覆盖、对过时技术的过度热衷、缺乏架构设计、缺少代码版本控制等。文章还强调了管理层对复杂代码块问题重视的重要性,并指出这些复杂代码库会随着时间的推移变得越来越庞大,需要更多的开发人员来处理。

原文链接:https://digma.ai/blog/coding-horrors-complex-codebase/

未经允许,禁止转载!

作者 | Roni Dover       译者 | 明明如月

责编 | 夏萌

出品 | CSDN(ID:CSDNnews)

037d3f35ef99212206aa1ded8986eceb.png

图源:https://digma.ai/

如果你在软件开发行业工作过一段时间,那么你可能已经遭遇过一些使你心生恐惧、感到沮丧、甚至无法面对的复杂代码库。这些复杂的代码库可能是一团散乱的代码,也可能是一个充满复杂依赖关系、测试覆盖率低的庞大单体应用。本文我们将深入讨论造成难以维护的代码库的一些常见原因。

请准备好一杯咖啡,代码恐怖故事即将开讲。


ebca00408772e38a9193cfa01ada5579.png

过分抽象增加代码库的复杂性

你是否听过这句话,“没有什么问题是添加一层抽象解决不了的”?我们很容易就会觉得,将代码整理为清晰的层次结构,就能让所有东西看起来井然有序、清晰明了。理想很丰满但是现实很骨感,在实际应用中,情况往往很快就会失控。抽象层开始渗透、堆叠,隐藏了你实际需要关注的重要代码部分。不知不觉中,你会发现原本只是一个简单的调试任务,变成了在类和对象迷宫中追逐幽灵的疯狂之旅。Reddit 用户 Zoozla 分享了他在一款大型 Java 单体应用中的工作经历。这款应用是一家银行用于货币交易的外汇系统的组成部分。这个复杂的代码库中,有一个令人眼花缭乱的 8 层抽象类结构,底层只有一个实际的类。它还包含了一个几乎具备图灵完备性的 XML 语言,用于解析遗留的二进制文件。更为糟糕的是,运行单元测试会对开发数据库进行修改,每次运行后都需要手动重新填充数据。Zoozla 花了数月时间试图重构代码中最糟糕的部分,但收效甚微。


152bb6f2197ff3d85db1b622546df050.png

过度通用代码让代码库难以维护

有时候,即使出发点是好的,结果也可能带来意料之外的负面影响。当开发者试图创建一个完美且灵活的软件时,这种情况就会经常发生。他们一头扎进复杂的抽象和依赖关系中,自以为正在创建一种真正具有适应性的东西。但在他们察觉之前,他们已陷入了一团乱麻的代码中,哪怕只是最微小的变化也会令人感到极度困扰。

用户 Shnorkylutyun 分享了他在 Java 应用中处理嵌套泛型和众多基类型包装器的经历。这个应用中存在各种类型的包装器和包装器之间的映射,以及描述具有 10 多个字段的通用形式的泛型类,每个字段的类型都有单独的泛型。而最多含有 6 种泛型类型的表单向导更是增加了混乱程度。如果一个表单中两个字段的顺序成功地被重新排序,而且它们都是字符串,那么这将是个值得庆祝的小确幸。


21ac018e77e1608d642774f084898997.png

对过时技术的过度热衷带来额外的复杂性

你可能听过这句话:“人往往会用自己熟悉的方法去处理问题”。在 90 年代末,有一群开发者如此迷恋 Smalltalk,以至于他们不惜将其概念强行适配到一个 C 语言应用程序中。结果,他们创造了一个令人眼花缭乱的复杂代码库,这个代码库依赖于文本字符串的发送处理,而不是传统的函数调用。再加上庞大的源文件和对 PostgreSQL 的奇特运用,你就得到了一份让人头痛不已的代码库。

Reddit 用户 Json-123 分享了他在 90 年代末为 Solaris 编写的一个 500 万行 C 语言应用程序的经历。原开发者试图通过发送文本字符串进行处理来在 C 中模拟 Smalltalk。这个复杂的代码库中,有一个超过 15 万行代码的庞大源文件,这使得许多 IDE 难以承受。更令人头疼的是,该应用程序将 PostgreSQL 当做一种复杂的文件锁定机制来处理 flat 文件(一种没有对应的关系结构的文件),而并非把数据迁移到数据表中。


18b33ce3f1a774edfb34937ede233ed2.png

交付压力导致虚假测试覆盖率

在压力、挫败感不断累积,以及对误导管理层的怨恨加剧的情况下,开发者可能会对代码库进行一些出乎意料的改动。相比精心设计的解决方案,交付压力可能导致了一些不寻常甚至怪诞的结果。

a6efd117460a06c4b9bd5b5a37af92ac.png

以 Reddit 用户 Aceluby 的经历为例,他曾经维护过一个 Java 应用程序,虽然在测试中达到了惊人的 99% 代码覆盖率,但是竟然一个断言也没有!测试仅仅检查代码是否会抛出异常,对代码的正确性几乎没有任何保障。维护这样的代码库是一项具有挑战性的任务。但,正是因为这种挫败感和压力,才会促使开发人员去解决问题并改进代码质量。


d96f02804bfc0df76ea3cc674bf44b31.png

缺乏架构设计造成野蛮生长

你是否有过这样的经历,走进一个房间,东西堆满了每一个角落,你却找不到自己需要的东西。这就是深入一个多年来无人管理、任其发展的代码库所带来的感觉。没有人驾驶这艘船,它就变成了一个充满曲折小径的迷宫,所有的路径看起来都一模一样。

679d300a3e6bcdb62e417b149ca6e6d7.pngReddit 用户 Zasch 描述了一个包含大约 570 个模块的项目,甚至有一些“测试模块”仅用于测试其他模块。这个单体代码库在没有架构师的情况下已经发展了 20 年,每个在项目上工作的人都在努力理解它。调试这个项目的代码如同噩梦一样,将整个代码库导入 IDE 会导致 IDE 卡死。唯一值得庆祝的进步就是项目成功升级到 Maven 3 和 Java 8。


87df72e089258b059ee92d96848ee791.png

在没有版本控制的情况下狂奔

有时,有些开发者的行为让人难以理解。他们的有些行为似乎让人怀疑他们是否适合编程。

Reddit 用户 fuseboy 分享了一个关于使用 Java Swing 构建复杂触摸屏应用的故事,其中的代码可谓是面条代码的经典示例。代码库中缺乏封装、分层和接口设计,变量被设置为公开状态,以便更方便地在类之间共享数据。更为惊人的是,竟然没有构建流程。开发者在命令行中私自构建他们的类,然后通过电子邮件将结果发送给技术负责人。


b7a6601e56c18aac86d76b596f4664b1.png

面对复杂的代码库,我们的未来充满了挑战

这些令人恐怖的复杂代码库比我们想象得要常见的多。当开发者被派去维护它们时,就如同被交到一张没有出口的迷宫地图。

我们当然有一些工具和方法论可以提供帮助,如静态代码分析器和重构工具,但面对如此复杂和庞大的代码库,它们往往力不从心。

更糟糕的是,当管理层未能认识到问题的严重性,或者简单地将短期目标置于长期可维护性之上时,对于那些已经在努力处理这些复杂代码库的开发者来说,这无疑是灾难性的。

并且,这些企业级的代码库随着时间的推移,只会变得越来越庞大。这些复杂的代码库需要更多的开发人员来处理,重写代码并不能轻易解决问题,反而可能导致更多的问题产生。

本文是“代码恐怖故事”系列第一篇。该系列的第二篇文章:《代码恐怖故事:解密隐藏在复杂代码库中的恐怖秘密》也将会在不久发布,敬请关注。

大多数开发者都有自己独特的故事。你是否也曾亲历过一些“代码恐怖故事”?欢迎在留言区分享讨论。

推荐阅读:

▶腾讯回应与Meta VR头显合作传闻;美国考虑限制中国用户使用美国云计算服务;ChatGPT暂停联网测试|极客头条

“盗窃”而来的 3000 亿单词?ChatGPT 摊上事了,遭索赔 30 亿美元!

▶QQ 用 Electron 重构后,终实现 Linux、macOS、Windows 三端架构统一!

Logo

一座年轻的奋斗人之城,一个温馨的开发者之家。在这里,代码改变人生,开发创造未来!

更多推荐