什么是高质量的代码
学习并整理一下个人的理解:什么样的代码是高质量的代码?
编程范式的历史与演变
简单回顾一下编程范式的历史与演变。
顺序编程
在早期编程中,人们采用的编程方式被称为顺序编程(非结构化编程)——程序按照上下文顺序执行指令,GOTO
语句在其中发挥了重要作用,
它可以无条件地跳转到程序的任意部分。
GOTO
语句的滥用导致了“意大利面条式代码”,使得程序变得难以理解和维护。为了克服GOTO
语句带来的代码混乱,20世纪60年代Edsger
Dijkstra等人提出了结构化编程。
结构化编程
结构化编程的核心是控制结构,例如顺序、选择(如if
、switch
)、循环(如for
、while
)等结构,通过这些控制结构来组织代码,尽可能避免GOTO
语句的使用。控制结构提高了代码的可读性和维护性,是现代编程语言的重要基础。
面向过程编程
面向过程编程是基于函数调用的编程范式,通过一系列过程(函数)的调用来组织代码,C语言是其中的典型代表。 面向过程编程的特点是数据与操作分离,这对于较小规模的程序没有问题,但是对于更大型的项目,就会遇到维护困难:难以通过函数管理复杂的数据和状态。
面向对象编程
为了应对面向过程编程在大型项目中的局限性,20世纪70年代提出了面向对象编程, 面向对象可以将数据和操作数据的方法封装到一起,通过类的继承可以实现代码的复用和扩展,允许不同的子类通过相同接口提供不同的方法。 Java是典型的面向对象语言。
函数式编程
上面的这一套发展脉络可以统称为命令式编程,程序通过执行具体命令来完成对应的功能,与之相对的是函数式编程。 命令式编程和函数式编程是编程思想的两个极端:
- 我们可以立足于现实,即计算机可以干什么,冯诺依曼结构的计算机本质上只能机械地执行一条条的指令,于是就有了命令式编程;
- 我们也可以立于目标,即我们希望干什么,最初有一些数理逻辑,数学证明等方面的朴素需求,这对应的是函数式编程,这些思想的产生甚至早于现代计算机的发明。
函数这个词在编程语言中其实有很多含义:
- 在命令式编程中的“函数”称为子过程更合适,它是一段命令的封装;
- 在函数式编程中的“函数”则与数学中的函数和映射更加契合,它代表的是一种对应关系,具有不可变性和无副作用的特点:相同的输入必然得到相同的输出。
函数式编程的优势是代码简洁,易于并行化,缺点是难度远大于命令式编程,学习曲线陡峭,应用很少,代表语言是Lisp和Haskell。
时至今日,主流的编程语言都是属于命令式编程风格的,但是它们在发展过程中也在不断吸收函数式编程的思想,两者并不是泾渭分明的。
代码的评价指标
这部分内容主要参考知乎上的回答:什么样的代码是高质量的代码? - 王争的回答 - 知乎。
简洁性
KISS原则:“Keep It Simple,Stupid”
我们需要通过尽可能简单的代码来完成目标,避免炫技地引入复杂的结构和设计模式。
可读性
我们需要编写提供易读、易理解的代码,让机器理解代码是容易的,困难的是让其他人也容易读懂代码,这方面有很多细节需要考虑:
- 编码是否规范(缩进和空格风格是否一致等)
- 命名是否规范
- 注释是否详尽
- 函数体的长度是否合适
- 函数参数是否过多,过于混乱
- 模块划分是否清晰
- ...
对于代码注释来说:注释并不是越多越好,在较难理解的位置添加说明即可;好的代码本身就是注释!
当然,有时候为了程序的性能提升也可以牺牲一部分代码可读性:代码丑到这个样子,性能一定快到飞起吧!
可复用性
DRY原则:“Don't Repeat Yourself”
我们需要在代码中尽量减少重复片段的编写,复用已有的代码是更好的选择。 如果代码中存在多处重复片段,不仅仅是代码量太大,还意味着改动时必须同步更改所有位置,否则很容易导致问题。
可扩展性
可扩展性表示代码应对未来需求变化的能力,对于具有可扩展性的代码,我们可以在不修改或少量修改原有代码的情况下,通过扩展的方式添加新的功能。 更简单地说,代码自身已经预留了一些功能扩展点,我们可以把新功能代码直接插到扩展点上,而不需要因为要添加一个功能而大动干戈地改动大量的原始代码。
可维护性
对代码的维护主要是修改bug、修改旧代码、添加新代码等。可维护性的直观含义为:
- 对于易维护的代码,我们可以在不破坏原有代码设计、不引入新的bug的情况下,快速地修改或者添加代码。
- 对于不易维护的代码,修改或者添加代码需要冒着极大的引入新bug的风险,我们可能需要花费很长的时间才能完成。
可维护性通常可以由前面的几个指标保证,例如可读性、可复用性、可扩展性等,有时还需要加上可测试性:代码本身是充分解耦的,使我们容易编写单元测试。
程序员的美德
懒惰: 懒惰使得你花大力气去偷懒。它敦促你写出节省体力的程序,同时别人也能利用它们。为此你会写出完善的文档,以免别人问你太多问题。
急躁: 当你发现计算机懒洋洋地不给出结果,会感到愤怒。于是你写出更优秀的代码,能尽快真正的解决问题。至少看上去是这样。
傲慢: 有极度的信心写出别人挑不出毛病的完美程序。
补充
在编程中,不要过早地对代码进行一些自以为是的优化,最重要的是将自己的意图清晰地展示给编译器,编译器会自行进行相关的优化。