Oracle哪些写出优雅的函数(Clean Code读书笔记之二)

函数是代码组合的中坚单位,高级编程语言的升华从结构化到面向对象,再到近日大有要复兴之势的函数式编程,函数都是组成那座高楼不可或缺的着力组成部分,它的机要不问可见。本文将基于「clean
code」第三章的始末,几乎捋五回怎样写出优雅的函数。

其三章讲了在写函数时应当小心的业务,小编首先拿一个开源的测试工具(Fitnesse)来举了一个事例,来表明好的函数该是什么样子。原则上实在和上一篇中讲到的命名的片段标准化很一般,就是一个名字只要可以自解释的,当然这一章还会讲到很多新的事物,这里拿这么些函数作为一个引子。

//代码2-1
public static String renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite)throws Exception{
    boolean isTestPage = pageData.hasAttribute("Test");
    if(isTestPage){
        WikiPage testPage = pageData.getWikiPage();
        StringBuffer newPageContent = new StringBuffer();
        includeSetupPages(test Page, newPageContent, isSuite);
        newPageContent.append(pageData.getContent());
    }
}

从上述代码可以看出上一章中涉嫌的一对东西,不要惧怕你的函数或者变量名定义的很长,在编译器已经长足发展的明日,对于很长的函数命名的拍卖已经不会变成语言仍旧性质的瓶颈了;然后所有函数就像在描述做一件工作的步骤,每一步我们都能看懂那是在干些什么业务,以上那些事例很好的来得了一个「好函数」应该的楷模。

自家已经听过一个Oracle的工程师讲到他们的编码须要,包含一个函数内部的if无法跨越八个,所有的函数应该界定在10行以内等,与那几个事例的思辨都是不谋而合。

上边起头列举小编对一个写好一个函数应该根据的规则的叙述:

1. 小!!!

The first rule of functions is that they should be small. The second
rule of functions is that they should be smaller than that.

小的函数不自然好,可是可以毫无疑问的是太长的函数一定是在某种程度上很烂的。

小编谈到她向来以来的视角是函数不应当抢先一个显示器能显得的品位,当然现在的显示器越来越大,那么一旦非要使用一个数字来说,他觉得一行不该当先150个字符(我觉得实际最好还维持在80或120个字符以内),函数的行数最好不用跨越100行,假诺能简单20行最好不过了。

小编在此地讲述了她和满世界知名的Kent Beck的一段讲话来比喻,Kent
Beck说一个函数最多应该不要跨越4行。那么些的确有点恐怖,我觉着能说了算在20行以内就早已很厉害了。函数要设计的小并不是目的,而是经过写出来小函数来达到让程序的阅读者可以很快的看懂那段程序,而且更短的主次往往代表更少的bug。接下来会有部分标准,如若您可以明白它们并尽可能遵守,会卓有作用的帮忙你写出小而高质量的代码。

  • 代码块和缩进
    小编在这一节讲了八个业务,代码块(就是if或者else块)的始末最多不超越一行,那样这一个在块中的函数往往能够有一个自解释的名字;一个函数的缩进等级最多无法当先2级。这四个要求在我看来都是无与伦比严苛了,一般人都做不到,然则朝着那方面努力总是好的。

2. 只做一件事

一个好的函数应该只做一件事,那是我们平时见到的传教,那么怎么才能说一个函数是「只做了一家事」呢,假如一个函数做了3件事,那而3件事又可以说是其它一件事的3个步骤,那么这些算不算是「只做一件事」呢?

作者认为那种景色是属于「只做了一件事」的,可是这几个函数应该只包蕴那3个步骤,而不包含3个步骤的具体落实,也就是说,即使这一个函数里富含了某一个手续的现实性完成,那么那些函数就不是「只做一件事」。

换言之,要是一个函数function1里的多少个语句可以被extract出来改成一个新的函数function2,那么function1就从未有过完毕「只做一件事啊」的标准。

  • 函数里的小节
    稍微人写代码喜欢在一个函数里选用分化的代码小节(比如第三节定义变量,首节实例化那个变量,第四节再对这个变量举办一些操作),作者认为那严重违背了「只做一件事」原则,是不行倒霉的习惯。

