有人能解释一下删除(或保留)未使用代码的好处吗



我多次听说必须从项目中删除未使用的代码。然而,我不清楚"为什么?"。

我不删除的要点是:

  • 已经编写了代码,并且付出了努力
  • 代码可以在合成环境和真实环境中进行测试
  • 如果组织良好(分组、单独的包、松散耦合等),它不会干扰您的整体代码分析或重构
  • 代码可能在将来使用
  • 删除后,作者可能会感到不舒服

有人能解释一下删除(或保留)未使用代码的好处吗?

以下是应该删除未使用代码的一些原因:

  • 对于任何新从事项目的人来说,他们不仅必须理解工作代码,他们还必须了解未使用的材料。这浪费时间并造成混乱。

  • 有一种危险是,在某个时候,有人会做出改变无意中涉及"休眠"代码,并可能引入错误。我知道这发生在我工作过的项目上。

  • 任何代码的维护都是一种管理负担。通过保存旧的冗余代码增加了负担。例如,合并主分支中的更改变得更加困难,因为要处理的代码更多,出错的可能性也更大。

  • 随着时间的推移,会添加越来越多未使用的旧代码到代码库。这增加了混乱误解和管理开销。

  • 未使用的代码再次被使用的可能性很小。随着时间的推移,重复使用的可能性会降低。如果代码要被删除并且被认为足够重要,那么代码可以被分支并记录下来。

  • 程序员可能对他们可能拥有的代码有任何个人感受努力工作是可以理解的。但专业的一部分需要把这些想法放在一边好的时间不代表任何人,在工作的代码库中也没有保存历史代码的地方。

@subsectus在介绍删除代码的原因方面做得很好;我想谈谈你保留代码的个别项目符号。

  • 代码已经编写完毕,并且付出了努力

但是,如果已经编写的代码没有使用,这只是成本,没有(未来)价值。这是徒劳的努力,保存这些努力的未使用产品并不能验证这些努力。我们保留代码是因为它现在很有用,而不是作为对作者努力的某种纪念。

  • 代码可以在合成和真实环境中进行测试

对不起,我不明白你的意思。

  • 如果组织良好(分组、独立包、松散耦合等),它不会干扰您的整体代码分析或重构

如果它存在于代码库中,无论组织得多么好,都会增加维护和理解负担。的确,它可以被组织起来,减少负担,但如果它消失了,就根本没有负担。

  • 未来可能会使用代码

在敏捷学校,我们说YAGNI:你不需要它。是的,你可能在未来有它的用途,但我们今天对明天的需求了解不够,无法以任何可靠性预测它。否则的想法就是傲慢走向傲慢。我们明天可以知道的是:我们希望我们的代码库易于修改,而未使用的代码会削弱这一特性。

  • 删除后,作者可能会感到不舒服

作者必须克服它。我们都写过一些没有用的东西-能够指向一个正在使用的代码体(因为未使用的cruft被删除了)比指向一个代码体要好得多,在这个代码体中你可以说有几个方法,"而那个方法实际上正在使用!">

拿起一些代码并弄清楚意图是否足够困难,但现在你必须弄清楚哪些部分没有使用?

代码已经编写完毕,并且付出了的努力

这也是不必要的。如果你不把它用于任何事情,它(根据定义)都是无用的,无论它做什么或花了多少精力

代码可以在合成和真实环境上进行测试

如果它没有用,即使你对它进行了测试,它仍然没有用。如果代码没有用,对它的测试也应该没有用(所以把注释的代码放在那里会产生歧义-你保留测试吗?如果你有注释代码的客户端代码,你也会对客户端代码进行注释吗?)

如果组织良好(分组、独立包、松散耦合等),它不会干扰您的整体代码分析或重构

并非如此。所有工具(源代码管理、静态分析、文档提取器、编译器等)的运行速度都会较慢,因为它们必须处理更多的数据(而这些数据中较大或较小的部分是噪声)。

