【问题标题】:When to violate YAGNI? [closed]什么时候违反 YAGNI? [关闭]
【发布时间】:2009-02-16 08:56:07
【问题描述】:

YAGNI“原则”指出,您不应该在需要之前就专注于提供功能,因为无论如何“您不会需要它”。

无论如何,我通常倾向于使用常识而不是任何规则,但有时我觉得如果你有充分的理由,过度设计或未来证明某些东西是有用的,即使你可能永远不会使用它。

我现在手上的实际情况差不多是这样的:

我有一个应用程序必须通过一个简单的专有通信协议(OSI 4 级)运行。该协议具有一组理想的特性(例如遵循 NORM 规范),这些特性为应用程序提供了稳健性,但并非严格要求(UDP 多播可以执行)。

还有一个事实是,该应用程序将来可能(但不一定)被其他无法访问专有解决方案的客户使用,因此需要另一个解决方案。事实上,我知道该应用程序的另一个客户的可能性很高。

那么,你的想法是什么?我应该只为专有协议进行设计,而将重构、接口提取等留到我真正需要的时候,还是应该现在设计考虑(不是目前的)未来?

注意:为了清楚起见,我很想听听关于一般问题(何时违反 YAGNI)的各种意见,但我真的很想对我目前的问题提出一些建议或想法两难:)

【问题讨论】:

  • 现在在programmers.stackexchange.com 上问这个问题更合适...
  • 想象一下只使用 2 位数字的 COBOL 约会系统。那将是违反 YAGNI 的好地方:)

标签: yagni


【解决方案1】:

YAGNI 应用于代码的原因是更改成本低。使用良好、重构良好的代码在以后添加功能通常很便宜。这与说构造不同。

在协议的情况下,稍后添加更改通常并不便宜。旧版本中断,它可能导致通信失败,以及一个 N^2 测试矩阵,因为您必须针对每个其他版本测试每个版本。将此与单个代码库进行比较,其中新版本只需要自己使用。

所以在你的情况下,对于协议设计,我不会推荐 YAGNI。

【讨论】:

  • 我不明白你的警告。添加新协议不应破坏现有功能,这就是回归测试的目的。如果你想要客户,你只需要测试“每个版本与其他版本”使用不同的协议进行互操作,这似乎不需要。所以:YAGNI。
【解决方案2】:

恕我直言

  • 我会说先去 YAGNI。使用“最简单的方法”让它在没有 NORM 规范的情况下工作。
  • 接下来比较未来进行“设计更改”的成本是否比现在进行更改明显更高。您当前的解决方案是否可逆?如果您明天或几个月后可以轻松进行更改,请不要现在进行。如果您现在不需要做出不可逆转的设计决策.. 延迟到最后一个负责任的时刻(以便您有更多信息来做出更好的决定)

如果您非常确定地知道即将关闭并且稍后添加它会很痛苦,不要成为鸵鸟......为它设计。
例如我知道在产品发货之前需要诊断日志。一个月后添加日志代码将比今天在我编写每个函数时添加它更加努力......所以即使我现在不需要日志,我也会覆盖 YAGNI。

另见:T. & M. Poppendieck 的精益书籍更能解释上述第 2 条的困境。

【讨论】:

    【解决方案3】:

    很好地构建你的程序(抽象等)并不是 YAGNI 所适用的。你总是想很好地组织你的代码。

    澄清一下,我认为您目前的困境是由于过度应用 YAGNI 造成的。以这样一种方式构建你的代码,使你有一个可重用的库来使用这个协议,这只是一个很好的编程实践。 YAGNI 不适用。

    【讨论】:

    • 是的 - YAGNI 是关于范围控制和设计的。这不是编写蹩脚代码的许可。
    【解决方案4】:

    我认为 YAGNI 可能不适用于你想学习的东西 :) YAGNI 适合专业人士,但不适合学生。当你想学习时,你总是需要它。

    【讨论】:

      【解决方案5】:

      我认为它非常简单明了:

      当你知道,完全确定,你会需要它时违反 YAGNI

      【讨论】:

        【解决方案6】:

        我不会担心的。你意识到“YAGNI”的事实意味着你已经在务实地思考。

        我想说,无论此处发布什么内容,从统计上讲,与没有以相同方式分析其实践的人相比,您更有可能提出更好的代码。

        【讨论】:

        • 我确信 Joel Spolsky 表达了类似的观点,但我找不到该帖子。不过,杰夫·阿特伍德有这个:codinghorror.com/blog/archives/001020.html
        • 不,不是那个。我认为它的要点是,如果您正在阅读本文并想知道自己是否适合作为开发人员,那么您已经赢了。如果您努力通过阅读和学习来提高自己,那么您已经处于最高百分位。
        【解决方案7】:

        我同意 Gishu 和 Nick 的观点。

        稍后设计协议的一部分通常会导致诸如“该死,我应该这样做,现在我不得不使用这种丑陋的解决方法”这样的想法

        但这也取决于谁将与此协议交互。
        如果您控制两端,并且它们将同时更改版本,您可以随时重构协议就像使用普通代码界面一样。

        关于稍后进行额外的协议功能实现,我发现实现该协议有助于验证其设计,因此如果需要,您可能至少想做一个简单的非生产代码示例来测试它官方设计。

        【讨论】:

          【解决方案8】:

          在某些情况下,违背 YAGNI 的直觉是有意义的。

          这里有几个:

          遵循编程约定。尤其是基类和接口契约。例如,如果您继承的基类提供 GetHashCode 和 Equals 方法,则覆盖 Equals 但不覆盖 GetHashCode 会破坏开发人员在覆盖 Equals 时应遵循的平台记录规则。即使您发现实际上不会调用 GetHashCode,也应遵循此约定。不覆盖 GetHashCode 是一个错误,即使没有当前的方法来激发它(除了人为的测试)。该平台的未来版本可能会引入对 GetHashCode 的调用。或者,另一位查看过文档(在本例中为您所继承的基类的平台文档)的程序员可能理所当然地期望您的代码在不检查您的代码的情况下遵守。另一种思考方式是,所有代码和适用文档必须保持一致,即使与其他人编写的文档(例如平台供应商提供的文档)一致。

          支持自定义。 尤其是不会修改您的源代码的外部开发人员。您必须在代码中找出并实现合适的扩展点,以便这些开发人员可以实现您从未想过的各种插件功能。不幸的是,您将添加一些外部开发人员最终很少使用的可扩展性功能,这对课程来说是很正常的。 (如果可以提前与所有外部开发人员讨论可扩展性要求或使用频繁的开发/发布周期,那很好,但这并非对所有项目都可行。)

          断言、调试检查、故障保护等这些代码实际上并不是您的应用程序正常工作所必需的,但它有助于确保您的代码现在和将来在修订时正常工作制作完成。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2010-10-17
            • 1970-01-01
            • 1970-01-01
            • 2012-09-05
            • 2010-09-20
            • 1970-01-01
            • 2012-09-19
            相关资源
            最近更新 更多