您是如何狂热地消除代码重复?

时间:2008-11-17 16:26:15

标签: refactoring code-duplication

你对消除重复代码有多狂热?

就个人而言,每当我看到重复代码时,无论是在测试代码还是生产中,我都倾向于重复复制。我唯一的例外是:

  1. 有时复制的减少非常少,因为新重构的方法有太多的参数实际上没有用/可读。
  2. 有时候,在测试代码中,当几个测试使用相同的代码而不是一个连贯的流程时,我只留下复制(但并非总是如此 - 取决于重复大小)。

17 个答案:

答案 0 :(得分:17)

我始终坚持第一次复制(即原件加一份)通常不值得去除的原则。这是因为原件加一份副本可能是“一次性”,并且你没有从移除它们中获得足够的证据来证明这项工作的合理性。

然而,一旦我开始制作第二份副本,我就会重写所有三份以删除重复。那是因为它现在(在我看来)从“一次性”变为“趋势”。我将更有可能再次使用代码,因此删除重复项的努力现在是值得的。

我毫不犹豫地将这个过程称为“重构”,因为这是XP阵营中的一个流行语,我在80年代早期用FORTRAN和C做了这个。

良好的编程习惯是永恒的(通常也是时髦的)。

干杯,

-Richard

答案 1 :(得分:15)

避免将代码分解到配置参数(需要改变行为)的代码,这会妨碍代码的意图。在你达到这一点之前尽量去......但它是一种平衡的行为。

答案 2 :(得分:14)

如前所述,我试图按照“干”原则生活 - 但我也说有另一种情况,我经常不愿意消除重复:

  • 请勿修改您没有(或无法经济/实际开发)单元测试的代码。

这组测试将包括提取的任何方法的调用代码。

如果我无法测试,我不能说我没有引入缺陷。有了测试套件,我至少可以说它已经完成了以前的工作。

答案 3 :(得分:13)

在消除代码重复方面,我认为自己是一个极端的狂热分子。只要我们没有达到里程碑的关键点,我会尽力删除我在代码中遇到的任何重复代码。最终,我只是耗尽时间,不得不单独留下代码用于下一个里程碑。在这种情况下,我经常至少检查一条评论,注意到重复以及需要采取哪些措施来删除它。

答案 4 :(得分:7)

我总是首先想到为什么这个代码是重复的。大多数时候,答案是懒惰/无知/等等,我重构。但是,偶尔会出现重复实际有效的情况。我在这里谈论的是两段语义无关的代码,但只是发生才能实现相同(或类似)的实现 。例如,考虑完全不相关(实际)流程的业务规则。规则可能等于一天,然后第二天其中一个更改。你最好希望它们不是由相同的代码表示,或者祈祷进行修改的开发人员可以发现正在发生的事情(单元测试,任何人?)。

答案 5 :(得分:5)

我们努力工作。有一个检测这种重复的工具确实很有帮助;无论最好的意图是什么,都是因为一个人没有想到,或者时间紧迫等等。

CloneDR在大型源系统中找到重复的代码,包括精确副本和接近未命中,由langauge语法参数化。它支持Java,C#,COBOL,C ++,PHP和许多其他语言。 我们自己使用它来帮助管理我们自己的代码。

答案 6 :(得分:4)

代码重复可能会在后面快速咬你,给你带来很大的痛苦。如果我看到重复的代码(当然通常来自其他人的旧代码;))我试着立即重构它。这是非常罕见的,不值得努力。现在花些时间,或者你以后会花更多的时间。

答案 7 :(得分:4)

我几乎是一个关于它的心理。如果我不止一次做某事我会重构。期间。感叹号。

答案 8 :(得分:4)

我过去对此非常自由 - 很明显尽量避免重复,但是如果你只需要从这里复制偶尔的15行代码到那里以节省下午的重构,那可能就好了因为你没有习惯它。

然后我开始了我现在的工作。

在我之前编写了大部分代码库的人把“过早的优化是所有邪恶的根源”这条线路看作是荒谬的极端。示例:应用程序中至少有五个不同的位置计算上传图形的缩略图的大小。这看起来像我可以合理化的东西,直到我意识到所有5个“路径”的缩略图都显示在同一个屏幕上 - 并且每个函数都以稍微不同的方式进行数学计算,并得到略微不同的结果。它们都是以复制品的形式开始的,但是在我们到达我发现它的地方之前,它们都被热轧了一年左右。