另一方面,如果代码组织得不好,它将扰乱静态分析、重构和其他任何操作。

你在你的工具输入中引入了噪音,并希望它们能正确应对。

如果您的静态分析工具计算出注释/代码比率,会怎样?你只是把它搞砸了,直到昨天(或者每当代码被注释时)都有一些相关的东西。

最相关的是,有注释的代码块在理解代码以进行维护和进一步开发时会出现延迟,而这种延迟几乎总是要花费大量成本。问问自己:如果你需要了解一个函数的实现,你宁愿看什么?两行清晰的代码,还是两行代码和另外二十六条不再实际的注释?

代码可能用于未来的

如果是,您将在团队选择的SCM中找到它。

如果您使用一个合格的SCM并依靠它来保留死代码(而不是打乱源代码),那么您不仅应该了解是谁删除了该代码(提交作者),还应该了解出于什么原因(提交消息),以及与之一起进行了哪些其他更改(该提交的其余差异)。

删除时,作者可能会感到不舒服

那么?

你(我想)是一个完整的开发团队,他们的报酬是制作你知道如何制作的最好的软件,而不是"你知道如何在不伤害X的感觉的情况下制作最好的软件"。

这是编程的一部分,大多数编写的代码最终都会被丢弃;例如,Joel Spolsky曾说过,对于他的公司来说,大约2%的编写代码都可以看到生产。

如果你优先考虑开发人员的自我而不是代码库的质量,你将牺牲产品的质量,因为。。。究竟是什么?保护你的开发伙伴的不成熟?保护同事不切实际的期望?

编辑:我看到了在源代码中保留注释代码的一个有效理由,这是一个非常具体的情况:当代码以奇怪/不直观的形式编写,而干净的重写方式由于一个非常微妙的原因而不起作用。这也应仅在重复尝试纠正问题之后应用,并且每次尝试都重新引入相同的缺陷。在这种情况下,您应该添加注释的直观代码作为注释,并解释为什么它不起作用(这样未来的开发人员就不会再次尝试相同的更改):

// note by <author>: the X parameter here should normally
// be a reference:
// void teleport(dinosaur& X);
// but that would require that we raise another dinosaur and
// kill it every twelve hours
// as such, the parameter is passed by value
void teleport(dinosaur X);

死代码正在污染您的代码

死代码降低了可理解性和可读性。

最好的代码总是被重用的,如果你有死代码,它会降低可重用性

我们受模块化编码方法的驱动,在这种方法中,我们设计代码是为了与其他程序员交互,而不是为了机器。我们应该投入最大的精力让他/她更容易理解我们的代码。这台机器无论如何都会好起来的。

死代码或注释代码就像虚假的痕迹符号,只会让人感到困惑,所以要不惜一切代价避免它。

  • 恐惧。这使得团队更加担心,生产更少。金额当引入更多的死代码时,恐惧感呈指数级上升。"我们不知道那个钻头是否用过,所以我们不敢把它取下来或碰它它。">
  • 清除更改。如果任何地方都需要改变在系统中也存在死代码,你会更改它吗?它是很难知道它是否肯定没有在某个地方使用,所以它总是有风险的。即使它不会打碎任何东西,死者会如果代码在这次更改后被重新使用,它还能工作吗?

    当处理彻底的更改时,开发人员还必须检查包含代码的每个地方,如果是死代码,这是多余的。当代码失效时,检查它们需要更长的时间,因为很难验证它是否没有在任何地方使用。

  • 精神负荷。每当你需要思考某件事是否或者是否应该对死代码做些什么,这需要你的一些脑力
  • 大雁追逐。"我需要一个关于如何使用Foobar。哦,它在代码库的这些地方。我会的检查第一个点击并找出它在UI中的位置。嗯。。。哪儿都找不到。">
  • 充气报告(例如代码、类、例程和更改的行数)。扭曲了项目的可见性,决定了应该对代码库的哪些部分进行操作,以及对未来项目的估计
  • 对代码库的信任减弱。这可能会导致在冗余任务上花费更多的时间,并破坏了使用代码库的流程。开发人员可能必须非常仔细地检查他们使用的所有东西是否都能以他们认为应该的方式工作

