有什么好的简洁的方法可以向非程序员解释复制粘贴编程的危险?[关闭]


27

我正在寻找一个很好的类比或隐喻,可以向非程序员说明复制粘贴编程的问题。我偶尔会为潜在客户进行代码/系统审查,而我看到的常见问题之一是在他们的代码库中有大量的复制粘贴代码。我经常在评论中提到这一点,每次我都必须解释为什么这是一个问题(对于那些只了解编程才能理解重用是一件好事的客户而言,这尤其困难,但不足以理解为什么会这样)复制粘贴不是很好的重用形式)。显然,我可以(并且确实)通过代码维护来解释该问题,但是对于这个非程序员会遇到的问题,有一个很好的,简洁的类比会很好。如果类比说明了为什么“搜索替换”不是此问题的有效解决方案,那将是一个好处。有什么建议么?

只是为了澄清一下(基于下面的Jaroslav的回答)-我不是在这里使用代码段。我看到的(经常是令人不安的)是大量代码的复制和粘贴,或者是十行代码的代码,用于将一些用户数据(使用内联SQL查询完成)粘贴到数十个PHP或ASP.NET页面中。因此,从同一项目中其他地方重复代码。

更新:这里有几个非常好的答案。我已经在评论中解释了为什么我选择Scott Whitlock的答案,但是如果您要与完全熟悉制造的客户打交道,我也强烈建议您使用whatsisname的答案。


嗯,那是一个艰难的过程。它不能很好地转换为经典的汽车/建筑/工厂类比.....
whatsisname 2011年

3
想象一下,在美国普通法中提到共和党和民主党,然后在增加三分之一的同时重命名其中一个党派……许多法律都必须重写。
工作

类似于这样的方式:您无法从Wiki,论坛等中理解粘贴复制代码(不安全,结构不良等),就像从以下位置打开电子邮件附件(病毒,间谍软件,垃圾邮件等)一样:第三方?
sakisk 2011年

@faif:复制粘贴的代码不一定是垃圾代码。您旁边的办公室那个人写的这可能是不错的代码。复制粘贴的代码的问题在于,它很快就会成为难以管理的维护/调试恶梦。
whatsisname 2011年

1
@faif:然后在括号中的部分
打乱

Answers:


36

就像这样...您家中只有一个时钟。大!您知道现在几点了,但是您总是必须去那个房间看一下。

但是,当然,您想知道现在是几点钟,而不必一直去那个房间,因此,您购买了更多的时钟,然后将它们分配到您的房屋中。这些时钟中的每一个都是独立的。他们都保持自己的时间。这意味着:

  • 当时间由于夏令时而改变时,您必须全部更改
  • 即使它们都准备好了,它们也会有所不同,并且很少能完美地达成共识。随着时间的流逝,它们会漂移。

现在,想象一下在具有数十个或数百个时钟的大型设备中存在相同的问题。这就是为什么您需要类似网络时钟这样的东西,以使其自己与中央时基保持同步。这样,时间只定义一次

复制粘贴编程就像购买更多独立时钟一样。它无法缩放。


1
我之所以选择这个答案,是因为我认为它最适合我经常遇到的情况-我看的大多数软件都是针对服务行业的人员,而且制造类比通常很难让他们理解。但是几乎每个人的家中都有多个时钟。我也喜欢它,因为我可以利用这样一个事实,即您家中的每个时钟可能具有不同的更改时间的过程(快速/慢速以不同的量)作为解释为什么不进行搜索和替换的方式不是维护复制粘贴代码的选项。
EZ哈特

38

假设您正在设计飞机。您只有一架喷气发动机。它卖得很好。现在,您将设计一架四引擎飞机,用于远距离航行。

现在,您没有为每个单独的引擎创建一套完整的工程规格和图纸,对吗?不,您在所有四个地方都使用相同的引擎。现在想象一下,如果您有4套图纸,并且必须进行一些更改。现在,您必须在所有四个引擎工程图中进行更改。如果由于间隔而意外忘记在第4引擎中进行更改,会发生什么情况?

