为什么“复制和粘贴”代码很危险?[关闭]


130

有时,我的老板会向我们抱怨:

为什么我们需要这么长时间才能实现功能?

实际上,该功能之前已在其他应用程序中实现,您只需要从那里复制和粘贴代码。成本应该低。

这确实是一个难题,因为在我看来,复制和粘贴代码并不是一件简单的事情。

您有充分的理由向您的非技术老板解释吗?


19
听起来好像不是从以前的应用程序中复制代码并将其粘贴到新应用程序中,而是一次又一次地重写相同的功能。我认为DRY原则更适合于不具有在整个系统中重复的相同功能,但是重用其他应用程序中的代码比重写它更好。
卡森·迈尔斯

5
因为每次您复制和粘贴代码时,都会删除印章。
DeadlyChambers 2014年

@CarsonMyers仅当组件可重用时。它旨在适应当前环境。
Sreekanth Karumanaghat

Answers:


171

如果您在复制粘贴代码中发现错误,则需要在每个位置修复该错误,并希望您能记住所有错误(对于更改的要求也是如此)。

如果将逻辑放在一个地方,则在需要时更容易进行更改(因此,如果您决定应用程序需要更新,则只需在一个地方进行)。

让老板了解DRY原则(不要重复自己)。

您所描述的内容听起来像是的完美用法,您可以在其中共享代码并将其保存在一个地方。

如果我打算在以后尽快重构代码,我将永远只复制粘贴代码-确保以后再提取通用代码,以便可以重用尽可能多的逻辑。不久之后,我的意思是几分钟和几小时后,而不是几天和几周。


41
+1。关键是复制和粘贴对于解决当前问题很便宜。真正的问题是,从长远来看,维护重复代码的成本远远高于精心设计的代码
Paolo,2010年

7
这不仅仅是一个错误问题;程序要求可以更改。我已经更改了五分之四的位置,之前需要进行一些更改。
David Thornley 2010年

1
如果您可以按需复制n粘贴,并跟踪重复的位置很容易以后进行抽象或更新,那么复制粘贴就不是一件坏事。有关更多详细信息和工具,请参见www.semanticdesigns.com/Products/Clone上有关克隆检测的讨论。
艾拉·巴克斯特

4
大量的ifs,而且大多数工具不支持在这一点上克隆检测。
Oded

2
从前有一个程序员在ESA工作。他当时正在为Ariane-5火箭开发软件,并且使用了复制粘贴方法。然后发生...
Hauleth

25

你会好得多分享通过建立一个库而不是代码复制使用复制和粘贴代码。

与重写(查找DRY)相比,您仍然会获得速度上的优势,但是只有一个地方可以维护代码。


1
我很好奇,如果您需要做的就是复制代码,为什么还要“削减”代码?
dpp

好点dpp。编辑!
CResults

12

显而易见的原因是,您将来要承担“债务”:您需要对代码进行的任何更改(不仅是错误修正,还包括任何更改)现在的成本都将增加一倍,因为您必须更新两个位置-风险更大,因为您最终会忘记其中之一。换句话说,现在使它工作更快将使您的工作将来变得更慢,这从商业角度来说可能是好的,但通常不是这样。

但是,更重要的原因是,“与此相同”的假设多半不是错误的。只要您的代码依赖正确的潜行假设,将其复制到另一个位置都会导致错误,除非这些假设也存在于新位置。因此,粘贴的代码通常从一开始就出错,而不仅仅是在下一次更改之后。


11

从设计角度讲,复制粘贴的代码无疑是一场灾难,将来有可能引起很多问题。但是你问为什么你花了很多工作,现在,答案是:因为它从来就不仅仅是复制和粘贴。