如果你知道代码库的一部分没有被使用是非常有价值的,因为这样你就可以删除它。如果你让它留下来,那么在未来很难或几乎不可能确定它是否真的没有被使用。例如,一些以令人惊讶的方式使用代码的东西:反射、动态调用从字符串连接的例程、eval、framework magic

然而,如果代码在未来被使用的可能性很高,那么如果它与其他代码一起使用,而不是在版本控制系统中,则更容易添加。过了一段时间,您可能记不起代码中的任何单词,因此很难从VCS内部找到代码。但我会让死代码很少存在,即使这样我也会把代码注释掉。

  • 未使用的代码是一个更大的搜索空间,供您通读,以及其他通常扫描代码的代码。例如,编译器、IDE、在文件中查找、调试、静态分析、更多要查看的内容、文件包含、从VCS签出等。这会减慢这些过程并增加显著的噪声
  • 未使用的代码并不总是死代码。它可能在某些情况下执行。这不仅可以为bug和性能问题提供一个载体,而且可能是一个安全问题。就性能而言,这可能会以意想不到的方式表现出来,比如更大的下载量
  • 未使用代码产生未使用代码。如果您删除了一个函数调用,然后搜索该函数的使用情况,看看它是否仍然需要,您可能会看到与以前未使用的代码相匹配的代码,并认为您可以保留它。未使用的码越多,确定代码是否未使用的跳数就越多
  • 未使用的代码仍然经常需要维护。比方说A和B取决于C。其中B没有被使用。您更改了C,然后B不会编译,因为您已经从C中的结构中删除了B所需的成员,现在您必须修复B或主动将其从编译中删除。你应该简单地把它去掉

这个列表可能看起来很简单,但每一个都以数百种不同的方式表现出来,在整个开发过程中都会增加协同作用。效率低下通常可以用直接的数学方式来证明或证明。

针对您的观点。。。

  • 已经编写了代码,并且付出了努力

但必须经常维护。它还会显示在诸如文件中查找之类的内容中。

  • 代码可以在合成和真实环境中进行测试

我不知道你说的这个是什么意思。我想它和上一个一样。你的意思是,代码已经过测试,清理它可能意味着它需要重新测试。这是一个通常值得的成本,因为它将在90%的时间内得到回报,并且为了避免在投入生产之前应该进行清洁。几乎所有的代码都有两次迭代,让它工作,让它干净。之所以要测试两次,是因为有人跳过了最后一步。如果你的代码也太贵了,无法校对diff、测试(如果有很多未使用的代码,很可能就是这样)等,那么这就是另一个完整的问题。

  • 如果组织良好(分组、独立包、松散耦合等),它不会干扰您的整体代码分析或重构

无论如何,您的代码应该是这样的,但这只是适度地缓解了问题。听到一些东西应该是有组织的但又不干净的,这是最奇怪的论点。尝试保持代码模块化并减少依赖性是很正常的,但你也想要可重用的代码,如果你的所有模块都是一个孤岛,那么你可能还没有做好准备。您还可能发现自己进行了过度的解耦,这只会缓解未使用的混乱代码的问题。

  • 未来可能使用代码

很多人高估了编写的代码。如果现在不使用它,那么它就是多余的,事实上,当你沿着这条路走下去时,通常只有一小部分未使用的代码变成了已使用的代码。在所有概率中,未使用的代码不太可能是可用的或已使用的代码。最有可能被重用的代码是正在执行某些操作的已使用代码。

更糟糕的是,未使用的代码没有目的。当有人出现并不得不更改一些最终影响未使用代码的内容时,他们会被困在那里,试图弄清楚这些没有用途的未使用代码需要做什么。