所以,这些都被重构了。而现在我是一个被掠夺的狂热分子。

答案 9 :(得分:2)

我认为它是优秀程序员最重要的指标。如果你可以编写完全因子代码 - 那么几乎按照定义它是很好的代码。

似乎几乎所有其他编程实践都只是让代码干涸的方法。

这有点夸大其词,但不是太多。在DRY和让你的界面尽可能稳定和最小化之间(分离关注)你正在成为一名真正的软件工程师,而不是程序员/黑客......

答案 10 :(得分:2)

VERY。就我而言,几乎所有的开发技巧,语录和“最佳实践”都源于不重复代码并使其可重用的原则。 MVC,装饰,OOP等等。

显然,有时需要保持一种实用主义感,但我倾向于非常倾向于干。

答案 11 :(得分:1)

由于复制有助于复制粘贴,因此我总是尽量避免在现有代码中存在重复的情况下进行复制或重构。

答案 12 :(得分:1)

正如Rewrite or Repair问题中提到的那样,您可能会在检测到重复代码时不时进行一些重构。

但我相信metric, from a code static analysis tool检测到这种“重写”操作会得到更好的管理,其中:

  • 检测到这些重复的代码
  • 指出趋势(因为往往会检测到越来越多的重复代码)

在这种情况下,可以优先考虑纠正措施,重点关注这种重构。

第二个想法,我想知道我可能是QA guy Zig指的是什么; - )

答案 13 :(得分:1)

我是DRY编码的忠实信徒。不要重复自己。如果你不止一次这样做,就把它放在一个帮助类中。

没有什么比记得在几个地方对同一件事做出改变更糟糕了。

答案 14 :(得分:1)

我开始时非常狂热,但最近的经历可能让我更加兴奋,并给了我另一套工具。具体而言,来自生物信息学的算法/概念。在新的位置,我们正在更新Web UI以使用CSS驱动的布局而不是表,所以我正在分析700个现有的JSP文件。我将所有代码行放入一个数据库中,总行数为100K,少于20K是唯一的。然后我将每个文件表示为一行行ID,并找到2行或更多行的公共子序列;最长的是几个JSP文件之间重复的近300行,以及切割和过去的极端情况。这就是我现在所处的位置,但我的下一个计划是将文件重新表示为line_id的OR(公共)subsequence_id序列,对它们进行排序,然后对排序顺序中彼此相邻的文件进行Levenshtein比较。这应该有助于模糊匹配不仅包含公共子序列的文件,而是包含一个等等的子序列。

答案 15 :(得分:0)

规范化代码,规范化变量,规范化数据库,规范企业层级,规范政府......

答案 16 :(得分:0)

我有时会犯复制粘贴罪,但我会尽可能地消除重复。例外情况是我有一个函数调用其他几个函数并且非常慢。有时可以将子函数的内容组合起来以提高速度,或者可以将基础SQL查询组合成更少或只组合一个。

实施例: 在库存管理中,项目的最小数量等于工作储备中的数量加上安全库存中的数量。安全库存等于工作储备的一半。

Function workingReserve(itemCode, someDate)
     ' Inside here is a looping structure that adds up the requirements for the next six weeks (because that's how long it takes between reorder and receipt).
End Function

Function safetyStock(itemCode, someDate)
    safetyStock = workingReserve(itemCode, someDate) / 2
End Function

Function minimumOnHand(itemCode, someDate)
    minimumOnHand = workingReserve(itemCode, someDate) + safetyStock(itemCode, someDate)
End Function

我很抱歉这是用VB编写的,但它来自Excel VBA函数。

实际上,workingReserve函数在相同的数据上运行两次。通过在minimumOnHand()函数中组合safetyStock()函数的业务逻辑,可以提高性能。

Function minimumOnHand(itemCode, someDate)
    minimumOnHand = workingReserve(itemCode, someDate) * 1.5
End Function

在实际代码中,我在解释业务逻辑的代码中有注释,但为了简洁起见,在此省略了它们。