学习并整理一下个人的理解:什么样的代码是高质量的代码?

编程范式的历史与演变

简单回顾一下编程范式的历史与演变。

顺序编程

在早期编程中,人们采用的编程方式被称为顺序编程(非结构化编程)——程序按照上下文顺序执行指令,GOTO语句在其中发挥了重要作用, 它可以无条件地跳转到程序的任意部分。

GOTO语句的滥用导致了“意大利面条式代码”,使得程序变得难以理解和维护。为了克服GOTO语句带来的代码混乱,20世纪60年代Edsger Dijkstra等人提出了结构化编程。

结构化编程

结构化编程的核心是控制结构,例如顺序、选择(如ifswitch)、循环(如forwhile)等结构,通过这些控制结构来组织代码,尽可能避免GOTO语句的使用。控制结构提高了代码的可读性和维护性,是现代编程语言的重要基础。

面向过程编程

面向过程编程是基于函数调用的编程范式,通过一系列过程(函数)的调用来组织代码,C语言是其中的典型代表。 面向过程编程的特点是数据与操作分离,这对于较小规模的程序没有问题,但是对于更大型的项目,就会遇到维护困难:难以通过函数管理复杂的数据和状态。

面向对象编程

为了应对面向过程编程在大型项目中的局限性,20世纪70年代提出了面向对象编程, 面向对象可以将数据和操作数据的方法封装到一起,通过类的继承可以实现代码的复用和扩展,允许不同的子类通过相同接口提供不同的方法。 Java是典型的面向对象语言。

函数式编程

上面的这一套发展脉络可以统称为命令式编程,程序通过执行具体命令来完成对应的功能,与之相对的是函数式编程。 命令式编程和函数式编程是编程思想的两个极端:

  • 我们可以立足于现实,即计算机可以干什么,冯诺依曼结构的计算机本质上只能机械地执行一条条的指令,于是就有了命令式编程;
  • 我们也可以立于目标,即我们希望干什么,最初有一些数理逻辑,数学证明等方面的朴素需求,这对应的是函数式编程,这些思想的产生甚至早于现代计算机的发明。

函数这个词在编程语言中其实有很多含义:

  • 在命令式编程中的“函数”称为子过程更合适,它是一段命令的封装;
  • 在函数式编程中的“函数”则与数学中的函数和映射更加契合,它代表的是一种对应关系,具有不可变性和无副作用的特点:相同的输入必然得到相同的输出。

函数式编程的优势是代码简洁,易于并行化,缺点是难度远大于命令式编程,学习曲线陡峭,应用很少,代表语言是Lisp和Haskell。

时至今日,主流的编程语言都是属于命令式编程风格的,但是它们在发展过程中也在不断吸收函数式编程的思想,两者并不是泾渭分明的。

代码的评价指标

这部分内容主要参考知乎上的回答:什么样的代码是高质量的代码?

简洁性

KISS原则:“Keep It Simple,Stupid”

我们需要通过尽可能简单的代码来完成目标,避免炫技地引入复杂的结构和设计模式。

可读性

我们需要编写提供易读、易理解的代码,让机器理解代码是容易的,困难的是让其他人也容易读懂代码,这方面有很多细节需要考虑:

  • 编码是否规范(缩进和空格风格是否一致等)
  • 命名是否规范
  • 注释是否详尽
  • 函数体的长度是否合适
  • 函数参数是否过多,过于混乱
  • 模块划分是否清晰
  • ...

对于代码注释来说:注释并不是越多越好,在较难理解的位置添加说明即可;好的代码本身就是注释!

可复用性

DRY原则:“Don't Repeat Yourself”

我们需要在代码中尽量减少重复片段的编写,复用已有的代码是更好的选择。 如果代码中存在多处重复片段,不仅仅是代码量太大,还意味着改动时必须同步更改所有位置,否则很容易导致问题。

可扩展性

可扩展性表示代码应对未来需求变化的能力,对于具有可扩展性的代码,我们可以在不修改或少量修改原有代码的情况下,通过扩展的方式添加新的功能。 更简单地说,代码自身已经预留了一些功能扩展点,我们可以把新功能代码直接插到扩展点上,而不需要因为要添加一个功能而大动干戈地改动大量的原始代码。

可维护性

对代码的维护主要是修改bug、修改旧代码、添加新代码等。可维护性的直观含义为:

  • 对于易维护的代码,我们可以在不破坏原有代码设计、不引入新的bug的情况下,快速地修改或者添加代码。
  • 对于不易维护的代码,修改或者添加代码需要冒着极大的引入新bug的风险,我们可能需要花费很长的时间才能完成。

可维护性通常可以由前面的几个指标保证,例如可读性、可复用性、可扩展性等,有时还需要加上可测试性:代码本身是充分解耦的,使我们容易编写单元测试。

程序员的美德

参考知乎上的一个回答

  • 懒惰: 懒惰使得你花大力气去偷懒。它敦促你写出节省体力的程序,同时别人也能利用它们。为此你会写出完善的文档,以免别人问你太多问题。

  • 急躁: 当你发现计算机懒洋洋地不给出结果,会感到愤怒。于是你写出更优秀的代码,能尽快真正的解决问题。至少看上去是这样。

  • 傲慢: 有极度的信心写出别人挑不出毛病的完美程序。