当一开始代码需要花费大量精力时,人们很容易有这种感觉。然而,一旦流利并习惯了它,代码就会变得像骑自行车一样。你会发现,随着编写这样一段代码的成本直线下降,保存它的成本也在攀升。

  • 删除后,作者可能会感到不舒服

这是作者的问题。一方面,将大量未使用的代码留给他人处理是自私的。另一方面,如果作者把他们的感受放在代码质量之上,那么他们可能不应该进行编码。你走上这条路,当他们的代码被破坏时,你无法修复,因为这会伤害他们的感情。如果有人仅仅因为代码是他们的,而不是因为它是好的,这不是一个好兆头。作者应该为自己的代码被清理而感到高兴。这就像有人帮你倒垃圾,然后把它扔到垃圾桶里。

如果有人为我做这件事,我会欣喜若狂。也许让我更容易克服这些感觉的是,不要等别人来做,试着自己去做。不断迭代地重写您已经完成的一段代码,使其性能更好、简洁、多余更少、更灵活,但每次代码更少。尽量不要对代码的数量感到满意,而要对代码的多少感到满意。这是一个很难升级的过程,一旦你做到了,你所有的代码都会在下面的一个很好的级别上出现,所以它不需要经常升级。

这个讨论已经有好几年的历史了,但我刚刚遇到它…

我没有看到提到的一件事是,删除未使用的代码必须进行的工作。在许多情况下,删除未使用的代码所花费的时间和精力在本质上并不是微不足道的,而且测试和记录重构后的系统通常会产生额外的成本。这只是决策过程中需要考虑的另一件事。

首先,您应该始终使用源代码管理工具来管理您的项目,因此删除未使用的代码是一种很好的做法,因为您可以随时使用源代码控制来获取删除的代码。对我来说,删除未使用代码的原因是,只有知道该代码未使用的人知道它,团队中的其他人会发现该代码,并试图弄清楚它的作用以及它如何适合整个应用程序,经过这么多努力,该代码根本没有使用,他们会感到失望:)

我认为可以有两种情况:-应用程序代码:如果它未被使用——也许它是未经测试的,并且随着时间的推移而未被接触,也许你可以转移到"内部代码库"-API代码:如果你正在编写一个库,那么IMHO是一个更好的选择来维护它,但在你的活动开发过程中

您确定该代码未使用吗

仅仅检查代码是否仍在编译是不够的。在C++中,如果删除一个"未使用"的隐式定义方法(如operator=),则不会出现编译器错误,该类将只是默默地开始使用(可能不正确的)默认实现。在Java或C#中,可以通过反射来使用代码。在面向对象的语言中,继承可以发挥作用(现在可以调用基类)。在几乎任何一种语言中,另一个重载函数都可能已经接管了它。

检查版本控制中代码的使用年限,而不仅仅是它是否未使用。我看到过一些看起来未使用但刚刚提交的代码,这些代码实际上是另一个开发人员项目的第一步。

积极删除未使用的代码

您付费维护代码:

  • 修复损坏的构建(工程时间)。最近,我们进行了一系列复杂的#include更改,为未使用的代码引入了新的重载,这给数十名开发人员组成的团队中的每一位工程师带来了相当大的头痛
  • 测试上的机器内资源(假设您有自测试的连续构建)。我的团队最近查看了所有最慢的测试,其中许多都是未使用的代码。在本地或作为持续集成的一部分运行测试的工程师正在等待对未使用代码的测试
  • 在可读性方面(再次工程化)。您的头文件表示API。如果它们包含没有人想使用但每个人都必须阅读的函数,那么代码的学习曲线就要困难得多
  • 在代码搜索中(再次工程化)。你会清理你的房子、硬盘还是谷歌硬盘?你搜索的域越多,就越重要的是要有相关的内容来避免误报(或者你使用更复杂的搜索,比如网络搜索引擎)

我想说,在五年的时间里,一般开发人员编写的所有代码基本上都会闲置,所以这种活动永远不会停止。不要让这是你;只写高质量和绝对必要的代码。

最新更新