假设您要更改螺丝或管螺纹的长度。现在,您不仅可以在工程图纸数据库中“搜索和更换”,还可能不小心更改了燃油泵中的安装螺钉,因为它们恰好具有相同的尺寸。或者为尾舵提供动力的液压管路使用了相同的螺纹,但现在有所不同,您无法再为尾部提供动力。

现在想象一下,您被NTSB困扰了,因为您的发动机在向佛罗里达州南部飞行时会随机抛出涡轮叶片并爆炸。现在,您要看哪些引擎图纸?他们所有人,其中之一?您怎么知道这四个都一样?也许已进行了更正,但它们仅适用于引擎一,因为设计引擎的那个人一年前离开了雷鬼乐队演奏,并且是唯一记得四个引擎在单独文件中的人,固定爆炸涡轮的家伙是他的替补。

复制和粘贴代码类似于具有重复的零件图,无论是螺钉还是引擎。您希望将组件抽象为可以重复使用的基本组件。

不要复制引擎,只需编写将引擎安装到机翼的代码即可。


11
现在,假设您发现4号发动机与其他三个发动机不同。这是有区别的吗?是否旨在应对起飞后立即向左转弯引起的某些扭矩问题?还是复印错误?
David Thornley

5
很好的类比...但是,如果有人难以理解复制/粘贴代码...喷气发动机可能同样困难:)
史蒂文·埃弗斯

这个类比你应该谈论固体燃料火箭而不是喷气发动机。这样,您就可以完成“看?就像火箭科学一样。”
2011年

这不是一个比喻。蓝图实际上是机械工件的代码。
直觉

7

您必须从共享相同资源而不是复制相同资源的角度来解释它。

例如,在一个大城市中,为每个房屋配备一个专门的发电站为房屋供电是否有意义,或者每个房屋共用一个电站是否更有意义?如果在电站使用的特定组件出了问题并且需要维修,则在一个地方进行维修会更容易,并且每个人都可以从这些维修中受益,而不必在每个专用电站进行维修。单独享受房屋福利。


7

“嘿,看起来所有的手术都 差不多吗?所以您不介意我为不同的手术随机复制不同手术的手术 指导吗?”


1
大!!!用刀做手术对不对?让我用屠夫刀对您进行脑部手术。
Aditya P

1
@AdityaGameProgrammer:当您拥有的唯一工具是割肉刀时,一切看起来都像火腿。
乔伊·亚当斯

6

复制和粘贴就像试图在没有模具的情况下制造零件。它的速度很慢,而且您一次只能从每个零件上使用一次,因为一旦确定它有缺陷或损坏,您就不能仅仅修理模具来创建合适的替换品。

在寻求类比时,首先我们必须考虑复制和粘贴编程的危险:

  • 由于副本不完全匹配而引入错误(未清除不必要的变量和代码路径)
  • 更高的测试要求 -抽象仅帮助您测试更改,并且仅更改分支,而不更改分支,从而消除了对回归测试的需求。
  • 复制会复制所有内容,包括错误。现在,适用于代码两部分的每个错误修复或功能的实施成本都增加了一倍,并且完全忘记它的可能性很高。
  • 搜索和替换加剧了上述问题,因为您不容易找到重复的代码。

反对复制和粘贴编程的主要武器是抽象。因此,要找到一个很好的类比,请寻找我们周围世界中的抽象示例。

抽象基于设置定义,然后继续在执行中使用这些定义的思想。没有定义,世界会是什么样?

  • 定义是法律语言的关键部分。想象一下一个没有核心定义但每次使用的术语都完整定义的合同。
  • 定义和模板用于构造。施工中的一个普遍问题是,每个新切割都是基于最后一个切割,而不是基于开始时进行的单个测量。这会导致长度随时间变化很大。
  • 公司组织基于摘要和定义。如果您的公司每次必须扩展,他们都必须从头开始定义新角色怎么办?那是行不通的。那么,如果他们决定只是选择一个相似的工作角色,并对其进行略微修改以适合自己,该怎么办。每个人都将被锁定在位,因为不可能四处移动资源。

只有要复制的作品是永久性的,才可以复制。否则,每个副本都会创建一个全新的分支,分别进行测试,维护和升级。

通过将所有分支捆绑到一个主干中,并隔离对较小分支甚至叶子的修改,抽象可以解决这一问题。


