我多次听到必须从项目中删除未使用的代码。但是,对我来说“为什么?”还不清楚。
我不删除的观点是:
- 代码已经写好了,花了很多力气
- 可以在合成环境和实际环境中测试代码
- 如果组织得当(分组,单独的软件包,松散耦合的等等),它不会影响您的整体代码分析或重构
- 将来可能会使用代码
- 删除后,作者可能会感到不舒服
有人可以解释删除(或保留)未使用代码的优点吗?
我多次听到必须从项目中删除未使用的代码。但是,对我来说“为什么?”还不清楚。
我不删除的观点是:
有人可以解释删除(或保留)未使用代码的优点吗?
Answers:
删除未使用的代码的一些原因如下:
对于任何刚从事项目工作的人,他们不仅必须了解工作代码,而且还必须了解未使用的材料。这是浪费时间,造成混乱。
有一种危险,有时某人会做出无意中涉及“休眠”代码并可能引入错误的更改。我知道这是在我从事的项目上发生的。
任何代码的维护都是管理负担。通过保留旧的冗余代码,负担增加了。例如,合并主分支中的更改会变得更加困难,因为有更多的代码需要处理,并且出错的可能性也更大。
随着时间的流逝,越来越多的旧未使用代码被添加到代码库中。这增加了混乱,潜在的误解和管理开销。
再次使用未使用的代码的可能性很小。随着时间的流逝,重复使用的可能性减小。如果要删除代码并且认为代码足够重要,则可以将代码分支出来并进行记录。
编码人员对他们可能会努力工作的代码所产生的任何个人感觉都是可以理解的。但是要成为专业人士,就必须将这些想法放在一边,以求更好。时间代表没有人,在工作的代码库中没有保留历史代码的地方。
@suspectus在介绍删除代码的原因方面做得非常出色;我想向您介绍一些用于保存代码的项目符号。
- 代码已经写好了,花了很多力气
但是,如果未使用已编写的代码,那么这只是成本,而没有(未来)价值。付出的努力是徒劳的,并且保留那些努力的未使用产品并不能验证那些努力。我们保留代码是因为它现在很有用,而不是作为对作者工作的某种纪念。
- 可以在合成环境和实际环境中测试代码
抱歉,我不知道您的意思。
- 如果组织得当(分组,单独的软件包,松散耦合的等等),它不会影响您的整体代码分析或重构
如果它存在于代码库中,则无论组织得如何好,它都会增加维护和理解负担。诚然,它可以使组织是少的负担,但如果它不见了,这是没有包袱可言。
- 将来可能会使用代码
在敏捷学校中,我们说YAGNI:您将不需要它。是的,您将来可能会用到它,但对于今天的需求,我们今天还不够了解,无法以任何可靠性进行预测。否则认为傲慢自大。我们明天能知道的是:我们希望我们的代码库易于修改,而未使用的代码有损于该特性。
- 删除后,作者可能会感到不舒服
作者必须克服它。我们写的所有东西都证明没有用-能够指向所有正在使用的代码体(因为删除了未使用的内容)要比指向其中的代码体好得多一些方法,“而实际上是在使用它!”
代码已经写好了,花了很多力气
这也是不必要的。如果您不将其用于任何用途,则它(按定义)是无用的,无论它做了什么或花费了多少精力。
可以在合成环境和实际环境中测试代码
如果没有用,即使对其进行了测试,它仍然没有用。如果代码无用,则对其进行的测试也将无用(因此,将注释的代码保留在那里,会产生歧义-是否保留测试?如果您拥有注释代码的客户代码,那么您是否也注释了客户代码? )
如果组织得当(分组,单独的软件包,松散耦合的等等),它不会影响您的整体代码分析或重构
不是这样 您的所有工具(源代码控制,静态分析,文档提取器,编译器等)将运行速度较慢,因为它们必须处理更多数据(该数据的较大或较小部分是噪声)。
如果代码未在另一方面井井有条,它会弄乱静态分析,重构和其他任何。
您正在将噪声引入到工具输入中,并希望它们能够正确应对。
如果您的静态分析工具计算注释/代码比率怎么办?您只是把它弄乱了,直到昨天才有意义(或者在注释了代码的任何时候)。
最重要的是,带注释的代码块会延迟理解代码以进行维护和进一步开发的时间,而这种延迟几乎总是会花费很多。问问自己:如果您需要了解功能的实现,那么您宁愿看什么?两行清晰的代码,或两行代码和另外二十六个不再实际的注释?
将来可能会使用代码
如果是这样,您将在团队的首选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);
彻底的变化。如果无效代码中还存在系统中各处需要更改的内容,您是否要进行更改?很难确定它是否绝对不在某处使用,因此始终存在风险。即使它不会破坏任何内容,但如果在更改后将其重新使用,则无效代码将完全起作用吗?
在进行彻底更改时,开发人员还必须检查包含代码的每个位置,对于无效代码,这是多余的。在代码失效后,检查它们会花费更长的时间,因为很难验证是否在任何地方都没有使用它。
如果您知道未使用代码库的一部分,这将非常有价值,因为您可以将其删除。如果保留它,那么将来很难或几乎不可能确定它实际上未被使用。例如,某些以令人惊讶的方式使用代码的事物:反射,动态调用由字符串连接的例程,eval,框架魔术。
但是,如果将来很有可能会使用代码,则将其添加到其他代码中而不是在版本控制系统中,则更容易添加。您可能忘记了一段时间后代码中没有的任何单词,因此很难从VCS的肠道中找到代码。但是我会让死代码很少存在,即使那样我也会注释掉代码。
这个列表看似简单,但是每一个都以数百种不同的方式表现出来,从而增加了在整个开发过程中协同作用的阻力。效率低下通常可以直接和数学的方式证明或证明。
为了回应您的观点...
但是它通常必须维护。它还会显示在文件查找等内容中。
我不确定这是什么意思。我认为与上一个相同。您的意思是代码已经过测试,清理代码可能意味着它需要重新测试。这是通常值得的成本,因为它将在90%的时间内还清,并避免在投入生产之前应进行清洁。几乎所有代码都有两次迭代,使其工作并使其干净。之所以必须进行两次测试,是因为有人跳过了最后一步。如果您的代码也太昂贵以至于无法读取差异,请进行测试(可能是因为很多未使用的代码太杂乱了),等等,这就是另外一个完整的问题。
无论如何,您的代码都应该像这样,但这只能适度缓解问题。听到某些东西应该组织得还不干净,这是最奇怪的说法。尝试保持代码模块化并减少依赖关系是正常的,但是您也想要可重用的代码,并且如果所有模块都是孤岛,那么您可能还没有干过。您可能还会发现自己进行了过多的去耦,但是却无济于事,从而减轻了未使用的混乱代码的问题。
许多人看重编写代码。如果现在不使用它,它将是无谓的,实际上,当您沿这条路走时,通常只有一小部分未使用的代码成为已使用的代码。极有可能未使用的代码不太可能是可用或已使用的代码。最可能被重用的代码是正在使用的正在执行某些操作的代码。
更糟糕的是,未使用的代码没有目的。当有人出现并不得不更改某些东西而最终影响未使用的代码时,他们将被困在那儿,试图找出这些未使用的代码是什么目的而无需做的。
人们在开始时很容易感觉到这种情况,因为代码需要大量的精力。但是一旦流利并习惯了,代码就会变得像骑自行车一样。您会发现,编写这样一段代码的成本直线下降,而使代码不断攀升的成本却越来越高。
这是作者的问题。一方面,将大量未使用的代码留给其他人处理是很自私的。另一方面,如果作者将自己的想法放在代码质量之上,那么他们可能不应该编写代码。这样做会导致代码损坏时无法修复他们的代码,因为这会伤害他们的感受。如果有人仅仅因为代码是他们的而不是代码的好而附加了代码,这不是一个好兆头。作者应该为自己的代码被清理感到高兴。这就像有人为您取出垃圾并扔进垃圾箱。
如果有人为我做的话,我将过月。可能更容易克服这些感觉,而不是等待别人去做,而是自己尝试做。不断迭代地重写已完成的一段代码,使其性能更好,简洁明了,多余更少,更灵活,但每次代码更少。尽量不要对代码量感到满意,而只需很少的代码就可以实现多少。这正在逐步升级,一旦完成,您的所有代码都会以良好的水平出现,因此不需要经常进行升级。
仅检查代码是否仍可编译还不够。在C ++中,如果删除“未使用”的隐式定义的方法(如operator=
不会出现编译器错误),则该类将仅默默地开始使用(可能不正确)默认实现。在Java或C#中,可以通过反射使用代码。在面向对象的语言中,继承可以发挥作用(现在可以调用基类)。在几乎所有语言中,另一个重载函数都可能已被接管。
在版本控制中检查代码的使用期限,而不仅仅是检查是否未使用。我看到过看起来未使用但刚刚提交的代码,实际上这是另一个开发人员项目的第一步。
您需要支付维护代码:
#include
变更链,为未使用的代码引入了新的重载,这导致数十名开发人员团队中的每个工程师都感到相当头痛。我想说的是,平均每个开发人员编写的所有代码在五年的时间里都不会使用,因此这项活动永远不会停止。不要让这个成为你;只写高质量和绝对必要的代码。