如果原始代码是作为一个相当独立的库编写的,目的是要重用,同时要兼顾灵活性和客户端使用-那么不错,但这不是复制粘贴,而是使用代码库。实际的代码复制粘贴通常如下所示:

  • “当然,我已经有了可以做到这一点的代码!”
  • “等等,这五个代码版本中的哪一个是我想用作源代码?
  • “嗯,所有这些'util_func_023'函数有什么作用?我没有记录它们吗?我现在需要哪个?
  • “哦,是的,此代码使用了代码库Y。猜猜我需要[ 选择一个:将所有代码库Y复制到我的新项目中/花一天时间从代码库Y中提取我想要的一个功能/花一周的时间从代码库Y中提取我想从代码库Y]中获得一项功能。”
  • “我复制了所有内容,是的!”
  • “为什么这不起作用?”
  • 这是您花费数小时/天/周花费在调试与您想要的代码相似的现有代码上的时间,而不是编写您实际想开始的代码。

总之,现有的无法直接使用的代码充其量可以作为编写类似代码的良好参考。当然,它不能完全解除,不能在完全不同的系统中工作。通常,可以安全地假定,编写和完成的所有代码都应尽可能少地弄乱-即使是副本而不是原始的代码本身。

如果要基于复制粘贴来构建项目,则必须以一种易于重用的方式开始编写代码,而无需复制原始代码并弄乱它。这是值得做的,如果那是您老板所期望的,那么你们俩都需要确保这就是您首先设计和工作的方式。



9

如果您已经实现了这些功能,则需要复制并粘贴以重复使用它们,这听起来好像您做错了什么。您不能将这些功能放在库中,这样就可以在没有复制/粘贴的情况下重复使用它们吗?


8

DRY原则(请勿重复): 维基百科上的DRY

“每条知识都必须在系统中具有单一,明确,权威的表示形式。”

其他链接


这就像在说“永远不要在男人的喉咙上插刀”,这听起来像是一个很好的规则。直到您意识到医生必须打破该规则才能执行气管切开术以挽救一个人的生命(如果他无法呼吸,可能是由于过敏反应,极端的过敏反应)。每个规则都有一个例外(也许对此例外,每个规则都有一个例外)。因此,对于真正的“工程”现实,每条规则都必须附有“为什么”,“何时”和“例外”列表,
MicroservicesOnDDD

所以...什么时候不遵循DRY?在我目前的工作中,我经常与固件相关,这与固件有关,而答案是我们“展开循环”并执行其他操作,因为这“提高了性能”。我们的继承层次结构很浅,我们直接使用大多数类而不是对其进行子类化,并且... ...我们经常使用复制和粘贴。我讨厌它,因为它使我们的代码库更难理解和维护。但是我们有我们的理由,这是可以接受的理由。我们不是唯一的利益相关者。而找到适当的平衡更是一门艺术。
MicroservicesOnDDD

7

在我看来,您的非技术老板最严重的误解是,您的工作主要是打字。他们认为您可以消除打字,从而节省大量时间。

我认为您可以为这个人提供的最好的教育是指出您所做的所有工作,而不是打字。即使大部分工作通常在打字的同时在您的脑海中不可见地发生。

当然,消除打字会节省一些时间。但是,工作量更大,不打字的部分就会变得更大,并且会浪费任何时间节省下来的精力,而且还有更多。


4

您确定您的老板想了解DRY原理,错误和其他技术资料吗?

当老板或公司低估完成某些项目所需的时间时,您通常会听到这种评论。而且基于错误的估计,签订了合同等。在大多数情况下,程序员没有参与估计。

为什么会这样?有时项目发起人的预算太少。您使用软件进行自动化的业务流程可能不值得您的团队付出。在这种情况下,经理们通常对坏消息非常闭门。在项目开始时,一厢情愿。然后经理试图责怪程序员。在您的情况下,可以通过复制和粘贴间接进行。在极端情况下,这称为死亡游行


3

复制和粘贴代码通常会导致巧合编程