2
我喜欢类比,恐怕其他人对非技术用户不会有太大帮助。
Matthieu M.

@Matthieu-我不知道您是否指的是第一个要点,但我并不是说这些是类比,我是在描述我认为是开发人员思考良好类比的思维过程。
妮可(Nicole)

4

我认为您在谈论的是重复代码,而不是复制粘贴(使用代码段等)。

这是一本历史书的类比,很好地说明了这一点。在古腾堡出版之前,僧侣们坐着手工写作,并一遍又一遍地重写同一本书。僧侣写的书经常带有错误,并且由于古腾堡,这个问题得以解决。

另一个比喻:自动取款机。您有一台自动取款机,可以提供各种卡,并且始终可以很好地为您服务。复制代码会创建不同的取款机,因此每个人都必须使用不同的取款机,有时该机器甚至会给您BSOD。

关于Jeff的复制粘贴,有一篇很棒的文章http://www.codinghorror.com/blog/2009/04/a-modest-proposal-for-the-copy-and-paste-school-of-code-reuse。 html

PS:我知道古腾堡之前有印刷机。


2

对于非程序员,我认为我们正在谈论商人,因此我会简短地谈及金钱的现实。

  1. 每行代码都会花费您的钱(无论是书面的还是复制的)
  2. 每个错误花费的成本远远超过每行。
  3. 每行代码都会添加潜在的错误
  4. 重复的代码=重复的错误
  5. 在同一测试周期内几乎不会发现重复的错误。

粘贴=烧钱。


1

我是否可以回答这个问题,但可以说您真的不需要类推,而试图为每种开发习惯或模式找到正确的类比似乎是错误的,而且往往适得其反。就像试图用扁平的脚做瑜伽...

复制/粘贴导致问题的原因有很多,它会将现有的错误传播到新粘贴的区域中,在某些以前被认为是性能增强的环境中,实际上现在速度变慢了(如果有人感兴趣,我可以提供示例,但是归结为JIT,您还真的认为自己比现代编译器还聪明吗?)。

它表明开发人员要么是懒惰的,要么是自私的,或者两者都是。如果这是您当前正在团队中进行的战斗,则取决于您在该团队中的职位(团队负责人/ jnr开发人员,snr开发人员,任何人),您需要解决此问题,可能需要在组织内部进行仲裁。

编辑:根据下面的评论,这是代表第三方(或什至第四方:)审查第三方代码的代码。我希望可以添加一些有用的东西。

首先,当为第三方编写代码时,他们是否有任何指标?例如,代码行(LoC)。

我仍然认为我上面所说的一些内容仍然很重要。我可能还应该问一下审查的目的是什么。如果要保留报价或更换报价,则必须提出很多不同的问题。

无论哪种方式,您都在评估代码的质量,好吧,复制任何粘贴都属于“开发人员对抽象和/或程序流控制设计表现出足够的理解”类别:

评论:开发人员未能表现出对抽象的任何理解,并且他们对程序流控制的方法容易出错。您可以在此处介绍“圈复杂度”。实际上,这很容易理解,从某种程度上来说,我认为我可能已经找到了答案:D对我来说是。

好吧,复杂的循环就是这样。你有一张地图。它具有您的出发位置和所有可能的目的地。不必很多。想想,停车场,咖啡厅,厕所。驾车复杂性是衡量到达任何目的地的起始位置的不同路线数量的度量。

复制和粘贴代码可能会增加循环复杂性,因为它将包含重复的逻辑,这些逻辑本可以抽象到其自己的命名块(或方法)中。

看起来合理吗?


需要明确的是,这是其他组织编写的代码,并将其带给我们的组织进行审查。因此,这不是我的组织内部的战斗,而是我需要使其他组织的人员(非程序员)理解的事情。
EZ哈特

知道这一点很有用,并希望它对我来说变得更加容易:)我将添加一个编辑。
伊恩

抱歉,需要长时间编辑,但是我认为tldr是复制和粘贴的代码是一种代码异味,表示循环复杂度(除其他事项外)增加,并且使用单面隐喻非常容易描述循环复杂度。
伊恩

1

用英语来形容。现在想象一下,每当您要描述该事物时,您都使用完整的字典定义而不是单词。别人对你的理解有多容易?

