在最近的一次代码审查中,我在一个类中发现了几行重复逻辑(少于15行)。当我建议作者重构代码时,他认为代码更容易理解。在再次阅读代码后,我不得不同意提取重复的逻辑会稍微损害可读性。
我知道DRY是指导原则,而不是绝对的规则。但总的来说,你是否愿意以DRY的名义伤害可读性?
答案 0 :(得分:58)
Refactoring: Improving the Design of Existing Code
三个规则
你第一次做某事时,你 去做就对了。第二次你做 类似的东西,你在复制时畏缩,但你做了重复的 无论如何。第三次你做类似的事情,你重构。
三次罢工,你重构。
Seibel:因此,对于每个XII调用,您都在编写 实现。
你有没有发现你积累了很多 一些非常相似的代码?Zawinski:哦,是的,当然。通常是第二次或第三次 你已经剪掉了 这段代码就好了,好吧,有时间停下来 切割和粘贴并将其放入 子程序。
答案 1 :(得分:40)
我绝不容忍。由于时间限制或诸如此类的原因,我最终可能会遇到一些问题。但我仍然没有找到重复代码真正有保证的情况。
说它会损害可读性只表明你擅长挑选名字: - )
答案 2 :(得分:31)
就个人而言,我更喜欢保持代码可以理解,首先是
DRY是关于简化代码维护的。在许多情况下,使代码不易理解以删除重复的代码会比使用重复的代码行更容易损害可维护性。
话虽如此,我确实同意DRY是一个很好的目标,在实际可行的情况下。
答案 3 :(得分:12)
如果相关代码具有明确的业务或技术支持目的P,您通常应该重构它。否则你将遇到克隆代码的经典问题:最终你会发现需要修改支持P的代码,你将找不到实现它的所有克隆。
有些人建议3个或更多副本是重构的门槛。我相信如果你有两个,你应该这样做;在一个大系统中找到其他克隆[或者甚至知道它们可能存在]很难,无论你有两个或三个或更多。
现在,在没有任何用于查找克隆的工具的情况下提供此答案。如果你可以可靠地找到克隆,那么重构的原因(避免维护错误)就不那么具有持久性了(具有命名抽象的效用仍然是真实的)。你真正想要的是一种查找和跟踪克隆的方法;抽象它们是确保你“找到”它们的一种方法(通过使发现变得微不足道)。
可以可靠地查找克隆的工具至少可以防止您进行无法更新克隆的维护错误。一个这样的工具(我是作者)是CloneDR。 CloneDR使用目标语言结构作为指导查找克隆,因此无论空格布局,注释中的更改,重命名的变量等如何都可以找到克隆(它适用于多种语言,包括C,C ++,Java,C#,COBOL和PHP) )。 CloneDR将在大型系统中找到克隆,而不会给出任何指导。显示了检测到的克隆,以及 antiunifier ,它本质上是您可能编写的抽象。它的版本(对于COBOL)现在与Eclipse集成,并在您在缓冲区中的克隆内部以及其他克隆的位置进行编辑时向您显示,以便您在那里时可以检查/修改其他克隆。 (你可能做的一件事就是重构它们:)。
我曾经认为克隆是完全错误的,但是人们这样做是因为他们不知道克隆与原始克隆会有什么不同,所以最终的抽象在克隆行为发生时并不明确。现在我相信克隆是好的,如果你可以跟踪克隆,并且在抽象变得清晰之后你试图重构。
答案 4 :(得分:8)
只要您重复任何内容,如果您发现自己犯了错误,就会创建多个位置进行修改,需要对其进行扩展,编辑,删除或其他任何你可能遇到的其他几十个原因迫使你做出改变。
在大多数语言中,将块提取到适当命名的方法很少会损害您的可读性。
这是你的代码,符合你的标准,但我的基本答案是你的“多少钱?” none ...
答案 5 :(得分:3)
你没说什么语言,但在大多数IDE中它只是一个简单的重构 - >提取方法。这样做容易多了,带有一些参数的单个方法比2个重复代码块更易于维护。
答案 6 :(得分:3)
很难抽象地说。但我自己的信念是,即使是一行重复的代码也应该被制作成一个函数。当然,我自己并不总能达到这个高标准。
答案 7 :(得分:3)
重构可能很困难,这取决于语言。所有语言都有局限性,有时重复逻辑的重构版本在语言上可能比重复代码更复杂。
当两个具有不同基类的对象在操作方式上有相似之处时,通常会出现代码LOGIC的重复。例如,两个GUI组件既显示值,又不实现访问该值的公共接口。重构这种系统要么需要采用比所需要的更多通用对象的方法,然后进行类型检查和转换,否则需要重新考虑类层次结构。重组。
这种情况与代码完全重复的情况不同。我不一定要创建一个新的接口类,如果我只打算使用它两次,并且两次都在同一个函数中。
答案 8 :(得分:1)
DRY的重点是可维护性。如果代码难以理解则难以维护,因此如果重构会损害可读性,那么实际上可能无法满足DRY的目标。对于不到15行的代码,我倾向于同意你的同学。
答案 9 :(得分:1)
一般来说,没有。无论如何不是为了可读性。总有一些方法可以将重复的代码重构为一种意图,揭示出像书,IMO这样的常用方法。
如果你想为了避免引入依赖关系而进行违反DRY的论证,这可能会带来更多的权重,你可以获得Ayende的自以为是的观点以及代码来说明here。
除非你的开发人员实际上是Ayende,否则我会坚持DRY并通过意图揭示方法获得可读性。
BH
答案 10 :(得分:1)
我接受没有重复的代码。如果在多个地方使用某些东西,它将成为框架的一部分或至少是实用程序库。
最好的代码行是一行未编写的代码。
答案 11 :(得分:0)
这实际上取决于很多因素,代码的使用量,可读性等。在这种情况下,如果只有一个代码副本,并且这种方式更容易阅读,那么也许它很好。但是如果你需要在第三个地方使用相同的代码,我会认真考虑将它重构为一个共同的函数。
答案 12 :(得分:0)
可读性是代码可以拥有的最重要的东西之一,我不愿意妥协。重复的代码是一种难闻的气味,而不是致命的罪。
话虽如此,这里也有问题。
如果这段代码应该是相同的,而不是巧合地相同,则存在可维护性风险。我会在每个地方都有评论指向另一个,如果它需要排在第三位,我会重构它。 (我实际上有这样的代码,在两个不共享相应代码文件的不同程序中,因此每个程序中的注释指向另一个。)
你还没有说过这些线是否是一个连贯的整体,执行一些你可以轻松描述的功能。如果他们这样做,重构它们。这种情况不太可能发生,因为您同意代码在两个地方嵌入更具可读性。但是,您可以寻找更大或更小的相似性,并可能将函数分解为简化代码。仅仅因为重复了十几行代码并不意味着一个函数应该由十几行组成而不是更多。