如果有人说注释没有增加任何价值,我会问:对谁而言?
就我个人而言,我从来不喜欢写显而易见的注释是不好的实践的建议——可能是因为我一直在写显而易见的注释。
Jim 展示了一些“与代码本身保真度相同的代码注释”的示例。 这些是代码注释中最难处理的。
// this function adds two numbers
function add(a, b) {
return a + b;
}
很容易指出这一点并将其称为无用。 我倾向于不留下这种类型的注释,但 Jim 对此提出质疑是公平的。 注释可以用于可能在某些时候与该代码交互的各种人员,所以为什么要限制它呢?
[…] 注释在阅读时与编写时可以起到截然不同的作用。 这些几乎是两种不同的活动。
我想补充一点,当重新访问旧代码与积极工作时,它们的作用也不同。 当您尝试代码审查与直接贡献时,也会有所不同。
我一直讨厌任何人在我评论太多时指出这一点。 我的目标是编写任何具有任何技能的人都可以阅读、理解和/或从中学习的代码。 当我离开一个项目时,我希望将其留在一个初级开发人员可以进入并弄清楚的状态。
拥有 15 年经验的人很容易阅读注释,但我发现新人需要指导。 这些显而易见的注释可以节省很多麻烦。
如果您有一个复杂的条件,
if (A && B && (C || !D)) { ...
,您可以添加一个注释说// 检查<复杂属性> 的 <事物>
。 通常,这表示将逻辑抽象到函数/方法中是有意义的;thingHasComplexProperty = (A, B, C, D) => (A && B && (C || !D))
。 这样您的条件读取if(thingHasComplexProperty(A, B, C, D)) {...
,无需注释(以及其他潜在好处)。在 Typescript 中,类似
add(a: number, b:number): number
这样的内容是完全不言自明的——在 JS 中,您可能需要更多详细的信息,但随后addNumbers(a,b)
会更好,因为它在调用站点中使它变得很明显,因此仍然不需要注释。我关于内联代码注释的经验法则是不应该解释代码的功能——您可以阅读编写良好的代码以了解其功能。 如果我编写内联代码注释,是为了解释原因——而不是功能。(除非代码过于复杂或难以阅读——在这种情况下,真正需要重构,而不是注释。)
我对提交日志采用相同的方法:永远不要解释您更改了什么——差异将显示更改了什么;相反,解释您更改的原因。
我对“为什么”注释很慷慨,所以并不是说我试图减少行数——而是,如果我添加注释,它们应该添加到已存在的信息中。 如果您编写的注释只是重复其他信息,您只会分散或混淆信息;您是在教读者忽略您的注释。
几年前,我(部分出于玩笑)提出可以对“可读性”进行度量,方法是计算某人阅读代码时出现的“打嗝”或“卡顿”次数——即计算每次短暂的回视或暂停,在这些暂停中读者重新检查或仔细检查一行以确认是否已正确理解。 您执行此操作的次数越少,代码的可读性就越高。 在阅读包含嵌入式注释的代码时,可以认为在与代码段关联的 // 行和自文档化的未注释段之间来回跳转,从本质上讲,可读性较差,因为它会导致流程中出现卡顿。 我并不是说它是好是坏,或者我是否喜欢它,但我想说的是,可以提出这种说法。