罗伯特·C·马丁(Robert C. Martin)的引用是出于上下文。这是带有更多上下文的报价:
没有什么比放置适当的评论那么有用了。没有什么比琐碎的教条式注释更容易使模块混乱了。没有什么比散布谎言和错误信息的陈旧粗鲁的评论造成的破坏那么严重了。
评论不像迅达的名单。他们不是“纯粹的好人”。实际上,评论充其量是必不可少的。如果我们的编程语言具有足够的表达能力,或者如果我们有能力巧妙地运用这些语言来表达我们的意图,那么我们将不需要太多注释,也许根本就不需要注释。
注释的正确用法是为了弥补我们未能在代码中表达自己的意愿。请注意,我使用了失败一词。我是真的 评论总是失败。我们必须拥有它们,因为我们不能总是想出没有它们的表达方式,但是它们的使用并不是值得庆祝的原因。
因此,当您处于需要编写注释的位置时,请仔细考虑一下,看看是否有某种方法可以翻转表格并用代码表达自己。每次用代码表达自己时,都应该轻拍一下。每次发表评论时,您都应该做个鬼脸,并感到自己表达能力的失败。
(从此处复制,但是原始引用来自“ 清洁代码:敏捷软件技巧手册”)
如何将此报价简化为“注释始终是失败”,这是一个很好的示例,说明了某些人如何将明智的报价从上下文中提取出来并将其转变为愚蠢的教条。
API文档(例如javadoc)应该记录API,以便用户无需阅读源代码即可使用它。因此,在这种情况下,文档应说明该方法的作用。现在您可以说“通过其ID检索产品”是多余的,因为它已经由方法名称指示,但是null
可能返回的信息对于记录文档绝对重要,因为这一点丝毫不明显。
如果要避免注释的必要性,则必须null
通过使API更显式来消除潜在的问题(将用作有效的返回值)。例如,您可以返回某种Option<Product>
类型,因此类型签名本身可以清楚地传达在未找到产品的情况下将返回的内容。
但是无论如何,仅通过方法名称和类型签名来完全记录API是不现实的。将文档注释用于用户应知道的任何其他非显而易见的信息。从DateTime.AddMonths()
BCL中获取API文档:
AddMonths方法考虑leap年和一个月中的天数来计算所得的月份和年份,然后调整所得的DateTime对象的日期部分。如果结果日不是结果月中的有效日,则使用结果月中的最后一个有效日。例如,3月31日+ 1个月= 4月30日。结果DateTime对象的时间部分与此实例相同。
您无法仅使用方法名称和签名来表达这一点!当然,您的班级文档可能不需要此级别的详细信息,仅是示例。
内联注释也不错。
不好的评论是不好的。例如,仅说明可以从代码中轻松看到的注释的示例,经典示例为:
// increment x by one
x++;
注释解释了一些可以通过重命名变量或方法或通过重组代码来使事情变得清晰的东西,这是代码的味道:
// data1 is the collection of tasks which failed during execution
var data1 = getData1();
这些是马丁批评的那种评论。该注释是未能编写清晰代码的征兆-在这种情况下,对变量和方法使用不言自明的名称。注释本身当然不是问题,问题在于我们需要注释才能理解代码。
但是应该使用注释来解释所有在代码中不明显的内容,例如为什么以某种非显而易见的方式编写代码:
// need to reset foo before calling bar due to a bug in the foo component.
foo.reset()
foo.bar();
注释解释了一个过于复杂的代码片段,这也是一种味道,但解决方法不是禁止注释,解决方法是修复代码!实际上,确实发生了混乱的代码(希望只是暂时的直到重构),但没有普通的开发人员第一次编写完美的干净代码。当卷积的代码发生时,写一个注释解释它的作用比不写注释要好得多。此注释还将使以后重构更加容易。
有时代码不可避免地很复杂。它可能是复杂的算法,或者出于性能原因可能是牺牲清晰度的代码。再次需要注释。