2009-06-15 91 views
7

重用代码与复制/粘贴的最佳做法是什么?代码重用和重构

重复使用的问题可能是更改重用代码会影响很多其他功能。

这是好的&不好:如果改变是一个错误修正或有用的增强,好。如果其他重用代码意外地因为依赖于旧版本(或者新版本存在错误)而中断,那么很不好。

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

是否有这个问题的最佳做法;重用需要防水单元测试吗?

回答

2

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

您必须管理此依赖关系

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

  • 消费者应该取决于一定(已知)重用代码/二进制的版本。

  • 消费者应保持重用代码/二进制的副本,但从来没有直接修改它,只有更新到新版本时,它是安全的

  • 当您修改resused代码库时请谨慎考虑。 突破变化的分支。

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

所以,你可以从重用收益(例如,你要修复在一个地方一个bug),并且仍然在你的变化控制是。但是当你更新重用的代码/二进制文件时,没有什么能够保证你不会被测试。

11

每行代码都有成本。

Studies显示成本与代码行数不成线性,呈指数关系。

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

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

编号

所有的代码都需要足够的单元测试。所有代码都是重用的候选对象。

+0

+1为了可读性和注意代码成本。 – cgp 2009-06-15 13:50:57

+0

-1严重滥用“指数”。事实上,它甚至不是二次的。 – 2009-06-15 15:08:39

+2

COCOMO看起来指数级:努力= 2.5 Ksloc ** 1.05。这不是指数? – 2009-06-15 15:10:18

1

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

2

复制和粘贴永远不是好习惯。有时候,它似乎是在一个非常贫穷的代码库短期修复好,但是在一个精心设计的代码库,你将有以下得到容易再利用:

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

如果您的代码库显示这些属性,复制和粘贴永远不会看起来像更好的选项。正如S Lott所说,不必要地增加代码库的大小会产生巨大的成本。

3

在我看来,在多个地方有可能改变一个地方而不是另一个地方的一段代码不符合适当的范围规则。如果两个不同的东西需要“相同的”方法/类来完成两个不同的功能,那么应该分解该方法/类。

请勿复制/粘贴。如果确实需要修改某个地方的代码,那么可以通过继承,重载或必要时复制和粘贴来扩展它。但不要通过复制粘贴类似的片段开始。

3

使用复制和粘贴几乎总是一个坏主意。正如你所说,你可以通过测试来检查是否有什么事情发生。

问题是,当你调用一个方法时,你不应该关心它是如何工作的,而是关于它的功能。如果你改变方法,改变它的作用,那么它应该是一个新的方法,或者你应该检查这个方法被调用的任何地方。另一方面,如果更改不修改该方法的作用(只有如何),那么你不应该在其他地方遇到问题。如果你这样做,你做错了什么...

2

是否有这种 问题的最佳做法;是否需要重用水密 单元测试?

是的,有点不错。重写你已经做好的代码永远不是一个好主意。如果你不重复使用代码并重写它,那么你就会将bug表面翻倍。与许多最佳实践类型问题Code Complete一样改变了我的工作方式。是的单元测试是尽你所能,是重用代码,并得到Code Complete副本,你会一切设置。

1

你写:

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

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

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

当它到达这一点时,几乎不可能知道哪些变化是由于某个原因而存在的,哪些是因为错误而存在的(因为更常见的是遗漏的错误 - 忘记应用补丁而不是改变一些东西 - 不太可能有任何证据或评论)。

如果您需要不同的功能调用不同的功能。如果您需要相同的功能,请避免复制粘贴,以保证那些将遵循您的人的完整性。

1

有一些指标可以用来衡量你的代码,并且由你(或者你的开发团队)决定一个合适的阈值。 Ruby on Rails有“Metric-Fu”Gem,它包含许多工具,可以帮助您重构代码并保持最佳状态。

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

2

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

此外,在非常简单的情况下,复制/粘贴可能看起来“OK”,但它也开始将程序员置入复制/粘贴良好的思维模式。这是“滑坡”。当重构应该是正确的方法时,程序员开始使用复制/粘贴。对于设置先例以及发送给未来开发者的信号,您必须小心谨慎。

甚至还有一个关于这个从别人的报价比我更有经验,

“如果你使用复制,而你的编码粘贴,你可能会犯一个设计错误。”
-- David Parnas

2

一个非常合适的复制和粘贴使用是Triangulation。为一个案例编写代码,查看具有一些变体的第二个应用程序,将&粘贴到新的上下文中 - 但尚未完成。这是如果你停止在那个时候你陷入困境。将这些代码复制出来,可能只有很小的变化,可以显示代码所需的一些常用功能。一旦在两个地方都进行了测试并在两个地方工作,您应该将该通用性提取到一个地方,从两个原始地点调用它,并且(当然)重新测试。

如果您担心从多个地方调用的代码引入脆弱风险,您的函数可能不够细。过度粗糙的函数,功能过多,难以重用,难以命名,难以调试。找到功能的原子位,命名它们并重用它们。

0

一般来说,复制和粘贴是一个坏主意。但是,像任何规则一样,这有例外。由于异常不太知名的不是规则我还是要强调什么恕我直言,是一些重要的:

  1. 您有一些非常简单的设计,你不想做设计模式,更复杂OO的东西。你有两个或三个情况在几十亿个微妙的方面有所不同,例如这里的一条线,一条线。从问题的本质来看,你不可能有超过2或3例的情况。有时候,为了解决这样一个相对简单的问题,只需要剪切和粘贴两个恶意中的一个就可以了,而不是为了解决这个问题。代码量有其成本,但概念上的复杂性也是如此。

  2. 你有一些代码,这对现在非常相似,但该项目正在迅速发展,你预计这两个实例将显著分歧随着时间的推移,到这种地步试图甚至找出相当大,可分解块功能将保持常见,更不用说将这些重构成可重用的组件,将会比它的价值更麻烦。这适用于您认为一个实例发生变化的概率远远大于一般功能变化的概率。