- 原文地址:Putting comments in code: the good, the bad, and the ugly.
- 原文做者:Bill Sourour
- 译文出自:掘金翻译计划
- 译者: bambooom
- 校对者:zhangqippp、steinliber
题图是克林特 · 伊斯特伍德在《黄金三镖客》中剧照。javascript
若是你之前听过这句话就打断我...html
「好的代码自身就是文档」。前端
在我 20 多年以写代码为生的经历中,这是我听得最多的一句话。java
陈词滥调。react
像其余许多陈词滥调同样,它的核心是一个真理。可是这个真理已经被滥用,大多数说出这句话的人并不知道它的真正意思。android
这句话正确吗?是的。ios
那是否是意味着你不该该给你的代码写注释?不是。git
本文中,咱们将介绍一下给代码写注释的好处、坏处和丑处。程序员
初学者须要了解,实际上有两种不一样类型的代码注释,我称之为文档注释和说明性注释。github
文档注释是为了给任何可能使用你的源代码的人看的,但他们不必定会通读代码。若是你正在构建给其余开发者使用的库或框架,你须要某种形式的 API 文档。
越早从源代码中提取 API 文档,随着时间的推移,文档就越有可能变得过期或不许确。减小这种状况的一个好策略就是直接将文档嵌入代码中,以后再使用工具提取文档。
下面是一个文档注释的例子,来自一个流行的 JavaScript 库,叫作 Lodash。
/** * Creates an object composed of keys generated from the results of running * each element of `collection` thru `iteratee`. The corresponding value of * each key is the number of times the key was returned by `iteratee`. The * iteratee is invoked with one argument: (value). * * @static * @memberOf _ * @since 0.5.0 * @category Collection * @param {Array|Object} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The iteratee to transform keys. * @returns {Object} Returns the composed aggregate object. * @example * * _.countBy([6.1, 4.2, 6.3], Math.floor); * // => { '4': 1, '6': 2 } * * // The `_.property` iteratee shorthand. * _.countBy(['one', 'two', 'three'], 'length'); * // => { '3': 2, '5': 1 } */
var countBy = createAggregator(function(result, value, key) {
if (hasOwnProperty.call(result, key)) {
++result[key];
} else {
baseAssignValue(result, key, 1);
}
});复制代码
若是你将这些注释与他们的线上文档作对比,你会发现它们彻底一致。
若是你开始使用文档注释,则须要确保这些注释遵循一致的标准,而且使它们与其余说明性的注释能够轻易区分开。一些普遍使用、有良好支持的标准和工具包括 JavaScript 的 JSDoc,dotNet 的 DocFx,Java 的 JavaDoc。
这种注释的缺点就是使你的代码很是「嘈杂」,并使得积极参与维护的人更难阅读代码。好消息是,大可能是代码编辑器都支持「代码折叠」的功能,这样就能够折叠这部分注释,专一在代码上。
上图演示在 Visual Studio Code 中折叠注释。
说明性注释是给任何可能须要维护、重构或扩展你的代码的人(包括你本身)看的。
一般来讲,须要说明性注释的代码散发着一种坏代码的气味,它的出现说明你的代码太复杂了。你应该尽可能简化代码并删除这种注释,由于「好的代码自身就是文档」。
如下是一个很差的 —— 虽然颇有趣 —— 说明性注释的例子。
/* * Replaces with spaces * the braces in cases * where braces in places * cause stasis. * (将大括号替换为空格,若是大括号形成停滞) **/
$str = str_replace(array("\{","\}")," ",$str);复制代码
若是做者不花时间在使用韵脚诗装点这个稍微使人疑惑的代码,确定能够将代码自己写的更加易读易懂。也许命名一个函数,removeCurlyBraces
在另外一个函数 sanitizeInput
中调用?
不要会错意,的确有很多时候 —— 特别当你正在拼命应对繁重的工做时 —— 注入一些幽默对身心都有好处。可是当你写了一个有趣的注释来修饰很差的代码时,实际上人们不太可能稍后重构或修复代码。
你真的想为掠夺全部将来程序员阅读这首聪明的押韵诗的乐趣而负责吗?大多数的程序员会笑起来,而忽略了这段代码自己的问题。
你也会遇到多余的注释。若是代码已经足够简单明了,就不须要再添加注释了。
好比说,不要作下面这种毫无心义的事:
/* 将年龄的整数值设为 32 */
int age = 32;复制代码
不过,有时候,不管你对代码自己作了什么,一个说明性注释仍是须要的。
这一般发生在你须要添加一些上下文解释一个不太直观的解决方法。
如下是一个来自 Lodash 的很好的例子:
function addSetEntry(set, value) {
/* 不要返回 `set.add`,由于它在 IE 11 中不可连接。 */
set.add(value);
return set;
}复制代码
也有一些状况是 ,在通过不少思考和实验后 ,看上去天真的解决方法事实上是最好的。在这些状况下,其余的程序员会不可避免地认为他们更聪明并开始本身动手实践,最后却发现你的方法是最好的。
有时上面提到的其余程序员就是将来的你。
在这些状况下,最好的作法就是写下注释,节省全部人的时间,避免尴尬。
如下这个注释完美地诠释了这种状况:
/** 亲爱的维护者: 当你完成了尝试「优化」这部分代码, 并意识到这是个多么大的错误时, 请增长下面的计数器以给下一我的警告: 总共在此处浪费的小时数 = 42 **/复制代码
固然,上面的例子更可能是有趣,而不是有帮助。可是你应该留下注释,警告其余人不要追求一些看似明显的「更好的解决方法」,由于你已经尝试过并否决了。当你这样作的时候,应该明确指出你尝试了哪些方案,为何否决了这些方案。
如下是一个 JavaScript 中的简单例子:
/* 不要使用全局 isFinite(),由于它对 null 值会返回 true. */
Number.isFinite(value)复制代码
咱们介绍了好处、坏处,那么丑处呢?
有时候你会感到沮丧,特别当你为谋生而写代码时,在代码注释中你倾向于将这种沮丧的情绪发泄出来。
使用过不少的代码库后,你会见到各类各样愤世嫉俗、沮丧到黑暗或意味深长的注释。
像这种看似无害的注释...
/* 这段代码很糟糕,你知道,我也知道。 继续往前,以后再叫我白痴。 */复制代码
...以及这种直白刻薄的注释
/* 这是配合 Richard 的工做而写的类,他是个白痴 */复制代码
这些可能看起来颇有趣,或者在当时帮助你发泄了一部分情绪。可是当你把它们变成生产环境代码时,它们使得编写它们的程序员以及他们的雇主看起来不专业和苦大仇深似的。
不要这么作。
若是你喜欢这篇文章,请在这篇文章下方戳一下 ❤ 点个赞,帮助我传播。若是你想阅读更多其余的文章,欢迎登记订阅我每周的 Dev Mastery 简报。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、React、前端、后端、产品、设计 等领域,想要查看更多优质译文请持续关注 掘金翻译计划。