多less抽象是太多了?
在一个面向对象的程序中: 多less抽象是太多了? 多less是正确的?
我一直是一个坚强的人。 我理解高级封装和抽象背后的概念,但总是感到本能地认为添加太多会混淆程序。
我总是试图拍摄一些抽象的东西,没有留下任何空的类或层。 而在有疑问的地方,我不会在层次结构中添加新的图层,而是尝试将某些东西放入现有图层中。
但是,最近我遇到了更高度抽象的系统。 系统中所有可能需要在层次结构中进行表示的事物都可以在前面find。 这导致了很多空的层次,最初看起来像糟糕的devise。 然而,第二个想法是,我已经意识到,留下那些空白的层让你有更多的地方在未来没有太多的重构。 它让你有更大的能力在老的基础上添加新的function,而不用做太多的工作来调整旧的function。
这两个风险似乎是你可以得到你需要的图层错误。 在这种情况下,人们仍然需要做大量的重构来扩展代码,并且仍然会有大量从未使用过的图层。 但是,取决于花费多less时间来提出最初的抽象概念,把它搞砸的可能性,以及如果得到正确的结果,以后可以节省的时间 – 可能还是值得去尝试。
我能想到的另一个风险就是过度做这件事的风险,而且从来不需要所有额外的层次。 但是那真的很糟糕? 额外的课程层次是否真的如此昂贵,以至于如果他们从未被使用过,那么这是多么的失败? 这里最大的开销和损失将是时间,这是失去了前面的层数。 但是,大部分时间仍然可以在以后使用抽象代码而不是更底层的代码来保存。
那么什么时候太多? 什么时候空的层和额外的“可能需要”抽象成为矫枉过正? 多less太less? 甜蜜点在哪里?
在你的职业生涯中,你有没有find可靠的经验法则来帮助你判断所需的抽象数量?
那么什么时候太多? 什么时候空的层和额外的“可能需要”抽象成为矫枉过正? 多less太less? 甜蜜点在哪里?
我不认为这些问题有确切的答案。 需要有经验来培养“太多”和“太less”的感觉。 也许一些度量或质量控制工具的使用可以帮助,但很难一概而论。 它主要取决于每种情况。
这里有几个链接可能会激发你寻求答案:
- 你不会需要它
- 使用/重用悖论
- 项目三angular形:好,快,便宜
- 计算机科学中的所有问题都可以通过另一层间接的解决scheme来解决(David Wheeler)
开发就是要在任何软件工程的努力中find各种紧张之间的平衡点。
抽象的要点是从math运算中分解出特定属性的共同属性:
ab + ac => a(b + c)
现在你用两个操作而不是三个操作来做同样的事情。 这个保理使我们的expression更简单。
抽象的典型例子是文件系统。 例如,您希望程序能够写入多种存储设备:笔式驱动器,SD卡,硬盘驱动器等等。
如果我们没有文件系统,则需要实现直接磁盘写入逻辑,笔式写入逻辑和SD卡写入逻辑。 但是所有这些逻辑都有一些共同之处:它们创build文件和目录,所以通过创build一个抽象层并为硬件供应商提供一个接口来完成这些特定的事情,可以将这些常见事物抽象出来。
事物分享共同的财产越多。 抽象的好处可以是:
ab + ac + ad + ae + af
至:
a(b + c + d + e + f)
这将把9个操作减less到5个。
基本上每个好的抽象概念大致上把系统的复杂性减半了。
你总是至less需要两件事情共享一个共同的财产,使抽象有用。 当然,你把一件东西分开,所以看起来像一个抽象,但这并不意味着它是有用的:
10 => 5 * 2
如果您只有一个实体,则无法定义单词“common”。
所以要回答你的问题。 如果你的系统尽可能简单,你就有足够的抽象。
(在我的例子中,加法连接了系统的各个部分,而乘法定义了一个抽象的具体关系。)
多less太less?
当你不断地与“低级”元素合作,你总是觉得你不想这样做。 摘要他们走了。
那么什么时候太多?
当你不能定期地制作一些代码部分的零碎,并且不得不将它们debugging到前一层。 你觉得这个特定的层面没有任何贡献,只是一个障碍。 算了吧。
甜蜜点在哪里?
我喜欢运用实用的方法。 如果你看到一个抽象的需要,并理解它将如何改善你的生活,那就去做吧。 如果你听说应该有一个“正式”的抽象层,但你不清楚为什么,除了研究之外,不要这样做。 如果有人坚持要抽象的东西,但不能清楚地解释将会带来什么,告诉他们走开。
从理论上讲,这只是一个简单的math问题,只需要使用三个(相当简单的)variables:
- S =使用节省
- C =额外抽象的成本
- P =使用的概率
如果S * P> C,那么代码是好的。 如果S * P <C,那就不好了。
然而,纯理论的原因是,你通常无法猜测使用它的可能性或节省的成本。 更糟糕的是,你无法猜测或通常甚至无法衡量其存在的成本。
至less有一些人从中得出了一个结论。 在TDD中,标准的口头禅是“你不会需要它”(YAGNI)。 简而言之,任何不直接有助于符合当前要求的代码被认为是一件坏事。 实质上,他们已经得出结论,使用的可能性是如此之低,以至于包括这样的额外代码是不合理的。
其中一些回到“自下而上”与“自上而下”的发展。 我倾向于将自下而上的开发看作是“图书馆开发” – 也就是说,不是开发一个特定的应用程序,而是真正为应用程序中需要的各种事情开发库。 这个想法是,一个足够好的库,你可以比较容易地开发几乎所有通用types的应用程序。
相当多的还取决于项目的规模。 数十年来一直使用的大型项目比小型项目更为长期的投资更为合理,小型项目被更快速地抛弃和replace。 这在现实生活中也有明显的类比。 你不用担心一次性razor的适合性,光洁度或工艺,你会在一周之内扔掉,就像你在未来几年使用的新车一样。
简而言之,如果代码难以理解,那么抽象就太多了。
现在这并不是说你应该硬编码一切,因为这是最简单的编写和读取的代码。
最简单的testing就是把它放下几天,把它拿起来问问自己,这是否有意义。 一个更好的方法是把它交给别人,看看他们是否能够正面或反面。
现实是,这取决于你如何看待未来。 您想要计划可以预见的更改,而不会创build太多的额外图层。 如果您有一个在系统之间传输数据的devise,请继续并创build一个接口,并使用计划的实现作为默认设置。 例如,你使用FTP来移动文件,但知道明年的标准将是基于消息的(或其他)。
至于devise中的图层,有时候增加的图层使编写更小的类更容易。 如果它意味着具体的类变得简单,那么添加概念层就没有问题。
每个不实际使用的抽象都太多了。 系统越简单,就越容易改变。 抽象层几乎总是使系统更复杂。
OTOH当然可以在没有任何抽象的情况下编写一个复杂的,难以维护的混乱,有时,“标准化”的抽象层可以帮助更好地构build一个系统,比大多数人能够自己做的更好。
参见RFC 1925的条款(6a)
,知道这确实是真的。 通过添加抽象层无法解决的唯一问题是由于抽象层太多而导致的问题。 (特别是每一个抽象都会使整个事情变得更难理解。)