《代码整洁之道》-函数

2,799 阅读6分钟

本系列文中会有大量书中内容摘抄,都是个人认为很值得分享的内容。当然,也会有个人感悟,作为学习记录及简单分享。

短小 & 只做一件事

每个函数应该尽可能的短小,这样就保证了每个函数的逻辑不会很复杂,阅读和维护的成本也比较小。
短小的函数会促使每个函数只做一件事,同时只做一件事,也促使函数尽可能短小,所以我把这两点放在了一起。
试想一下,当你尝试阅读一个函数,结果发现它竟然有几百行那么长,这无异于一盆冷水泼下来。然后你硬着头皮尝试理解这段代码,发现里边的逻辑互相纠葛,68行的一个逻辑调用指向了145行,148行的逻辑调用又指向了47行...,最后你读完这段代码,用尽了一天的力气,更甚者这段代码比我描述的更糟糕,最后你放弃了去理解它。
而如果编写这段代码的小伙伴遵循短小及只做一件事的规则,那么这个难以理解的函数估计就会变成十个甚至更多清晰、简洁的函数。

每个函数一个抽象层级

什么是抽象层级?
我理解就是代码逻辑或者完成功能的颗粒度。
比如一个项目的开发过程大致是:

  1. 立项
  2. 需求产出
  3. 编程实现
  4. 发布 它们都是同一级别的流程,从上往下理解起来也比较简单,一下就弄清了整个过程,而如果这个过程中有了其他粒度的过程,理解起来可能就是另一种情况。
  5. 立项
  6. 需求产出
  7. 编程实现
    1. UI确定主色调
    2. 建数据库
    3. 前端技术选型
    4. 建数据库表
    5. UI确定设计风格
    6. 后端技术选型 ...... 可以看到,还没到开发阶段,逻辑已经有点乱了,如果这是一段代码逻辑呢?如果嵌套了更细粒度的流程呢?所以保证每个函数内的逻辑都是一个抽象层级,对于代码的理解和维护是很有必要的。
      函数中混杂不同抽象层级,往往让人迷惑,读者可能无法判断某个表达式是基础概念还是细节。更糟糕的是,这就像破损的窗户,一旦细节与基础概念混杂,更多的细节就会在函数中纠结起来。

向下规则

所谓向下规则就是让代码拥有自顶向下的阅读顺序,让每个函数后面都跟着位于下一抽象层级的函数,这样一来,在查看函数列表时,就能寻抽象层级向下阅读。读者可以自由选择先理解最高抽象层级的主逻辑,还是单独只看其中某一部分的完整逻辑,而且这种选择十分简单,且不用担心迷路。

函数参数

作者讲到最理想的参数数量是0,其次是1,再次是2,应尽量避免3。
参数不易对付,他们带有太多概念性。参数的含义往往不是那么易于理解,读者需要像理解上下文一样理解参数的含义。
从测试的角度看,参数甚至更叫人为难。想想看,要编写能确保参数的各种组合运行正常的测试用例,是多么困难的事。如果没有参数,就是小菜一碟。如果只有一个参数也不太困难。有两个参数,问题就麻烦多了。如果参数多于两个,测试覆盖所有可能值的组合简直令人生畏。
输出参数比输入参数还要难以理解。读函数时,我们惯于认为信息通过参数输入函数,通过返回值从函数中输出,我们不太期望信息通过参数输出。所以输出参数往往让人苦思之后才恍然大悟。

无副作用

副作用是一种谎言,函数承诺只做一件事,但还是会做其他被藏起来的事。
比如在登录的函数中包裹设置全局变量的逻辑或者页面跳转的逻辑。
再比如在查询用户是否登录的函数中,包裹判断用户没有登录,就清空用户信息的逻辑。
这对于函数的调用者来说是有风险的,因为他很可能不知道该函数的副作用。同时这也违反了函数短小和只做一件事的规则,如果非要这么做,记得把函数名称重命名为 loginAndSetUserInfo checkLoginAndClearUserInfo,但是尽量不要这么做。

别重复自己

如果一个方法或者一段逻辑在超过一处调用,那么他就需要被抽离出来,这样不但会减少代码体积,更重要的是增加了代码的可维护性。当这段逻辑需要修改时,我们只需要修改抽离出来的函数就可以,而不必修改更多的位置,也就避免了忘记修改某处的风险。

如何写出这样的函数

写代码和写别的东西很像。在写论文或文章时,你先想什么就写什么,然后再打磨它。初稿也许粗陋无序,你可以对其斟酌推敲,直至达到你心目中的样子。
我写函数时,一开始都冗长而复杂,有太多缩进和嵌套循环,过长的参数列表。名称是随意起的,也会有重复的代码,不过我会配上一套单元测试覆盖每行丑陋的代码。
然后我打磨这些代码,分解函数,修改名称,消除重复。我缩短和重新安置方法。有时我还拆解类,同时保持测试通过。
最后遵循本章列出的规则,我组装好这些函数。我并不从一开始就按照规则写函数,我想没人做得到。

这里作者讲了自己是如何编写代码的,其实整个过程就是重构的理念,先实现功能,并用单元测试保证功能的稳定性。然后对代码进行重构。一开始就按照本章的规则些函数,或者说直接写出简洁的代码是不现实的,好代码都是不断重构的产物。

总结

本章内容对于如何组织代码逻辑以及如何拆分函数进行了系统的介绍,提出了一系列编写函数应该遵循的规则,我认为十分有价值。
作者在最后的小结中讲到:大师级程序员,把系统当作故事来讲,而不是当作程序来写。他们使用选定编程语言提供的工具构建一种更为丰富且更具表达力的语言,用来讲那个故事。遵循本章中关于函数的规则,函数就会被很好地归置,然后将编写的函数干净利落地拼装到一起,形成一种精确而清晰的语言,帮助你讲故事。
我距离讲故事还有很长的一段路要走,所以从现在开始,编写好每一个函数吧!💪