我听到的最常见的论点之一是不遵守 坚硬的 面向对象设计的原理是 Yagni (尽管Arguer通常不称呼它):

“可以将功能X和功能Y放入同一类是可以的。这真是太简单了,为什么要添加新类(即复杂性)。”

“是的,我可以将所有的所有业务逻辑直接放入GUI代码中,这要容易得多,更快。这将永远是唯一的GUI,而且很不太可能出现重大新要求。”

“如果在不太可能的新要求情况下,我的代码变得太混乱了,我仍然可以为新要求重构。因此,您的'如果您以后需要……'参数不计算在内,该怎么办。”

您反对这种做法最有说服力的论点是什么?我怎么能真正 显示 这是一种昂贵的做法,尤其是对于在软件开发中没有太多经验的人来说。

有帮助吗?

解决方案

设计是权衡的管理和平衡。 Yagni和Solid并没有冲突:前者说 什么时候 为了添加功能,后者说 如何, 但是他们都指导设计过程。下面我对您的每个特定报价都使用Yagni和Solid的原则。

  1. 构建可重复使用的组件的三倍是单使用组件。
  2. 可重复使用的组件应在三个不同的应用程序中尝试,然后才能足够通用到重复使用库中。

- 罗伯特·格拉斯(Robert Glass) 三个规则, 软件工程的事实和谬论

重复使用的可重复使用的组件的关键要素是首先在多个位置找到相同目的的关键要素,并且 然后 移动它。在这种情况下,Yagni通过在需要的地方插入该目的,而不必担心可能的重复,而不是添加通用或可重复使用的功能(类和功能)。

在初始设计中,最好的方法是显示Yagni不适用的何时确定具体要求。换句话说, 在编写代码之前进行一些重构 证明重复不仅可能存在,而且已经存在:这证明了额外的努力。


是的,我可以将所有业务逻辑直接放入GUI代码中,这要容易得多,更快。这将永远是唯一的GUI,而且新要求明显不太明显。

它真的是唯一的用户界面吗?是否计划了背景批处理模式?会有网络界面吗?

您的测试计划是什么,您将在没有GUI的情况下测试后端功能?是什么使您可以轻松测试GUI,因为您通常不想测试外部代码(例如平台生成GUI控件),而是专注于您的项目。

可以将功能X和功能Y放入同一类是可以的。为什么要添加新类(即复杂性),这太简单了。

您能指出需要避免的常见错误吗?有些事情很简单,例如平方数(x * x vs squared(x))对于一个过于简单的例子,但是如果您可以指出某人犯的具体错误(尤其是在您的项目中或团队中的人),则可以显示将来的共同班级或功能如何避免这种情况。

如果在新要求的不太可能情况下,我的代码变得太混乱了,我仍然可以重构新要求。因此,您的“如果您以后需要...”参数不算在内。

这里的问题是“不太可能”的假设。您同意这不太可能吗?如果是这样,您与此人同意。如果不是这样,您对设计的想法与此人的观念不一致 - 解决差异将解决问题,或者至少向您展示下一步去哪里。 :)

其他提示

听起来您正在用砖墙吵架。我是Yagni的忠实粉丝,但与此同时,我也希望我的代码会 总是 至少在两个地方使用:应用程序和测试。这就是为什么UI代码中的业务逻辑之类的事情不起作用的原因;在这种情况下,您不能单独测试UI代码的业务逻辑。

但是,从您所描述的响应来看,听起来这个人对做得更好不感兴趣。那时,没有任何原则会帮助他们。他们只想竭尽所能。我甚至说,这不是Yagni推动他们的行动,而是懒惰,而且您独自一人不会击败懒惰(除了威胁经理或失业之外,几乎什么也没做)。

