Analyzing Dependency Distribution Changes Arising from Code Smell Interactions

本研究通过对 116 个开源 Java 系统的实证分析,揭示了代码异味交互会显著改变静态依赖分布(通常导致依赖增加),从而为更精准的异味检测、优先级排序及重构策略提供了依据。

Zushuai Zhang, Elliott Wen, Ewan Tempero

发布于 2026-03-05
📖 1 分钟阅读☕ 轻松阅读

Each language version is independently generated for its own context, not a direct translation.

这篇论文就像是在给软件代码做一次“体检”,专门研究当代码里出现多个“坏习惯”(代码异味)互相勾结时,会对软件结构造成什么破坏。

为了让你更容易理解,我们可以把软件开发想象成经营一家大型餐厅

1. 核心概念:什么是“代码异味”?

在餐厅里,如果某个厨师(代码模块)总是把别人的活抢过来干,或者把厨房搞得乱七八糟,这就叫“代码异味”。

  • Feature Envy(羡慕嫉妒恨):就像厨师 A 总是跑到厨师 B 的灶台上去炒菜,而不是在自己的灶台上做。
  • God Class(上帝类):就像有一个超级大厨,他不仅炒菜,还负责点菜、收银、甚至打扫卫生,什么活都他干。
  • Data Class(数据类):就像一个只会端盘子的服务员,只负责把菜端出去,自己不会做任何加工。

2. 研究的核心问题:当“坏习惯”抱团时

以前的研究主要看单个坏习惯(比如只看那个抢活干的厨师)。但这篇论文发现,当两个或多个坏习惯凑在一起“勾肩搭背”时,情况会变得更糟。

这就好比:

  • 如果只有一个厨师乱跑,可能只是效率低一点。
  • 但如果“乱跑的厨师”(Feature Envy)专门去依赖那个“只会端盘子的服务员”(Data Class),他们俩就会形成一种奇怪的依赖关系

这篇论文问了一个关键问题: 当这些“坏习惯”互相依赖时,它们之间的连线(依赖关系) 是变多了还是变少了?这些连线是不是让餐厅(软件)变得更难管理了?

3. 研究方法:数了 116 家餐厅的“连线”

研究人员像侦探一样,检查了 GitHub 上 116 个开源的 Java 软件项目(相当于 116 家不同的餐厅)。
他们把代码里的“坏习惯”找出来,然后统计:

  • 情况 A:两个“坏习惯”互相依赖(比如乱跑的厨师依赖端盘子的服务员)。
  • 情况 B:一个“坏习惯”依赖一个“正常”的模块。

然后,他们对比这两种情况下,模块之间连线的数量。

4. 主要发现:勾结让混乱加倍

研究结果非常直观,可以用三个比喻来总结:

发现一:勾结会让“连线”爆炸式增长

结论:当两个“坏习惯”互相依赖时,它们之间的连线数量显著增加
比喻:就像两个捣蛋鬼凑在一起,他们之间会建立无数条私下的“秘密通道”。原本只需要走正门(正常依赖)的事情,现在他们之间全是错综复杂的“暗道”。这导致如果你想改动其中一个,整个餐厅都会跟着震动(涟漪效应),维护成本极高。

  • 数据:在 36 种可能的组合中,有 28 种情况都出现了连线激增。

发现二:有些“勾结”是固定的模式

结论:某些特定的坏习惯组合,总是以相同的方向改变连线数量。
比喻

  • 如果“乱跑的厨师”(Feature Envy)去依赖“端盘子的服务员”(Data Class),他们之间的连线总是变多
  • 如果“超级大厨”(God Class)去依赖“乱跑的厨师”,连线也总是变多
    这就像是一种固定的化学反应:只要 A 和 B 碰到一起,必然会产生更多的麻烦。

发现三:不同角色的表现不同

研究人员把代码分成了“提供者”(给数据的)和“消费者”(用数据的)。

  • 数据类(Data Class) 是典型的“提供者”,它被其他坏习惯依赖时,连线会暴增。
  • 上帝类(God Class) 既是“提供者”也是“消费者”,它参与勾结时,会让整个系统的连线变得极其复杂。

5. 这对我们有什么用?(给开发者的建议)

这篇论文不仅仅是为了发现理论,更是为了给出行动指南

  1. 优先处理“勾结”的坏习惯
    不要只盯着一个单独的坏习惯修。如果两个坏习惯互相依赖,优先解决这对组合。因为修好这一对,能切断大量复杂的“秘密通道”,比单独修一个要划算得多。

  2. 利用“勾结”来发现隐藏的问题
    如果你发现一个模块(比如“乱跑的厨师”)和另一个模块(比如“端盘子的服务员”)之间的连线突然变得异常多,这可能是一个信号:那个“端盘子的服务员”可能也是个有问题的模块(比如它其实是个数据类,但被过度使用了)。这可以帮助开发者更精准地找到问题所在。

  3. 重构策略

    • 例子:如果“乱跑的厨师”总是依赖“端盘子的服务员”的数据,最好的办法不是切断联系,而是把那个厨师直接搬进服务员的厨房(把方法移到数据类里)。这样,他们就不再是“跨部门勾结”,而是“内部协作”,连线就消失了。

总结

简单来说,这篇论文告诉我们:代码里的“坏习惯”如果单独存在,可能只是个小麻烦;但如果它们互相勾结,就会像滚雪球一样,让软件变得极其脆弱和难以维护。

识别并优先解决这些“勾结”的坏习惯,是保持软件健康、降低维护成本的最有效手段。就像在餐厅里,与其一个个批评捣乱的员工,不如先把那些互相串通、制造混乱的小团体拆散。