作为一名程序员,我感到自己陷入困境,希望使我的程序尽可能抽象和通用。
这样做通常可以让我重用我的代码,并为可能(或可能不会)再次出现的问题提供更通用的解决方案。
然后我脑海中的声音说,解决问题虚拟化就这么简单!为什么要花比您更多的时间?
我们所有人的确都遇到过这个问题,抽象在您的右肩上,而“解决问题的愚蠢”在左边。
听哪个,多久听一次?您对此有何策略?您应该抽象一切吗?
作为一名程序员,我感到自己陷入困境,希望使我的程序尽可能抽象和通用。
这样做通常可以让我重用我的代码,并为可能(或可能不会)再次出现的问题提供更通用的解决方案。
然后我脑海中的声音说,解决问题虚拟化就这么简单!为什么要花比您更多的时间?
我们所有人的确都遇到过这个问题,抽象在您的右肩上,而“解决问题的愚蠢”在左边。
听哪个,多久听一次?您对此有何策略?您应该抽象一切吗?
Answers:
听哪个,多久听一次?
除非必须,否则请不要抽象。
例如,在Java中,必须使用接口。它们是抽象的。
在Python中,您没有接口,没有Duck Typing,也不需要高耸的抽象级别。所以你就是不。
您对此有何策略?
在您写了三遍之前,请不要抽象。
有一次-很好-有一次。只需解决它并继续前进即可。
两次表明此处可能存在某种模式。或可能没有。可能只是巧合。
三次是模式的开始。现在,它超越了巧合。您现在可以成功抽象。
您应该抽象一切吗?
没有。
的确,除非您有绝对的证据证明您在进行正确的抽象,否则永远不要抽象任何东西。没有“三个重复的规则”,您将以无用的方式编写无用抽象的内容。
这样做通常会让我重用我的代码
这种假设通常是错误的。抽象可能根本没有帮助。这可能做得不好。因此,除非必须,否则请不要这样做。
啊,雅尼 最滥用的编程概念。
使代码通用与执行额外工作之间有区别。您是否应该花费额外的时间使您的代码松耦合并轻松地适应其他事情?绝对。您是否应该花时间实施不必要的功能?否。您是否应该花时间使您的代码与尚未使用的其他代码一起工作?没有。
俗话说“做可能可行的最简单的事情”。问题是人们总是将简单与容易混淆。简单需要工作。但是值得付出努力。
你会落水吗?当然。但是我的经验是,很少有公司比他们现在已经需要更多的“立即完成”的态度。大多数公司需要更多的人,他们会提前思考问题。否则,他们总是会遇到一个自我维持的问题,那就是没有人有时间去做任何事情,每个人都总是在匆忙中,没有人做任何事情。
这样考虑:很有可能再次使用您的代码。但是您不会正确地预测这种方式。因此,使您的代码干净,抽象且松耦合。但是,请勿尝试使您的代码与尚不存在的任何特定功能一起使用。即使您知道将来还会存在。
simple
和之间有很好的区别easy
!
三段论:
一般性是昂贵的。
您正在花别人的钱。
因此,必须将普遍性的代价证明给利益相关者。
问问自己,您是否真的在解决更一般的问题,以便以后节省利益相关者的钱,或者您只是觉得做出不必要的一般性解决方案是一项理智的挑战。
如果确定普遍性是可取的,则应像其他任何特征一样设计和测试它。如果您无法编写测试来证明您已实现的通用性如何解决了规范要求的问题,那么就不要着急了!不符合设计标准且无法测试的功能是任何人都无法依赖的功能。
最后,没有“尽可能通用”的东西。假设您只是为了争辩而使用C#编写软件。您要使每个类都实现一个接口吗?每个类都是抽象基类,每个方法都是抽象方法?这很笼统,但距离“尽可能笼统”不远。那只是允许人们通过子类更改任何方法的实现。如果他们想更改方法的实现而不进行子类化怎么办?您可以使每个方法实际上是委托类型的属性,并带有一个setter,以便人们可以将每个方法更改为其他方法。但是,如果有人想添加更多方法呢?现在,每个对象都必须是可扩展的。
此时,您应该放弃C#并使用JavaScript。但是您还没有达到足够普遍的程度。如果有人想更改成员查找针对此特定对象的工作方式怎么办?也许您应该改为使用Python编写所有内容。
增加通用性通常意味着放弃可预测性,并大量增加测试成本,以确保所实施的通用性实际上能够成功满足实际用户的需求。这些成本是否可以通过对付钱的利益相关者的利益来证明?也许他们是;您可以与利益相关者讨论。我的涉众根本不愿意我放弃静态类型以追求完全不必要和极其昂贵的通用性,但也许您愿意。
需要明确的是,进行概括和实现抽象完全是两件事。
例如,考虑一个复制内存的函数。
该函数是一个抽象,隐藏了如何复制这4个字节。
int copy4Bytes(char * pSrc,char * pDest)
概括而言,可以使此函数复制任意数量的字节。
int copyBytes(char * pSrc,char * pDest,int numBytesToCopy)
抽象使自己可以重用,而泛化只是使抽象在更多情况下有用。
更具体地讲,与您的问题有关,抽象不仅从代码重用的角度来看很有用。通常,如果操作正确,它将使您的代码更具可读性和可维护性。使用上面的示例,如果您浏览代码copyBytes()或一次遍历一次将数据移动一个索引的数组的for循环,那么更容易阅读和理解呢?我认为抽象可以提供一种自我文档,使代码更易于使用。
根据我自己的经验,如果我能给出一个很好的函数名称来准确描述我打算执行的一段代码,那么无论是否我会再次使用它,我都会为其编写一个函数。
此类事物的一个好的通用规则是零,一,无穷大。就是说,如果您需要多次编写内容,则可以假设您将需要更多次并进行概括。这条规则意味着您第一次写东西时就不必理会抽象。
此规则的另一个很好的理由是,第一次编写代码时,您不一定知道要抽象什么,因为您只有一个示例。墨菲定律意味着,如果您第一次编写抽象代码,则第二个示例将具有您没有预料到的差异。
埃里克·利珀特(Eric Lippert)指出了我想在他的文章将来对设计进行校对的三点内容。我认为,如果您遵循它,您将处于良好状态。
第一:过早的普遍性是昂贵的。
第二:在模型中仅表示那些始终在问题域中并且其类关系不变的事物。
第三:使策略远离机制。
“ 抽象”位于您的右肩上,“ 求解困难”位于左侧。
我不同意“愚蠢地解决它”,我认为它可以更“聪明地解决它”。
更聪明的是:
默认选择应该是第二个。除非您可以证明需要世代相传。
仅当您知道将在多个不同的项目/案例中使用通用解决方案时,才应使用通用解决方案。
通常,我发现一般的解决方案最好用作“核心库代码”