我喜欢用“一半而不是一半”来考虑Yagni,从37Signals中借用这句话(https://gettingreal.37signals.com/ch05_half_not_half_assed.php)。这是要限制范围,因此您可以专注于做最重要的事情。这不是马虎的借口。

GUI中的商业逻辑对我来说是一半的。除非您的系统微不足道,否则如果您的业务逻辑和GUI尚未独立更改(几次),我会感到惊讶。因此,您应该遵循SRP(固体中的“ S”)和重构 - Yagni不适用,因为您已经需要它。

如果您今天在做额外的工作以满足假设的未来要求,那么关于Yagni和不必要的复杂性的论点绝对适用。当那些“如果以后我们需要...”场景无法实现时,您会陷入更高的维护成本,而这些抽象现在妨碍了您实际拥有的更改。在这种情况下,我们正在谈论通过限制范围来简化设计的方法 - 做一半,而不是一半。

没有答案,或者说,您和您的对话者都不喜欢答案:Yagni和Solid都可能是错误的方法。

试图与一支没有经验的团队一起坚持下去,或者一支具有紧张目标的团队几乎可以保证您最终会得到一堆昂贵,过度工程的代码...这不会是坚实的,只是过度工程(又名欢迎到现实世界)。

试图去Yagni进行一个长期项目,并希望您以后可以重构只能在一定程度上工作(又称对现实世界的欢迎)。 Yagni擅长于概念验证和示威者,获得市场/合同,然后能够投资于更稳定的东西。

在不同的时间点,您都需要两者。

这些原则的正确应用通常不是很明显,并且很大程度上取决于经验。如果您不自己做,这很难获得。每个程序员都应该有这样做的后果经验,但是当然,它总是应该不是“我的”项目。

向他们解释问题是什么,如果他们不听并且您无法让他们倾听,那就让他们犯错。如果您经常需要解决问题,那么您应该抛光简历。

根据我的经验,这总是一个判断电话。是的,您不必担心实施的每个小细节,有时将方法粘贴到现有类中是可以接受的,但丑陋的解决方案。

的确,您以后可以重构。重要的一点是实际上 进行重构. 。因此,我认为真正的问题不是偶尔的设计妥协,而是一旦显然存在问题,就推迟了重构。实际上,经历它是困难的部分(就像生活中的许多事情一样……)。

至于您的各个观点:

可以将功能X和功能Y放入同一类是可以的。为什么要添加新类(即复杂性),这太简单了。

我要指出的是,在一个班上有所有东西是 更复杂 (因为这些方法之间的关系更加亲密,更难理解)。拥有许多小课并不复杂。如果您觉得清单要长时间,只需将它们整理成包装,就可以了:-)。就我个人而言,我发现仅将课程分为两到三个类,可以对可读性有很大帮助,而无需任何进一步的变化。

不要害怕小课,不要咬;-)。

是的,我可以将所有业务逻辑直接放入GUI代码中,这要容易得多,更快。这将永远是唯一的GUI,而且新要求明显不太明显。

如果有人可以说“很不可能明显的新要求出现。”我相信那个人真的 真的 需要现实检查。钝,但温柔...

如果在新要求的不太可能情况下,我的代码太混乱了,我仍然可以重构新要求。因此,您的“如果您以后需要...”参数不计数

这具有一些功绩,但前提是他们实际上进行重构。因此,接受它,并将他们履行承诺:-)。

坚实的原则允许软件适应更改 - 在需求和技术更改(新组件等)中,您的两个论点是针对不变的要求:

  • “很不可能有明显的新要求。”
  • “如果不太可能有新要求的情况”

真的可以吗?

在开发的各种开支方面,无法替代经验。对于许多从业者来说,我认为在糟糕的情况下做事,难以维持的方式从未给他们带来问题(嘿!工作安全)。从长远来看,我认为这些费用变得很明显,但是提前做些事情是别人的工作。

这里还有其他一些很好的答案。

可以理解,灵活并能够修复和改进的能力总是您的事物 需要。的确,Yagni假设您可以相对轻松地证明必要时可以回来并添加新功能,因为没有人会做一些疯狂的事情,例如在班级中(该课程中的Yagni!)或将业务逻辑推向UI逻辑,例如Bunging Bunging Bunging无关的功能。

有时候,过去似乎疯狂的事情在过去是合理的 - 有时,UI与业务的边界线或在不同阶级中应该属于不同阶级的责任之间的边界线并不那么清楚,甚至不太清楚。有时候,在2小时时间内绝对需要3小时的工作。有时候人们只是不打正确的电话。由于这些原因,这方面偶尔会休息,但是它们将妨碍使用Yagni原则,而不是原因。

质量单位测试,我的意思是单位测试而不是集成测试,需要遵守固体的代码。实际上,不一定是100%,但在您的示例中,将两个功能塞入一个类中会使单位测试更加困难,打破单个责任原则,并使新手团队的代码维护更加困难(因为很难理解) 。

使用单元测试(假设良好的代码覆盖范围),您将能够重构功能1安全和安全您不会破坏功能2,但是没有单位测试和同一类中的功能(在示例中只是懒惰)重构充其量是冒险的,充其量是灾难性的。

底线:遵循KIS原理(保持简单),或者遵循知识分子的吻原理(Kis愚蠢)。以每个案例为单位,没有全局答案,但是请始终考虑其他编码者是否需要在将来阅读 /维护代码以及在每种情况下单位测试的好处。

tldr;

扎实的假设,您理解(至少有点),未来对代码的变化WRT SRP。我要说的是对预测能力的乐观。另一方面,Yagni假定大多数情况下您不知道未来的变化方向,这对预测能力是悲观的。

因此,因此,Solid/SRP要求您为代码组建类,以便它具有更改的原因。例如,少量的GUI更改或服务更改。

Yagni说(如果您想强制在这种情况下强制应用它),因为您不知道会发生什么变化,并且如果GUI更改会导致GUI+ServiceCall更改(同样,后端更改会导致GUI+SeviceCall Change) ,只需将所有代码放入单一类。

长答案:

阅读《敏捷软件开发,原理,模式和实践》一书

我对固体/srp提出了简短的摘录:“如果,[...]应用程序不会以导致两个责任在不同时间发生变化的方式变化,则无需将它们分开。的确,将它们分开会闻到不必要的复杂性。

这里有一个科罗利。变化轴仅是发生变化时变化的轴。如果没有症状,那么应用SRP或任何其他原则是不明智的。”

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top