如何编写高质量和可维护的代码

我们怎么做才能既不需要写很多注释,又能保证代码易于理解呢?

其中一个主要的方法就是让代码自文档化。其优势在于,既不用写注释,又能使得代码易于维护。

下面就是三种使得代码自文档化的基本方法:

  • 命名:利用名字来解释变量、函数等的目的。
  • 封装函数:将一些特定功能的代码封装成一个函数以明确目的。
  • 引入变量:将表达式插入至专用变量。

这可能看上去很简单,但在实际操作过程中会让人觉得有点棘手。首先你得明白哪些地方有问题以及哪些地方适用这些方法。

除了上面三个以外,还有一些应用范围也比较广的方法:

  • 类和模块接口:将类和模块中的函数暴露出来,让代码更加清晰。
  • 代码分组:用组来区分不同的代码片段。

接下来我们将具体讲一讲如何在实际应用中运用上面这5个方法。

1.命名

先看几个如何运用命名的方法来阐述代码使得其自文档化的例子。

重命名函数

给函数命名通常都不会太难,但是这里面也有一些需要遵循的简单规则:

避免使用含糊的字眼,例如“handle”或“manage”——handleLinks、manageObjects。

使用主动动词——cutGrass、sendFile,以表示函数主动执行。

指定返回值类型——getMagicBullet、READFILE。强类型的语言也可以用类型标识符来表明函数的返回值类型。

重命名变量

指定单位——如果里面有数值参数,那可以加上其单位。例如,用widthPx来取代width以指定宽度的单位是像素。

不要使用快捷键——a和b都不能作为参数名。

封装函数

关于这一点,我们将举几个如何把代码封装成函数的例子。此外,这么做还有一个好处是,可以避免重复代码。

将代码封装成函数

这是最基本的:将代码封装成函数以明确其目的。

猜猜下面这行代码是干什么的:

var width = (value - 0.5) * 16;

好像不是很清楚,当然有注释就一清二楚了,但是我们完全可以封装成函数以实现自文档化……

var width = emToPixels(value);function emToPixels(ems) {return (ems - 0.5) * 16;
}

唯一改变的是计算过程被转移到了一个函数里。该函数名明确地表达了它要做什么,这样一来就不必写注释了。而且,如果有需要后面还可以直接调用此函数,一举两得,减少了重复劳动。

用函数表示条件表达式

If语句如果包含多个运算对象,不写注释的话理解起来就比较难。

if(!el.offsetWidth || !el.offsetHeight) {
}

知道上面这代码的目的不?

function isVisible(el) {return el.offsetWidth && el.offsetHeight;
}if(!isVisible(el)) {
}

其实,只要将这些代码封装到一个函数里,那就很容易理解了。

引入变量

最后再讲讲如何引入变量。相较于上面两个方法,这个可能没那么有用,但是无论如何,知道比不知道好。

用变量替换表达式

还是上面这个if语句的例子:

if(!el.offsetWidth || !el.offsetHeight) {
}

这次我们不封装函数,改用引入变量:

var isVisible = el.offsetWidth && el.offsetHeight;
if(!isVisible) {
}

用变量替换程式

我们也可以用来清楚说明复杂程式:

return a * b + (c / d);
var divisor = c / d;
var multiplier = a * b;
return multiplier + divisor;

类和模块接口

类和模块的接口——也是面向公共的方法和属性——有点像说明如何使用的文档。

看个例子:

class Box {public function setState(state) {this.state = state;}public function getState() {return this.state;}
}

这个类也可以包含其他代码。我特意举这个例子是想说明公共接口如何自文档化。

你能说出这个类是如何被调用的吗?很显然,这并不明显。

这两个函数都应该换个合理的名字以表述它们的目的。但即便做到这一点,我们还是不怎么清楚如何使用。然后就需要的代码或者翻阅文档。

但是如果我们这样改一下呢……

class Box {public function open() {this.state = open;}public function close() {this.state = closed;}public function isOpen() {return this.state == open;}
}

明白多了,是吧?请注意,我们只是改动了公共接口,其内部表达与原先的this.state状态相同。

这么一改,我们一眼看去就知道怎么用。原先那个函数名虽然不错,但是依然让我们觉得云里雾里,还不如后者直截了当。像这样做一个小小的改动产生大大的影响,何乐而不为呢?

代码分组

用组来区分不同的代码片段也是自文档化的一种形式。

例如,像这篇文章中说的那样,我们应该尽可能将变量定义在靠近使用它的地方,并且尽可能将变量分门别类。

这也可以用来指定不同代码组之间的关系,这样更加方便其他人知道他们还需要了解哪些代码组。

看看下面的例子:

var foo = 1;blah()
xyz();bar(foo);
baz(1337);
quux(foo);

var foo = 1;
bar(foo);
quux(foo);blah()
xyz();baz(1337);

将foo的所有使用组合放在一起,一眼望去就能知道各种关系。

但是有时候我们不得不在中间调用一些其他函数。所以如果可以那就尽量使用代码分组,如果不可以,那就不要强求。

其他建议

  • 不要自作聪明。看看下面这两个等价的表达式:
imTricky && doMagic();if(imTricky) {doMagic();
}

很显然后者更好。

  • 命名常量:如果代码里面有一些特殊值,那最好给它们命名。var PURPOSE_OF_LIFE = 42;
  • 制定规则:最好遵循相同的命名规则。这样阅读的人就能在参考其他代码的基础上正确猜测出各种事物的含义。

