LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

编程规范准则

2021/10/28

一个庞大系统应该由许多短小的结构组成,我们在让代码能工作的前提下还应该考虑代码的条理性

因此我们需要一些编程规范来帮助我们编写和重构代码。


1.命名应该是有意义的(我认为最重要的)

我认为有关明命名的准则是最重要的,先不谈代码架构问题,倘若命名是没有意义的甚至是重复的

在工作和交流中就会起到混淆视听降低可读性的严重后果。

应该花时间为我们的函数,变量,类,参数取个好名字。

名字应该名副其实的表达这个数据的用途。类名,变量名使用名词短语,而函数名则尽量使用动词短语。

命名时还应当注意:区分应该有意义(避免使用a1,a2,a3);避免误导(不使用关键词例如list,否则会以为这个数据是list类型的)

每个词对应一个信息(用来表示两数相加的函数和将某数据放入容器的方法不能都叫add)


2.注释并不是尽然好的

这表示简洁的易读的代码的重要性,代码并不是能跑得动就行的,花时间重构代码很有价值

注释的用法是弥补我们在尝试表达代码意图时所遭遇的失败

应尽量用可读性更好的代码来表达而非使用注释

值得写的好注释有:代码规范中所要求的法律信息;将某些晦涩的参数或返回值的意图解释清楚(如果可以的话最好还是用函数名来表达)


3.函数应该尽量简洁短小

在初步编写时没人能一次性写出好的函数,但我们可以慢慢改进重构精简它们。

每个函数都应该短小,且一目了然,每个函数都只做一件事,并且每个函数都将你带到下个函数。

确保函数只做一件事,得确保函数内的语句都是同一抽象层级的。

函数的参数应该尽可能的少,多使用无参,或者单参数函数,少用双参数函数,避免用三个及以上的参数,这样会大大降低可读性。

可以通过将参数封装为类来减少函数的参数数量。

尽可能避免在不同函数中重用相同的代码段


4.将数据进行良好的封装

封装是面向对象设计的三大特性之一

从编程开始时,老师就教导我们尽量将数据设为私有private,将必要的函数和数据再设为公开public。

一方面能保护一些数据,只暴露所需的接口,接口之内皆为黑盒。

一方面能减少模块间的相互干扰,相互依赖,能极大减少代码的耦合度。

对于面向对象编程而言,代码难以添加新函数,因为可能需要修改所有的类,与此相对却更方便添加新的数据类型。

我认为在如今的编程环境中,这种情况可能更居多,所以面向对象是很出众的。


5.类应该短小精炼

我认为若有能力将上述的问题处理好,说明已经有初步的重构代码的能力了

编写一个短小精悍的类虽然同样很重要但此时就是个小case啦。

首先我们类的命名应该是精准的,确定性了指明这个类该做什么事情

我们根据类的职责来确定类的成员和类的长度。

其次类应该具有尽量强的内聚性,应该只具有少量的实体,类中方法尽量围绕这个实体做数据操作。

内聚性高就表明这个类能自成一体,类中实体和函数能相互依赖,结合成一个逻辑实体。


6.多使用异常处理机制来进行错误处理

曾经限于语言不支持异常,先辈们采用返回错误码的方式来汇报错误。

异常处理机制就可以让我们捕获并处理这些错误,然后我们可以让程序沿着一条不会出错的路径继续执行。

它的优越之处在于抛出异常不会影响代码的逻辑性,也不必催促调用者立即检查错误。

一般我们先编写强行抛出异常的语句,以便来往处理器中添加行为。

其次我们根据我们的期待往try语句块中再填入我们所需测试的语句。

编写异常语句时,可以将错误处理语句隔离看待,独立于主要逻辑之外

这样我们能单独处理它并极大提升代码的可维护性。

其中要注意的是,我们应该尽量减少返回值为null,而改为返回特例对象和抛出异常。


7.设计架构应一步步迭代

我们不该在代码能工作后就止步于此。

优秀的架构意味着我们做出一个改动时,整个程序会期待它而不是畏惧它的副作用。

由于良好的组织性,后续的人处理代码时不必花大量时间修改和理解代码。

良好的测试来为我们消除破坏代码的恐惧,接着我们将进行代码重构来迭进我们的代码。

重构过程中我们遵循:运行所有测试,提升内聚性,降低耦合度,减少重复,切分关注面,

模块化系统性关注面,缩小函数尺寸和减少类和函数数量,保证表达力。(按重要性排序)

表达力,函数和类的相关规范在上文中提到过,下文则会介绍测试规范和重构思路。


8.为代码编写测试

检查自己是否有一套可靠的测试机制,同样是进行代码重构的前提。

编写测试是为了确保我们的代码能如愿以偿的工作,同时测试的确可以捕捉到大多数bug。

TDD三原则:

在编写不能通过的单元测试前,不可编写生产代码;

只可编写刚好无法通过的单元测试,不能编译也算不通过;

只可编写刚好足以通过当前失败测试的生产代码;

我们用较大的比例用测试覆盖代码,就能保证代码的可拓展,可维护,可复用。

在编写测试代码时同样要确保测试代码的整洁(即可读性)

确保我们的每段测试代码只测试一个功能,而不是一段超长的测试代码将所有功能纳入其中

测试代码同样也是代码,我们一样遵守上文提到的那些准则就行


9. 代码重构的思路

就如上文所说到的,代码不可能第一次编写时就是简洁且完整的,我们可以先遵从一些编程时的准则(命名,注释)

在完成目标后我们进行代码的重构。因此完成重构的前提当然是我们有一段能完成职责的代码。

重构并不是将程序完全重新写一遍,而是在之前同样的算法和机制上将我们的代码变得具有逻辑性。

因此我们首先需要一个用例来验证程序的功能,随后我们进行我们所需的改动。

每当一处小改动发生时,我们就执行这个用例确保程序的行为是否发生了变化。

代码重构的几个方向:

将大函数按照模块和行为分为几个小函数

将函数变为内联函数;

将临时变量(有着复杂表达式赋值并且多次使用的)改为使用查询函数的返回值来取代;

若临时变量赋值的意义不同则创建新的临时变量并使用不同名称;

使用临时值而避免对函数参数进行直接修改(会丧失参数的原始值)


10.格式

将格式放在最后,并非格式不重要,而是在各种规范和自动化工具的普及下

拥有一个整洁的代码格式并不是困难的事,但这关乎到团队的沟通,依然很重要。

我们应该制定一个简单的规则,并在整个项目中贯彻它。

我们应该限制每个源文件的大小(行数)在同一个数量级的规格上,在源文件的顶部给出最高层次的抽象(概念和算法)

随后在下文中将细节依次展开,直至源文件最底层的函数和细节;

关系密切且放在同一源文件的数据间隔应该尽可能小,避免读者在源文件中跳来跳去的阅读;

变量声明应该尽可能接近使用位置,循环中的控制变量尽可能在循环语句中声明;

一个函数若调用另一个函数则它俩应该尽可能相近;

过程中记得用空行来区分各个函数和模块,使得代码块更具有条理性和可读性。

其他有关每行长度,缩进,对齐,字符间的空格的相关内容则不赘述,

因为借助于先进的IDE和自动化工具,这些规范早已刻在DNA里了。


相关文献:《Clean Code》《Game Programming Pattern》《Refactoring》