如果我的代码不能兼而有之,那么应该是DRY还是可读的?


14

我正在为一个简单的加密练习编写Ruby代码,并且经常遇到这个难题(如果您必须知道的话,该练习是单人密码)。这是一个问题,我是否应该使用使函数可读的描述性变量和单步语句来填充我的逻辑,而不是使用简洁,密集的语句来消除重复和/或最大程度地减少错误的机会,从而填充我的逻辑。

我最近的例子:我的程序接受输入,并且由于严格的格式准则,它可以轻松确定输入是否应该加密或解密。为简化起见,一旦加密密钥和消息被转换/生成为兼容,就可以从加密消息中减去密钥,或者将密钥添加到未加密消息中,以获得所需的输出(将密钥视为加密,消息+加密=代码;代码-加密=消息)。DRY位置告诉我,我应将加密的消息与未加密的消息进行不同的转换,这样就无需区分使用加密密钥并将其应用于消息的功能。我发现这意味着我需要在函数中嵌套一些if语句,但逻辑似乎很牢固。但是,此代码不容易阅读。

另一方面,我可以编写两个不同的函数,这些函数根据应用程序确定加密或解密时设置的标志来调用。这将更易于阅读,但会复制将加密密钥应用于消息的高级功能(导致对其进行加密或解密)。

我应该倾向于可读代码还是简洁代码?还是我错过了获得此功能并满足这两个原则的另一种方法?这是一个必须考虑项目目的并做出最佳决策以达到该目的的规模吗?

到目前为止,相对于可读代码,我倾向于强调简洁的DRY代码。


2
可用第一,干燥第二,可读第三。高度可用的代码会导致高度易读的消费代码,从而更容易满足DRY和可读性要求。这就是为什么您想采取一些令人讨厌的复杂性,如果无法将其改进的话,可以使用一个不错的API将它们包装在某个地方。至少与他们进行交互的代码也可以避免这种方法的破坏。
Jimmy Hoffa 2013年

4
一些实际的代码示例可能会有所帮助,我怀疑您缺少某些第三种方法,例如具有干式可读代码的高阶函数
jk。

2
不能重复。简明易读和DRY易读是两个非常不同的比较。没有干比没有简洁要危险得多。
djechlin

只是不要陷入这样的陷阱:假设大量重复的代码更具可读性,因为它属于可预测的模式。我怀疑这样想可能很容易,除非您维护了一个重复性很高的系统,以至于在一个分支中发现了细微的错误,而在另一个几乎相同的分支中却找不到了。
KChaloux

我不明白“将加密密钥应用于邮件的高级功能”的含义。如果您意味着加密和解密之间存在重叠,请考虑使用提取方法重构来分解出公共部分。
亚伦·库兹哈斯

Answers:


20

DRY是一个准则,而不是一种宗教。那些将DRY置于最重要的位置的人,把它做得太远了。

首先,可用代码至关重要。如果代码没有用处和可用性,那么它就不是……而且首先编写它没有任何意义。

其次,有一天,有人将不得不维护您的代码。如果您的代码无法维护,则它们会破坏您的“美丽”的密集,简洁,DRY设计,同时诅咒您的名字。不要这样 我就是那个人,每当我在代码注释中看到某个名字时,我都会发抖。

编写缺少“描述性变量”的密集代码,并使用lambda将所有内容粘贴到嵌套三元表达式中,而无需任何文档,这很聪明。很高兴知道您可以做到-但事实并非如此。聪明的代码很难调试。 避免编写聪明的代码

花在软件上的大部分时间都花在了软件的维护上,而不是第一次编写。编写代码,以便您(或其他人)可以快速,轻松地修复错误并根据需要向其添加功能,而只需进行很少的理想设计更改即可。


直觉与否,您遇到了我忽略的问题。我一直在尽我所能编写“聪明”的代码,只是知道我可以做到,我同意很高兴知道这一点,但是在这里我同意你的看法,这是一种不好的做法。现在,我有很多重构工作。
lutze 2013年

1
@lutze我是一个perl,有时是ruby编码器,当然可以理解在其中编写聪明代码的诱惑。此答案的预发布版本包括Larry Wall关于傲慢的一句话-我认为这在处理将要维护的代码时是非常重要的优点。由于语言的简洁性,有时很难获得编写更多代码的优势,而不是尝试编写精巧的密集代码……直到必须维护它为止。

17

基于您是否理解DRY的问题,我不确定。DRY代码与简明代码不同。通常情况恰恰相反。

在这里,我不确定这个例子有什么大不了的。创建一个加密功能,一个解密功能,通用功能的助手(混合字节),以及一个简单的前端以接受输入并确定加密/解密...无需重复。

通常,DRY和可读性都可以帮助维护和扩展代码。并非所有方案都是平等的,删除一些重复的可读性很高并不是一个好主意,也没有一堆重复的代码可以增加一些可读性。

如果按一下,我更喜欢可读性。重复的代码仍然可以测试-不可读的代码会导致您做(和测试)错误的事情。


要点,我确实已经将DRY原则与简洁代码的目标结合了一点。
lutze

12

我不熟悉您的具体情况,但可以提供一些一般性指导。

可读性和DRY的目的都是可维护性