3. 每个函数只含有同一个层级的用空想来安慰自己

本条条件是相比好领悟的,比如代码2-1中的getWikiPage()函数的中间贯彻,和renderPageWithSetupsAndTeardowns()里的几个函数调用就不在一个虚无层级上;或者对newPageContent.append()的函数调用鲜明就与其余函数调用不是在同一抽象层级。

  • 自上而下的翻阅代码:层层向下
    小编认为好的代码读起来应当像是记叙文,自上而下的讲课完结一件业务的手续。换种说法就是阅读一个顺序就好像在阅读一堆的TO(英文单词to,为了……)段落:为了做某件事情1,大家去做了作业2,为了工作情2,大家去做了业务3。与此同时小编又说认为那个规格遵守起来格外难,不过这是一个奋力的矛头,努力去读书这些条件会帮忙您写出来更小的,只蕴涵同一流抽象的函数。

4. Switch语句

在coding进程中很难防止要用到switch语句的事态,在这种情况下就很难去维持以上讲到的有的平整,小编的提议是对此Switch语句,应该将它包裹起来,使用多态(具体讲可能就是概念抽象工厂方法,然后switch能够被放在抽象工厂方法的完成类里,同时让switch对于它的调用者完全透明)为这些函数的实在使用者提供劳动。

5. 行使自解释(descriptive)的名字

函数的名字要力所能及描述它自身的做事内容,不要害怕函数名会变得很长,一个长的自解释的名字比一个短的不明所以的名字要好得多。

再者在名字的选项上要前后一致,那么些规格同前一篇讲命名中的一些条条框框如出一辙。

6. 函数参数

最精美的函数应该没有参数的,其次比较好的是唯有一个参数的、唯有八个的,包蕴八个参数的函数应该尽量被防止选择,七个以上的参数的函数不应有留存。

饱含参数的函数鲜明已经包含了一个和函数内容不在同一个层级上的悬空(参数本身),还有从测试的观点看,参数的存在也增强了写测试用例的难度。

奇迹有些参数还被看作出口用途,这种情景应当尽量幸免。

