【问题标题】:How to identify that code is over abstracted?如何识别代码过度抽象?
【发布时间】:2011-04-12 13:14:55
【问题描述】:

应该使用哪些措施来识别代码过度抽象且难以理解,以及应该采取哪些措施来减少过度抽象?

【问题讨论】:

    标签: abstraction


    【解决方案1】:

    我完全同意@ArnisLapsa 写的:

    "Simplicity over complexity, complexity over complicatedness"
    

    还有那个

    an abstraction is used to "de-level" those, from complicated to complex
    

    (从复杂到简单)

    另外,正如@MartinHemmings 所说,一个好的抽象是非常主观的,因为我们的想法并不相同。事实上,我们的思维方式会随着时间而改变。所以有些人觉得简单的东西在别人看来可能很复杂,甚至随着经验的增加变得更简单。例如。一元操作对于函数式程序员来说是微不足道的,但对其他人来说可能会严重混淆。同样,具有可变对象相互通信的设计对于某些人来说可能很自然,而对其他人来说则无法跟踪。

    话虽如此,我想添加几个指标。请注意,这适用于代码库中使用的抽象,而不是“范式抽象”,例如一切都是函数或一切都被设计为对象。所以:

    • 对于它所关注的人,抽象在概念上应该比其他替代方案更简单,而无需查看实现。如果您发现考虑所有可能的情况比使用抽象进行推理更简单,那么这种抽象不适合(适合您)
    • 它的实现应该只考虑抽象,而不是它将用于的特定情况。只要抽象实现具有针对特定情况的部分,它就表示“不合适”的抽象。并且增加泛化以应对每个新案例,这是错误的方式(并且往往会落入下一个问题)。
    • 我发现(并且实际上已经爱上)过度抽象的一个非常常见的指标是抽象代表了超出所需的内容,现在。他们应该尽可能地允许做需要做的事情,但仅此而已。例如,假设您正在考虑或已经拥有一个“二维点”抽象,您可以为其定义许多所需的运算符。然后你有另一个需求,它可能真的是一个类似于 2d 的“4d 点”。不要开始使用“Ndimensionnal point”抽象,尤其是认为您以后可能需要它。也许你永远不会有除了 2 和 4d 之外的任何东西(因为它在积压中永远是“一个好主意”),但是会弹出一些要求将 4d 点转换为 2d 点对。这将很难推广到 n 维。因此,可以检查每个抽象以覆盖并且仅覆盖实际需求。在我的例子中,“n 维”的复杂性实际上只用于处理 2 和 4d 的情况(4d 甚至可能不会用那么多)。
    • 最后,从更全局的角度来看,具有许多不相关抽象的代码库表明开发团队倾向于抽象每一个小问题。因此,其中许多可能已经或变得过于抽象了。

    【讨论】:

      【解决方案2】:

      下载 Magento 并查看代码,阅读其中的一些文档并查看其 ERD:http://www.magentocommerce.com/wiki/_media/doc/magento---sample_database_diagram.png?cache=cache

      我不是在开玩笑,这太抽象了.. 试图取悦每个人并覆盖每个基础是一个糟糕的想法,并且会让每个人的生活都变得非常困难。

      【讨论】:

      • 更新:图像似乎消失了。这是他们 ERD 的 EAV 部分:i.stack.imgur.com/sFIJb.png
      • @John_Hunt,我要笑了。几个小时以来,我一直致力于为 Magento 创建一个新的自定义主题——这首先带来了这个线程。你钉了。 Magento 不是皇帝的新装吗?
      【解决方案3】:

      我会给出一个会得到很多反对票的答案!

      如果代码是用 OO 语言编写的……它必然是过度抽象的。语言越纯,问题就越严重。

      应该非常谨慎地使用抽象。如果有疑问,请始终使用具体的数据结构。 (以后可以随时抽象,这比反抽象容易:)

      您必须非常确定您在当前上下文中具有正确的抽象,并且您必须非常确定该概念能够经受住变化的考验。抽象在代码和编码器的性能上都付出了高昂的代价。

      对过度抽象的一些弱测试:如果数据结构是产品类型(C 中的结构)并且程序员已经为每个字段编写了 get 和 set 方法,他们完全没有提供任何真正的抽象,禁用运算符,如C 增量,没有目的,根本不理解结构字段名称已经是产品的抽象表示。复制和叠加界面不是一个好主意。

      对产品案例的一个很好的测试是是否存在需要维护的任何数据不变量。例如,一对表示有理数的整数几乎就足够了,几乎不需要任何抽象,因为所有对都是有效的,除非分母为零。然而,出于性能原因,人们可能会选择保持不变量,通常要求分母大于零,并且分子和分母互质。为了确保不变量,产品表示被封装:由构造函数保护的初始值和受约束以保持不变量的方法。

      要修复代码,我推荐以下步骤:

      1. 记录抽象维护的表示不变量

      2. 如果找不到强不变量,请删除抽象(方法)

      3. 使用直接访问数据的方法重写代码。

      此过程仅适用于低级抽象,即类对小值的抽象。

      更高层次的过度抽象更难处理。理想情况下,您会反复重构代码,检查每个步骤后它是否继续工作。然而,这将是困难的,有时需要进行重大重写,而不是改进。除非抽象离基础太远以至于无法继续维护它,否则它可能不值得。

      【讨论】:

        【解决方案4】:

        “简单大于复杂,复杂大于复杂”

        所以 - 只有当您将复杂性“降低”到复杂性时,抽象某些东西才有好处。这样做的原因可能各不相同:更好的模块化、更好的封装等。

        识别过度抽象是一个先有鸡还是先有蛋的问题。为了减少过度抽象,您需要了解代码行背后的实际原因。这包括理解特定抽象本身的想法(与将其称为缺乏理解的抽象原因相反)。这还不够——您需要知道一个更好、更简单的解决方案来证明它过于抽象。

        如果您正在寻找可以代替您执行此操作的工具 - 不要再看了,只有头脑才能可靠地判断。

        【讨论】:

        • “只有头脑才能可靠地判断”……至少在接下来的 20 年内……;-)
        【解决方案5】:

        我个人会说“理想的抽象级别是什么?”是一个主观问题。

        我不喜欢为每个原子操作使用新行的代码,但我也不喜欢在一行中包含 10 个嵌套操作。

        我喜欢使用递归函数,但我不喜欢仅仅为了递归而使用递归。

        我喜欢泛型,但我不喜欢(嵌套)泛型函数,例如为每种预期的特定类型使用不同的代码...

        这是个人意见和常识的问题。这能回答你的问题吗?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-10-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多