形成一个不存在的事物或不存在的事物(想象)的心理图像,表示一个以另一个条件为条件的动作或状态。意志的简单过去。表示相对于过去时间的未来感。指出过去反复或普遍发生的行动(将)并非易事;需要巨大的体力或精神努力才能完成或理解或忍受(困难)。

显示经过重构以消除重复的实际代码的实际前后示例也无济于事。


我建议排演第二段,以展现莱斯利·尼尔森(Leslie Nielsen)的风格:-)
卡尔·比勒费尔德

1

还存在安全性和代码完整性问题。

如此处所示,可以将恶意数据嵌入到传输到剪贴板的Unicode字符中。

根据您的编辑器对Unicode字符的响应方式,这可能会导致源代码发生意外更改,编译器输出发生意外更改或某些我尚未想到的事情。


0

我在这里可以看到几种不同的路线:

  1. gi窃 -有些人可能从学校记住了这一点,在那儿,盗窃知识产权是一个很大的禁忌。复制粘贴编程可能像这样,因为有人可能不了解其来源,或者使用盲目复制和粘贴的特定解决方案可能会从中得到什么陷阱,而没有分析这项工作的效果如何以及为什么会或可能不会有效解决问题的方法。

  2. 盲目跟随方向-大多数人可能不得不去一些以前从未有过的地方。有些人可能已经使用MapQuest或Google Maps查找地点,然后按照给出的说明进行操作。尽管软件给出了到达目的地的具体说明,但有一些故事让人迷失方向或只是找不到他们应该去的地方。这是粘贴粘贴的另一大危险,就像有人将您的指示从A到B传递给您,而又不让您看到任何可能使旅行变得更加艰难的区域地图一样,这是另一个危险。如果那看起来并不困难,您可以要求别人戴着眼罩从A到B来做事,这样他们就必须依靠其他感觉来确定他们面对的方向并到达目标。

数据,信息,知识和智慧可能是一个很好的模型,可以用来说明为什么搜索和替换作为解决方案无效,因为复制和粘贴非常机械化并且没有太多思考,因此传输的数据没有正确使用它的知识和智慧。可以以核能为例,说明如何理解这种差异非常强大。在安全性和使用方面,将核反应堆与核弹进行对比,以了解如何知道去哪里不足以安全地利用原子能。


0

假设您有一群学生和学校的一套规则。并非将规则发布在一个普通的地方,所有学生都必须参考您,并递给每个人一份规则副本。每个学生都被告知必须遵守信件上的规则副本。

现在修改其中一条规则,说如果发生灾难,您应该去新的避难所。您必须去找每个学生并修改他们的规则集。如果其中一名学生失踪而龙卷风袭来,则该学生将前往老地方并死于可怕的死亡。


0

有人给您发送了带有附件文档模板的电子邮件。在模板更改之前,请随时使用它。不用担心,他们不会忘记给您发送刷新的副本。



0

这种不良做法还有另一个重要方面,至今尚未有人考虑:通过盲目复制他人的(全部或部分)代码(未经他们的许可,可能会违反版权法


0

我看到的复制粘贴编码是一种开发人员不了解或不想推断他们在做什么的代码,并将已经“或多或少”完成了所需功能的不同部分复制到一起,最后随意地将它们摆动使它们适合在一起。

有三个主要问题:

  1. 它永远不会导致没有错误的代码。曾经
  2. 如果他们在编写代码时不理解代码,则在调试时永远无法弄清楚代码。只有其他人才能清理他们造成的混乱,但需要支付额外费用。
  3. 如果他们避免考虑正在编写的代码,则避免学习。如果他们避免学习,他们将永远不会成为一名优秀的程序员。如果他们永远都不会成为一名优秀的程序员,为什么他们会加入您的团队?

0

假设您有5个女朋友(狡猾的狗狗),并且希望向所有人发送情人节礼物。您输入第一个字母,添加她的名字,并提及你们分享的令人难忘的内容。然后,您将字母复制和粘贴四次,每次都丢失一个#1女友名字的实例,并进行复制和粘贴,因为您输入了错字。现在,您的五个女友中有四个正在前往女友#1的家。

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.