「Clean
Code」整本书都是基于Java和其余类似的高等语言为底蕴的,不过在一部分看法差异的语言中,含有八个参数的函数在领略上是截然小难点的,不过它们或者在此外位置(比如编写测试用例)也会存在丰硕多彩的标题。

  • 单个参数
    有二种相比广泛的场景适合选拔单个参数的函数,一种是「函数是要对此参数问一个标题,并赢得一个答案」(比如
    boolean
    fileExists(“MyFile”),另一种是「此函数是要对此函数对此参数举办一个操作,把它变成别的一中东西,并将它回到」(InputStream
    fileOpen(“MyFile”))。

别的还有一种境况比较不那么周边,可是也不行实用的单个参数函数格局,event。那种情状下函数接受一个参数event,可是从未重临值,函数会根据这几个event对象来进行一些任何操作。

动用那几个样式时也还要要运用一个正好的名字来清晰的叙述函数的用处,从而让代码阅读者可以清楚火速地询问函数的目标。

  • Flag参数
    Flag参数是丑陋的,不应当被选取;往往一个暗含Flag参数的函数能够被诠释或简捷的选拔if
    else代码块就足以直达相同的出力。

  • 多少个参数
    小编认为几个参数的函数是麻烦精晓的,唯一可能比较适度的场合是,那四个参数本身就是「一个独立对象的五个不变的零件」,比如Point(x,
    y),x轴坐标和y轴坐标共同组成了平面坐标系中的一个点。
    只是,小编认为五个参数的函数并不是残忍了,所有人都不可防止的在骨子里编程中使用它们,可是毫无疑问要精晓它们是会带来一些不良后果的,最好是可以把这么些函数都转化成单个参数的函数。

  • 两个参数
    多少个参数的函数万分不便领会甚至不时会被误解,所以在应用前最好三思再三思。

  • 参数对象
    当一个函数须求2个或者3个参数是,往往可以将她们一切仍然局地封装成一个对象,从而达到裁减参数数量,使函数尤其便于精晓和有限支撑的目标。

  • 参数列表
    有时一个函数会接受一个变长的参数列表,那种景象下实际它们得以当做一个List结果的参数对象,所以可以被当作一个单个参数的函数,作者是相比推荐这种办法的。

      public String format(String format, Object...args)
    
  • 动词和关键词
    动用一个好的函数名可以清楚的解说函数和参数的目标。对于单个参数的函数,函数和参数应该是一个「动词 +
    名词」的咬合。

再有一种「关键词」的方式来作为函数的名字,比如选用assertEquals(expected,
actural),而不是assertExpectedEqualsActual(expected,
actural),那样就不必要读者必须精晓参数的次第,从而下降了阅读此代码的难度。

7. 决不有副效率

函数的副效能就像是谎言一样,一个函数声称它要做一件事,可是还要它又做了其它一件「隐藏的」事,有时候它会修改自己的类中的属性,有时候它会修改传进来的参数或者其余全局变量,不管哪一种境况,这都是不好的。

  • 出口参数
    在「面向对象编程」出现以前(比如C语言),有时候必须使用一个参数(常常是一个指南针)来作为函数的输出,然而在「OOP」中,「this」指针往往隐喻了它是用来作为出口指针的效劳,那么输出参数应该尽量的避免使用,假诺有那样的必要,修改「this」中的属性往往是更好的选用。

8. 推行和摸索分离

一个函数要不履行了某个行为(比如改变了一个对象的景况),要不答应了某个难点(比如重回某个对象的某些音信),可是不应有而且做如此两件事。

9. 使用Exception,不要选用重回错误码

归来错误码轻微地违反了上一个条条框框,小编提议不用使用重返错误码而选拔抛出Exception的不二法门。那样的不二法门往往会时代码更短而鲜明易读。

  • 提取try/catch代码块
    作者提议在应用try代码块时要将try中的代码提取,使得所有try/catch代码块是一个完全的错误处理代码块,而不分包具体的任何操作逻辑,那就适合了「只做一件事」的标准化。

  • 错误处理是「一件事」
    小编指出做错误处理的函数,应该只做错误处理那「一件事」,也就是说一个暗含try关键词的错误处理函数应该是以try那些单词为开首的。如代码2-2所示:

      代码2-2
      public void delete(Page page){
          try{
              deletePageAndAllReferences(page).
          }catch(Exception e){
              logError(e);
          }
      }
    
  • 凭借磁铁
    再次回到错误码的艺术还有一个标题是,往往在那种情景下,所有的内需错误处理的地点都会须要依靠那些类依旧文件,那样的被大规模依赖的类叫做「信赖磁铁」

依傍磁铁在一般的平凡支付中很难幸免,而且自己认为那也不是一个急需强力幸免的规范。

10. 不要再度自己(Don’t repeat yourself)

大家在写代码时反复会将同一一个算法、或者一段处理逻辑、甚至一段同样的代码重复的出现在五个地点,甚至是同一个源文件的不等地点。那频仍是过多代码品质难点的源流,也有无数编程原则和特级实践都是为着控制或者消灭重复而发出的。

  • 结构化编程
    小编认为一旦能确保保持函数「很小」,那么很多难题就足以缓解了,那么结构化编程的一对规则(比如一个函数唯有一个输入和一个出口)则不需求被遵从了。

11. 你怎么才能写出那般的函数

程序员写代码跟其余项目的编著一样,是一个不住创新的历程。小编认为写出好的函数几乎是这样多少个步骤

  • 先直接把想法写成代码,它们可能是很长同时复杂的,可能违反了以上很多条条框框,同时也会有一套单元测试来cover所有的代码用来做回归测试,做为将来对代码重构的根底
  • 下一场先导对代码进行修改,分离函数,修改名称,消灭重复,同时要维持测试用例完全通过。
  • 最终动用上述所有条条框框来对函数进行地毯式的末梢修改。

12. 总结

借使您根据以上所有的条条框框,你的函数会变体面量短小、卓越命名、并且有所突出的集体结构。但是永远不要忘记那不是目标而是手段,你的末梢目标是让任何系统越来越周全。

自己的博客

相关文章