结论

要想能使代码自文档化提高其可维护性是一个非常漫长的历程。每个注释都需要花心力去写,所以尽量精简方可省时省力。

然而,自文档化的代码永远取代不了文档和注释。因为代码在表述上总有其限制,所以写好注释亦是不可或缺的。此外,API文档于类库而言非常重要,因为光靠阅读代码是理解不了的,除非这个类库真的是小得不能再小。

如何编写高质量和可维护的代码相关推荐

  1. 读《编写高质量iOS与OS X代码的52个有效方法》

    又看了一遍<编写高质量iOS与OS X代码的52个有效方法>这本书,做一个简单的总结,其中runtime和GCD那些的不是太详细,要想很详细估计写的东西比篇文字都多,但恰巧又是iOS的重点 ...

  2. [读书笔记]读《Effective Objective-C 2.0编写高质量iOS与OS X代码的52个有效方法》(一)...

    第一条:了解Objective-C 语言的起源 Objective-C为C语言添加了面向对象特性,是其超集.Objective-C使用动态绑定的消息结构,也就是说,在运行时才会检查对象类型.接收一条消 ...

  3. 《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法》笔记

    2019独角兽企业重金招聘Python工程师标准>>> 这本书很早有了解过,评价都不错,但最近才终于把这本书看完,整本书介绍了很多个提高Objective-C的方法,都是平时用得很多 ...

  4. 【Python】使用31条规则编写高质量且美丽的Python代码

    Raymond Hettinger在pycon US 2013 视频,幻灯片上的讲话. 代码示例和直接引用都来自Raymond的演讲.我在这里复制它们是为了我自己的启发和希望别人会发现它们像我一样方便 ...

  5. Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法笔记-协议与分类...

    23.通过委托与数据源协议进行对象间通信 如果要在委托对象上调用可选方法,那么必须提前使用类型信息查询方法判断这个委托对象能否响应相关选择子. if ( [_delegate respondsToSe ...

  6. 蛙蛙推荐:如何编写高质量的python程序

    蛙蛙推荐:如何编写高质量的python程序 蛙蛙推荐:如何编写高质量的python程序 - 蛙蛙王子 - 博客园 蛙蛙推荐:如何编写高质量的python程序 如何编写高质量的python程序 目录 代 ...

  7. 判断某值是否属于枚举类中的值_编写高质量可维护的代码之优化逻辑判断

    if else.switch case 是日常开发中最常见的条件判断语句,这种看似简单的语句,当遇到复杂的业务场景时,如果处理不善,就会出现大量的逻辑嵌套,可读性差并且难以扩展. 编写高质量可维护的代 ...

  8. 编写高质量可维护的代码:优雅命名

    大家好,我是若川.今天分享一篇关于如何命名更优雅的文章. 点击下方卡片关注我.加个星标,或者查看源码等系列文章.学习源码整体架构系列.年度总结.JS基础系列 本文首发于政采云前端团队博客:编写高质量可 ...

  9. 读书笔记:编写高质量代码--web前端开发修炼之道(二:5章)

    读书笔记:编写高质量代码--web前端开发修炼之道 这本书看得断断续续,不连贯,笔记也是有些马虎了,想了解这本书内容的童鞋可以借鉴我的这篇笔记,希望对大家有帮助. 笔记有点长,所以分为一,二两个部分: ...

最新文章

  1. 祝全天下的教师,节日快乐!
  2. ubuntu KDE桌面
  3. C++ Primer 5th笔记(chap 15 OOP)继承之类型转换
  4. java中class.forname连接mysql数据库_数据库链接与 Class.forName()用法详解
  5. WebAPi的可视化输出模式(RabbitMQ、消息补偿相关)——所有webapi似乎都缺失的一个功能...
  6. 【计算机基础】 Virtual memory 虚拟内存
  7. 小米登录协议分析_小米回应小米11充电头兼容问题
  8. web高德地图怎么加载离线地图_怎么验证全国离线卫星地图缓存文件的完整性
  9. vs code python 插件_工具篇-vscode效率提升插件
  10. 作为微软技术.net 3.5的三大核心技术之一的WCF虽然没有WPF美丽的外观
  11. ERROR: Failed building wheel for pycrypto
  12. jsp不能使用return时候,如何在出异常时退出,不在向下执行
  13. vba循环通过键盘某个按键按下退出循环_[VBA]For Next与Do Loop循环
  14. caffe上手:如何导出caffemodel参数
  15. Julia: 自制的Julia代码排版工具CodeBeautify
  16. android常用代码合集,Android开发常用经典代码段集锦
  17. 学考计算机会考考点工作总结,高中生学业水平考试工作总结范文
  18. openlayers6 解决调用百度地图之瓦片偏移、坐标偏移、无限拖动裂缝偏移问题
  19. 为您的创业公司推荐5款类Slack开源协作工具
  20. 如何对音频文件进行剪辑

热门文章

  1. emq插件开发mysql_EMQ的Mysql插件
  2. dl 系列服务器,DL系列服务器内存总结..doc
  3. kotlin 反射java类_关于Kotlin反射中实例化类的问题
  4. 源码安装python
  5. ubuntu 安装 postgres
  6. 从postgress 读取数据
  7. 两个数组找相同元素_Excel 数组公式全面解析
  8. MATLAB实战系列(七)头脑风暴优化(BSO)算法求解旅行商问题(TSP)
  9. WEB开发中的会话控制
  10. Hadoop学习之HDFS架构(一)