我发现这篇文章写得特别糟糕。因此,叙述保持抽象,无法阐明弗雷德正在反复工作这一事实。弗雷德(Fred)遇到的一个明显问题是,他对整体体系结构不了解。不幸的是,当我们使用未记录的遗留代码时,这种情况经常消失,而专有技术却丢失了。通过合同和断言编程对设计的引用相当不错,但是不幸的是,即使在它们之后,示例/练习也无法解释。
mapto

3

我认为“ 另一个应用程序 ”在这里很关键,如果另一个应用程序已经过测试并在使用中,则不应将其更改为使用公共库,因此您不能与它共享代码。

同一个应用程序中,“复制和粘贴”是不好的,但是在由不同团队开发或具有不同发布周期的代码库之间,“复制和粘贴”可能是最佳选择。


虽然我可以看到使用库发布对其他应用程序的更新没有什么意义,但至少对功能分支中的必要更改进行检查可能是一个好主意。这将使您确信该库的接口对于至少两个有问题的应用程序足够通用,并允许您在发行周期的适当时间合并更改。
SamB

2

我曾在一家类似的公司工作。作为一名实习生,那时我还不知道更好,所以当我开始一个新项目时,我的老板还建议将代码粘贴到其他地方。嗯,正如您可能认为的那样,整个软件相当混乱,以至于当您尝试修复错误时,会出现两个新的错误。


2

即使其他应用程序已经具有所需的功能,该功能的代码也可能根本不适合您当前的应用程序,而无需进行大量重写。这就像拿一辆福特汽车的发动机,然后试图将它装配到丰田汽车上一样。通常,有一个经验法则是,如果您必须修改要复制的代码的25%以上,最好(廉价)从头开始重写它。

将有问题的代码提取到库中听起来很引人注目,但这可能比听起来困难得多,具体取决于其他系统的构建方式。例如,该功能的代码可能很难提取,因为它以不整洁的方式(例如,通过访问许多全局变量等)连接了许多其他代码。


1

告诉老板,每个变量名称的一部分都包含旧项目的名称,现在您必须手动更改它们。如果您的老板不知道(或想知道)为什么复制/粘贴效果不好,他/她可能还相信:)


1

是的,最大的问题是它不仅是复制和粘贴-其复制然后粘贴然后再稍作修改。

然后,当其中一个粘贴的变体出现问题时,它将被更改。然后,另一种变体被更改。

然后,您发现所有变体都必须更改,因为原始副本存在错误。现在,您已经完全没事了,因为所有粘贴区域现在都不一样了。

而且您不知道吗,这种糟糕的编码通常几乎完全没有注释。

对我而言,区别在于,当您有多个代码副本在做同一件事时,您拥有的只是一堆代码。当只有一个代码完成每件事时,便有了一个系统。

可以很容易地通过单点修改来更改系统的行为-更改一堆代码的行为需要一堆代码。

我喜欢系统,而不是一堆代码。


1

在您面前的即时功能(尤其是在应用程序较小时)的开发速度与随着应用程序增长而产生的长期维护成本之间需要权衡取舍。

复制和粘贴可以更快地实现即时功能,但是随着应用程序大小的增加,在修复错误,进行系统范围的更改以及维护应用程序不同组件之间的工作流方面,这将使您付出巨大的代价。

这是企业主需要听到的论点。这与维护车队的可接受成本相似,但是,对于软件而言,软件体系结构的损坏方面通常对业务部门隐藏,并且只有开发人员才能看到。


0

他是对的,如果团队之前已经实现了类似的功能,那么第二次重复该步骤会容易得多

但是,您可能应该解释每个应用程序都是不同的。仅仅因为你在一个安装了一扇门的房子,并不意味着你可以在另一栋房子里安装了另一扇门没有时间平 -你会因为经验更快(#门安装),但它仍然需要一定的时间,让你的设备,安装门,确保其垂直,然后将其拧入框架。


0

在我公司中,我们始终使用类和方法,并为其提供技术文档。我认为这是最佳实践,如果您可以使用具有良好键的svn搜索应用程序查找之前使用的方法类:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.