代码重用和重构

时间:2009-06-15 13:45:46

标签: refactoring code-reuse

重用代码与复制/粘贴有什么最佳做法?

重用问题可能是更改重用代码会影响许多其他功能。

这很好&坏:如果更改是错误修正或有用的增强,那就太好了。如果其他重用代码意外破坏,因为它依赖于旧版本(或新版本有错误),那就太糟糕了。

在某些情况下,复制/粘贴似乎更好 - 粘贴代码的每个用户都有一个私有副本,可以自定义而不会产生后果。

这个问题是否有最佳实践;重复使用是否需要水密单元测试?

12 个答案:

答案 0 :(得分:11)

每行代码都有成本。

Studies表明成本与代码行数不成线性关系,它是指数级的。

复制/粘贴编程是重用软件的最昂贵方式。

“重用是否需要水密单元测试?”

没有

所有代码都需要适当的单元测试。所有代码都是重用的候选者。

答案 1 :(得分:3)

在我看来,在一个地方使用的一段代码有可能在一个地方而不是在另一个地方改变,而不是遵循适当的范围规则。如果两个不同的东西需要“相同”的方法/类来做两个不同的函数,那么应该拆分该方法/类。

不要复制/粘贴。如果事实证明你需要修改一个地方的代码,那么你可以扩展它,可能通过继承,重载,或者你必须复制和粘贴。但不要从复制粘贴相似的部分开始。

答案 2 :(得分:3)

使用复制和粘贴几乎总是一个坏主意。正如你所说,你可以进行检查以防止你破坏。

关键是,当你调用一个方法时,你不应该真正关心它是如何工作的,而是关于它的作用。如果您更改方法,更改它的作用,那么它应该是一个新方法,或者您应该检查调用此方法的位置。

另一方面,如果更改没有修改方法执行的操作(仅限方法),那么您应该在其他地方没有问题。如果你这样做,你做错了......

答案 3 :(得分:2)

复制和粘贴绝不是好习惯。有时候,作为一个非常糟糕的代码库中的短期修复似乎更好,但是在设计良好的代码库中,您可以使用以下内容轻松重复使用:

  • 封装
  • 定义良好的接口
  • 对象之间的松散耦合(很少依赖)

如果你的代码库展示了这些属性,那么复制和粘贴永远不会是更好的选择。正如S Lott所说,不必要地增加代码库的大小会产生巨大的成本。

答案 4 :(得分:2)

  

这是否有最好的做法   问题;重复使用需要防水   单元测试?

是的,有点肯定。重写你已经做过一次的代码永远不是一个好主意。如果你永远不会重复使用代码而只是重写它,那么你就会将错误表面加倍。与许多最佳实践类型问题一样,Code Complete改变了我的工作方式。是最好的单元测试,是重用代码并获得Code Complete的副本,你将全部设置。

答案 5 :(得分:2)

因此,消费者(重新使用者)代码依赖于重用的代码,这是正确的。

您必须管理此依赖关系

二进制重用(例如dll)和代码重用(例如脚本库)也是如此。

  • 消费者应该依赖于重用代码/二进制文件的某些(已知)版本

  • 消费者应该保留重复使用的代码/二进制文件的副本,但不要直接修改它,只有在安全时更新到新版本。< / p>

  • 修改重用的代码库时请仔细考虑。 分组修改。

  • 如果消费者想要更新重用的代码/二进制文件,那么它首先必须测试以确定它是否安全。如果测试失败,那么消费者可以总是回到最后一个已知(并保持)好的版本。

因此,您可以从重用中受益(例如,您必须在一个地方修复错误),并且您仍然可以控制更改。但是,每当您更新重用的代码/二进制文件时,没有什么可以使您免于测试。

答案 6 :(得分:2)

复制/粘贴导致功能分歧。代码可能会以相同的方式开始,但随着时间的推移,一个副本中的更改不会反映在所有其他副本中。

