代码整洁之道(二)优雅注释之道
一、Best Practice
注释应该声明代码的高层次意图,而非明显的细节
反例

说明
上文方法用于根据参数生成签名,注释中详细描述了签名算法的实现步骤,这其实就是过度描述代码明显细节
正例

总结
1. 注释一定是表达代码之外的东西,代码可以包含的内容,注释中一定不要出现
2. 如果有必要注释,请注释意图(why),而不要去注释实现(how),大家都会看代码
在文件/类级别使用全局注释来解释所有部分如何工作
正例

总结
通常每个文件或类都应该有一个全局注释来概述该类的作用
公共api需要添加注释,其它代码谨慎使用注释
反例

说明
以上接口提供dubbo rpc服务属于公共api,以二方包的方式提供给调用方,虽然代码简单缺少了接口概要描述及方法注释等基本信息。
正例

总结
公共api一定要有注释,类文件使用类注释,公共接口方法用方法注释
在注释中用精心挑选的输入输出例子进行说明
正例

总结
对于公共的方法尤其是通用的工具类方法提供输入输出的例子往往比任何语言都有力
注释一定要描述离它最近的代码
反例

说明
该方法有一行代码从map里删除了一个数据,注释放在了put调用之前,而没有直接放在remove之前
正例

总结
注释要放在距离其描述代码最近的位置
注释一定要与代码对应
反例

说明
注释中说明生成随机字符串的长度不能超过16字符,实际代码已经修改为32个字符,此处注释会产生误导读者的副作用
正例

总结
1. 注释一定要与代码对应,通常代码变化对应的注释也要随之改变
2. 若非必要慎用注释,注释同代码一样需要维护更新
一定要给常量加注释
反例

正例

总结
给每一个常量加一个有效的注释
巧用标记(TODO,FIXME,HACK)
1. TODO 有未完成的事项
2. FIXME 代码有已知问题待修复
3. HACK 表示代码有hack逻辑
示例

配置标记
可以扩展IDE修改标记的配置,比如加入解决人,关联缺陷等信息,以IDEA为例修改入口如下:

总结
1. 巧用TODO、FIXME、HACK等注解标识代码
2. 及时处理所有标识代码,忌滥用
适当添加警示注释
正例

说明
该方法创建了一个大小固定为1且类型为Map的数组链表,这个用法比较奇怪,需要注释说明原因
总结
代码里偶尔出现一些非常hack的逻辑且修改会引起较高风险,这个时候需要加注释重点说明
注释掉的代码
反例

说明
常见套路,为了方便需要的时候重新复用废弃代码,直接注释掉。
正例
同上,删除注释部分代码
总结
不要在代码保留任何注释掉的代码,版本管理软件如Git可以做的事情不要放到代码里
循规蹈矩式注释
反例

说明
分析上述代码可以发现两处注释非常别扭和多余:
1. 类注释使用了默认模版, 填充了无效信息
2. IDE为Getter及Setter方法生成了大量的无效注释
正例

总结
1. 不要保留任何循规蹈矩式注释,比如IDE自动生成的冗余注释
2. 不要产生任何该类注释,可以统一配置IDE达到该效果,推荐使用灵狐插件
日志式注释
反例

说明
修改已有代码很多人会手动添加注释说明修改日期,修改人及修改说明等信息,这些信息大多是冗余的
正例
代码同上,删除该注释
总结
不要在代码中加入代码的著作信息,版本管理可以完成的事情不要做在代码里
“拐杖注释”
反例

说明
示例代码简单实现了更新指定map k-v等功能,如果目标map不存在则使用指定k-v初始化一个map并返回,方法名为 updateConfigWithSpecifiedKV ,为了说明方法的完整意图,注释描述了方法的实现逻辑
正例

总结
抛弃“拐杖注释”,不要给不好的名字加注释,一个好的名字比好的注释更重要
过度html化的注释
反例

说明
类注释使用了大量的html标签用来描述,实际效果并没有带来收益反而增加阅读难度
正例

总结
1. 普通业务注释谨慎使用html标签,它不会给你带来明显收益,只会徒增阅读难度
2. 如果是公共api且用于生成javadoc可以考虑加入必要的html标签,比如链接,锚点等
二、编程语言注释实践
Java
文件/类注释规范
目前IDE安装 灵狐 后会自动配置IDE的file templates为如下格式:

强烈建议使用如上配置,统一、简洁就是最好。__如果有特殊需要需要定制类注释可以参考下图:

方法注释

IDE提供了统一的方法注释模版,无需手动配置,好的方法注释应该包括以下内容:
1. 方法的描述,重点描述该方法用来做什么,有必要可以加一个输入输出的例子
2. 参数描述
3. 返回值描述
4. 异常描述
举个例子:

块注释与行注释
1. 单行代码注释使用行注释 //
2. 多行代码注释使用块注释 /* */
Python
文件注释
重点描述文件的作用及使用方式

类注释

1. 类应该在其定义下有一个用于描述该类的文档字符串
2. 类公共属性应该加以描述
函数注释

1. Args:列出每个参数的名字, 并在名字后使用一个冒号和一个空格, 分隔对该参数的描述.如果描述太长超过了单行80字符,使用2或者4个空格的悬挂缩进(与文件其他部分保持一致). 描述应该包括所需的类型和含义. 如果一个函数接受*foo(可变长度参数列表)或者**bar (任意关键字参数), 应该详细列出*foo和**bar.
2. Returns: 描述返回值的类型和语义. 如果函数返回None, 这一部分可以省略
3. Raises:列出与接口有关的所有异常
多行注释与行尾注释

1. 复杂操作多行注释描述
2. 比较晦涩的代码使用行尾注释
Golang
行注释
常用注释风格
包注释
/**/ 通常用于包注释, 作为一个整体提供此包的对应信息,每个包都应该包含一个doc.go用于描述其信息。

JavaScript
常用/**/与//,用法基本同Java。
Shell
只支持 # ,每个文件都包含一个顶层注释,用于阐述版权及概要信息。
其它
待完善
小结
本文先总结了注释在编程中的最佳实践场景并举例进行了说明,然后就不同编程语言提供了一些注释模版及规范相关的实践tips。关于注释我个人的认知是:注释即代码,注释即文档,写好注释一个工程师必备的素质之一,在整洁代码前提下,更少的注释是跟高的追求。关于注释的实践暂时写到这里,后面会持续完善,也欢迎大家提供好的tips,文中代码大多出自于日常业务项目,也有部分摘自开源库,若有不妥之处敬请指正。
本文作者:竹涧
本文为云栖社区原创内容,未经允许不得转载。