在大多数情况下,可维护性很重要,与编写代码相比,您将花费更多的时间维护代码。如果您认为编写代码是一种特殊的维护,则尤其如此。

不幸的是,DRY经常被误解。这部分是因为它看起来是如此简单,但是就像许多简单的事情一样,它可能非常复杂。

DRY的意图是,每个功能单元都只存在于一个地方。如果遵循该原则,则负责更改或验证功能的代码维护者可以一次处理该代码。如果不遵循DRY,则存在非常现实的危险,即该功能的某些副本将无法正确维护。

对DRY的最直接的违反是复制粘贴编码,其中整个代码块在代码库中重复出现。以我的经验,这是令人惊讶的普遍现象,并且没有增加可读性的方式。因此,重构代码以引入通用方法总是会增加DRY一致性和可读性。

第二种最明显的违规行为是“复制粘贴并稍加更改”。同样,重构以引入带有参数的通用方法,或者将函数分解为多个步骤并抽象出通用性几乎总是可以提高可读性。

然后是更细微的冲突,其中功能重复但代码不同。这总是不容易发现的,但是当您看到它并重构以将通用代码放入单个方法/类/函数中时,该代码通常比以前更具可读性。

最后,还有重复设计的情况。例如,您可能在代码库中多次使用了状态模式,并且您正在考虑进行重构以消除这种重复。在这种情况下,请谨慎操作。您可能会通过引入更多抽象级别来降低可读性。同时,您实际上不是在处理功能性的重复,而是在处理抽象的重复。有时值得,但有时却不值得。您的指导原则是问“其中哪一个更易于维护”。

每当我做出这些判断调用时,我都会尝试考虑人们花在维护代码上的时间。如果代码是核心业务功能,则可能需要更多维护。在那种情况下,我的目标是使对熟悉代码库和所涉及抽象的人员可以维护代码。我会更乐于引入更多抽象来减少重复。相反,如果脚本涉及太多抽象,那么对于维护人员而言,很少使用且很少维护的脚本可能较难掌握。在那种情况下,我会在重复方面犯错。

我还考虑了团队其他成员的经验水平。我避免与经验不足的开发人员进行“奇特”的抽象,但要利用成熟的团队采用经行业认可的设计模式。

在脑震荡中,您的问题的答案是做任何使您的代码最易于维护的事情。在您的情况下,这取决于您的决定。


我认为您已完全确定了我的问题之一。我给出的我尝试不重复的功能的示例很可能是抽象的重复。
lutze 2013年

+1。我目前正在处理一个滥用复制和粘贴到一个荒谬程度的系统。分解出一个单一的复制/粘贴代码在从今天我的一个类400线去除方法。不幸的是,我在900行方法中找到了它
KChaloux13年

1
如果两个代码构造当前执行相同的操作,但是对一个代码的更改通常不应意味着对另一个代码的更改,则复制/粘贴可能比分解式通用功能更好。如果代码使用两个字符换字符的相同方法出于不同目的执行相同的操作,并且始终根据所需目的来进行方法的选择,那么如果稍后出于某些目的之一需要做些事情,则仅更改适当的方法即可方法只会影响那些应该受到影响的行为。使用单一的通用方法可能会使更改变得更加困难。
2014年

7

如果在尝试使它们变干时,它们的功能变得更复杂,更长(因此可读性更差),则说明您做错了。您试图在一个函数中添加太多功能,因为您认为这是避免在第二个函数中重复相同代码段的唯一方法。

使代码DRY几乎总是意味着将通用功能重构为较小的功能。每个功能都应该比原始功能更简单(因此更具可读性)。为了使原始函数中的所有内容都处于相同的抽象级别,这也可能意味着将其他部分未使用的其他部分重构出来。然后,您原来的函数将变成“高级函数”,调用较小的函数,并且它也变得更小,更简单。

因此,执行此操作最多会导致代码中的抽象级别有所不同-有些人认为此类代码的可读性较差。以我的经验,这是一个谬论。这里的重点是给较小的函数起好名字,引入命名数据类型和抽象,而第二个人可以很容易地理解它们。这样,“ DRY”和“可读性”应该很少,很少发生冲突。


2

虽然我不确定在这里到底是什么引起了问题,但是我的经验是,当您发现DRY和可读性发生冲突时,该是重构某些内容的时候了。


0

我会选择可读(=可维护)而不是每周的任何一天进行DRY。实际上,两者通常是一致的,获得DRY概念的人通常会产生(大部分)可读代码。


2
如果没有任何解释,那么如果有人发表相反的意见,此答案可能会毫无用处。例如,如果有人发布诸如“我会选择DRY(=可维护)而不是一周中的任何一天可读”这样的声明,那么此答案将如何帮助读者选择两种相反的观点?考虑将其编辑成更好的形状
2013年

0

在我的职业生涯中,我非常非常非常非常罕见地发现了一个合法案例,该案例使DRY具有可读性。首先使其可读。命名好。如果需要,请复制并粘贴。

现在退后一步,看看您创造的整体效果,就像画家退后一步来查看他们的画作一样。现在,您可以正确地识别重复了。

重复的代码应重构为自己的方法,或提取为自己的类。

重复代码应该是万不得已的方法。首先可读且干,如果限制重复代码的范围,则会使可读性失败。

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.