此外,在非常简单的情况下,复制/粘贴可能看起来很“好”,但它也开始让程序员进入复制/粘贴很好的思维模式。这就是“滑坡”。当重构应该是正确的方法时,程序员开始使用复制/粘贴。你总是要小心设置先例和发送给未来开发人员的信号。

甚至有一个关于这个的报价来自一个比我更有经验的人,

“如果您在编码时使用复制和粘贴,则可能会出现设计错误。”-- David Parnas

答案 7 :(得分:2)

复制和粘贴的一个非常合适的用途是Triangulation。编写一个案例的代码,请参阅第二个具有一些变体的应用程序,复制&amp;粘贴到新的上下文中 - 但你还没有完成。如果你停止就会遇到麻烦。将此代码重复(可能具有微小变化)会暴露您的代码所需的一些常用功能。一旦它出现在两个地方,经过测试并在两个地方工作,你应该将这种共性提取到一个地方,从两个原始地方调用它,然后(当然)重新测试。

如果您担心从多个地方调用的代码会带来脆弱的风险,那么您的功能可能不够精细。过于粗粒度的函数,功能太多,难以重用,难以命名,难以调试。找到功能的原子位,命名它们并重用它们。

答案 8 :(得分:1)

你应该编写单元测试,而且是的,克隆代码在某种意义上可以给你安全感,你的更改不会影响大量其他例程,这可能是一种虚假的安全感。基本上,您的安全感来自于对知道代码使用方式的无知。 (这里的无知不是贬义,只是因为无法了解代码库的所有内容)习惯使用IDE来了解代码的使用位置,并习惯于阅读代码以了解如何正在使用它。

答案 9 :(得分:1)

你写的地方:

  

重用的问题可能就是这样   更改重用的代码会影响   许多其他功能。   ......在某些情况下,似乎是这样   复制/粘贴更好 - 每个用户   粘贴的代码有一个私人副本   它可以自定义   后果。

我认为你已经扭转了与复制粘贴相关的问题。如果您将代码复制到10个位置,然后需要对行为稍作修改,您是否记得在所有10个位置更改它?

我已经研究了大量繁琐的大型代码库,通常你会看到的结果是 - 相同的4行代码的20个版本。它们的一些(通常是小的)子集有1个微小的变化,一些其他小的(并且只有部分相交的子集)有一些其他的微小变化,不是因为变化是正确的,而是因为代码被复制和粘贴20次并且几乎应用了变化,但不是很一致。

当达到这一点时,几乎不可能分辨出哪些变化是有原因的,哪些因为错误而存在(并且因为它通常是遗漏的错误 - 忘记应用补丁而不是改变某事 - 不太可能有任何证据或评论。

如果您需要不同的功能,请调用其他功能。如果您需要相同的功能,请避免复制粘贴,以确保那些跟随您的人的理智。

答案 10 :(得分:1)

有一些指标可用于衡量您的代码,并且由您(或您的开发团队)决定是否有足够的阈值。 Ruby on Rails有“Metric-Fu”Gem,其中包含许多工具,可以帮助您重构代码并使其保持最佳状态。

我不确定哪些工具可用于其他语言,但我相信有一个用于.NET。

答案 11 :(得分:0)

一般来说,复制和粘贴是个坏主意。但是,与任何规则一样,这也有例外。由于例外情况不如规则所知,我将重点介绍恕我直言的重要内容:

  1. 你有一个非常简单的设计,你不想让设计模式和OO的东西更复杂。你有两三个案例,这些案例有很多微妙的变化,即这里的一条线,一条线。从问题的本质来看,你不可能有超过2或3个案例。有时它只是剪切和粘贴的两个邪恶中的较小者,而不是为了解决这样一个相对简单的问题来设计地狱。代码量有其成本,但概念复杂性也是如此。

  2. 你有一些非常相似的代码目前,但项目正在迅速发展,你预计这两个实例会随着时间的推移而发生显着差异,甚至可能会发现相当大的,可以考虑的功能块将保持常见,更不用说将它们重构为可重用的组件,将比它的价值更麻烦。当您认为对一个实例的不同变化的概率远大于对常见功能的变更的概率时,这适用。