C语言怎么样勾勒来优雅的函数(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. 总结

假设您照以上所有的规则,你的函数会变换得体量短小、良好命名、并且有所出色的团伙结构。但是永远不要遗忘这不是目的而是手段,你的最终目的是让全体系统更加完善。

自之博客