4

所以干掉代码应该是件好事吧?在我正在从事的一个项目中,存在某些模型/实体或多或少相同的情况,除了使用它们的上下文。也就是说,每个这样的实体都有一个标题、描述、标签、一个 user_id 等和一些其他属性。因此,他们在各自控制器中的 CRUD 操作看起来非常相似。

我的经理争辩说它重复了代码,需要干掉。因此,他提出了 CRUD ruby​​ 模块,当included 负责所有这些实体的控制器的 CRUD 操作时。但最终,Simplicity 受到了损害。代码失去了可读性,因为每个“事物”都被命名为“对象”。调试变得困难,干掉代码的全部意义就丢失了。

这只是一个案例。其中有几个 DRYing 会导致复杂、难以调试的代码。所以问题是,我们什么时候停止干燥代码?因为并非每次您都意识到代码已经失去了简单性(而且代码作者通常从未意识到代码的简单性已经失去了)。此外,如果我们必须在简单性和 DRYed 代码之间进行选择,应该选择什么,如果有一种情况,您只能获得其中任何一个。

4

8 回答 8

4

据我了解,如果干掉代码会导致失去简单性,那么我们就做错了。我认为,我们应该干燥重复且具有单一职责的代码。如果代码职责不同和/或实体的抽象无法命名,我们不会重复代码。代码模式可能会重复,但它是完全不同的代码,有自己的责任。如果 DRYing 导致代码模糊,您可能正在尝试 DRY 具有相似模式的不同职责的代码,这并不是一个真正的好习惯。DRYing 应该增强简单性,而不是抑制它。

于 2009-10-07T06:20:32.470 回答
2

如果您遵循 REST,那么是的,控制器将非常相似并且大部分是样板。我同意你的经理的观点,这是一个问题。

听起来他想出了一个次优的解决方案。要获得更好的,请查看 Jose Valim 的inherited_resources 插件,该插件被合并到 Rails 3中。

于 2009-10-07T09:29:43.693 回答
0

可读性和可维护性是好的代码的两个最重要的特征。不幸的是,有时必须做出妥协。这是一个平衡问题,并不是每个人都会同意。

我自己,我也倾向于你的观点。如果这意味着代码更容易理解,我宁愿有一些明显的重复。

于 2009-10-07T06:21:19.330 回答
0

至于“调试”问题,我习惯于创建这样一个“基类”来包含一个补充字段。该字段是一个简单的字符串,用于标识最派生的类(因此从构造函数传递到构造函数)。然后每条消息都会打印这个字段+对象ID“realtype [id]”,然后一切都变得容易调试了。

现在开始干燥。

DRY 有两件事:

  • 建立层次结构
  • 使用通用代码

第一点现在应该很好理解了。类的层次结构意味着 IS-A 关系。如果两个类具有相似的行为但在其他方面在功能上不相关,那么它们不应该是同一层次结构的一部分。它只会让糟糕的维护者感到困惑并损害可读性。

第二点可以更频繁地使用,尤其是在脚本语言中。对于前面的示例,我认为您可以简单地定义将采用不同类(对不同业务建模)并统一对待它们的通用方法,而不是具有类的层次结构。这样可以避免重复(DRY),但不会牺牲可读性(恕我直言)。

我的 2 克拉。

于 2009-10-07T06:27:22.313 回答
0

如果每个人都告诉我——板着脸——我的代码需要 DRYing,我可能会认为这表明他们要做的任何其他事情都是非常牵强的,而且是为了——的它。

话虽如此,编写代码的简单性(懒惰)和代码本身的简单性(优雅)之间也存在差异。不过,我同意这是一种平衡。有一次我自己也遇到过这种情况(在 PHP 中,但是哦,它让我想起了你的困境):

$checked = ($somevariable) ? "checked=\"checked\"" :"";
echo "<input type="radio" $disabled_checked />";
$checked = ($someothervariable) ? "checked=\"checked\"" :"";
echo "<input type="radio" $checked />";

这甚至不是我正在处理的一个很好的例子。本质上,因为它是一个无线电输入,所以两个输入都需要某种方式来知道哪个是要冒泡的。我知道它有你老板可能称之为“潮湿”的问题,所以我绞尽脑汁想想出一些解决方案会很优雅,切中要害。最后我把它展示给一位高级开发人员,他说:“不,一切正常,它做了它需要做的事情。它只是多出了一行。”

当我被提醒说我对项目的伤害比担心这个问题更多时,我感到如释重负,但与此同时,我仍然感到失望的是,他对一个基本原则如此漫不经心(好像它不是一个他的,虽然我确信它是)。

因此,尽管我同意,您的经理可能只是为了做某事而做某事,但只有当我们努力提出更好的方法和方法时,我们才能获得更好的语言(如 Ruby 和 Python)以及更酷的库(如 Jquery)。

基本上,如果下周你突然有 70 个things而不是 2 个怎么办?如果你老板的物品让这件事变得轻而易举,那他是对的。如果是同样多的麻烦(在代码中或在执行中),他就错了。但这并不意味着没有比保持简单更好的答案,因为它只是几件事。

于 2009-10-07T06:39:08.343 回答
0

DRY 原则的目的是帮助提高代码的“质量”。

如果更改没有提高代码的质量,那么是时候停止了。判断这一点的能力来自经验。随着需求的变化,重构代码的最合适的方式也会发生变化,所以不可能让一切都变得理想——至少你需要先冻结需求。

除非您正在打代码,否则最小化代码的大小通常不应该是质量的考虑因素,所以当唯一的目的是减少代码的大小时,不要 DRY。

复杂的技巧弊大于利。

于 2009-10-07T08:32:07.943 回答
0

应用 DRY 来提高可维护性的一个关键原因是确保当需要更改代码时,只需要在一个地方进行更改,从而避免在需要更改的地方没有更改的风险。

但我并没有讲述整个故事:

对 Dave Thomas 的采访让 DT 说:

DRY 说,每一条系统知识都应该有一个权威的、明确的表示。

我第一次看到“DRY”是在The Pragmatic Programmer中,所以我倾向于在这方面与 Dave 合作。

这里还有一篇值得一读的文章

但 DRY 是一个原则,而不是规则:我们对原则理解得越好,我们就越能够识别应该应用它的情况。

(最后,在我开始“干燥”该代码之前,我想我想要的不仅仅是“或多或少相同”:如果我能清楚地看到未来这两件事可能会出现分歧的方式那么我会倾向于不理他们)。

于 2009-10-07T08:48:35.250 回答
0

对我来说,重复代码是一种可能有多种来源的气味:

  • 缺少变量(引入变量)。
  • 缺少方法(将表达式推入方法)。
  • 特征嫉妒(将行为推入嫉妒的类别)。
  • 过度概括(将泛型类分解为特定的具体类)。
  • 抽象不足(将属性和行为下推到新类中)。

这个列表可能不完整。将其视为一个起点。

当你发现重复时,想想它是什么问题的症状。然后尝试解决这个问题。完成后,请考虑新代码的可读性。如果情况恶化,您可能处于以下位置之一:

  • 您在重复的根源上错误地识别了问题(还原、重新考虑、再试一次)。
  • 重复是必要的权衡(恢复您的更改并接受它)。
  • 您的软件必然是复杂的(提交您的更改并接受它)。

如果可能,请考虑发布示例代码以及此类问题。它们提供了一些具体的解决方法。请记住,很多这些东西都是非常主观的。

于 2009-10-07T09:02:36.403 回答