【问题标题】:When to stop DRYing up the code?何时停止干燥代码?
【发布时间】:2009-10-07 06:16:12
【问题描述】:

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

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

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

【问题讨论】:

  • 应该成为社区维基
  • 为了清楚起见:“DRY 原则”是对“避免重复”的混淆。

标签: ruby-on-rails ruby dry design-principles


【解决方案1】:

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

【讨论】:

  • 是的,每次我想在屏幕上打印一些东西时,我都必须重复echo。也许我应该为该代码的所有重复使用创建一个函数。我会称之为...echo()。 :p
【解决方案2】:

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

听起来他想出了一个次优的解决方案。如需更好的,请查看 Jose Valim 的 inherited_resources plugin,即 incorporated into Rails 3

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

      现在开始干燥。

      有两件事要干燥:

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

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

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

      我的 2 cts。

      【讨论】:

      • 如果没有层次结构,泛型方法可能会再次包含一些由“if”、“case”或“eval”组成的 Voodoo 逻辑(当然不是在所有情况下),恐怕, 也是维护者头疼的迹象。
      • 补充字段有什么用my_obj.class.name没有做到的?
      【解决方案5】:

      如果每个人都直截了当地告诉我我的代码需要 DRYing,我可能会认为这表明他们要做的任何其他事情都将是非常牵强的。 -为了它。

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

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

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

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

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

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

      【讨论】:

      • Anthony:检查你的代码。 $checked 还是 $disabled_checked?是哪个?
      • 很好看。这是我对这个愚蠢帖子的第四次编辑。我已经醒太久了。
      【解决方案6】:

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

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

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

      复杂的技巧弊大于利。

      【讨论】:

        【解决方案7】:

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

        但我并不是在讲述整个故事:

        This interview with Dave Thomas 有 DT 说:

        DRY 表示系统的每一部分 知识应该有一个 权威的,明确的 表示。

        我第一次看到“DRY”是在The Pragmatic Programmer,所以我倾向于和戴夫一起去。

        还有一篇文章值得一读here

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

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

        【讨论】:

          【解决方案8】:

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

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

          此列表可能不完整。把它当作一个起点。

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

          • 您错误地确定了重复问题的根源(还原、重新考虑、重试)。
          • 重复是必要的权衡(还原您的更改并接受它)。
          • 您的软件必然很复杂(提交您的更改并接受它)。

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

          【讨论】:

            猜你喜欢
            • 2013-09-16
            • 2014-12-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多