it-swarm.cn

在方法内部编写注释不是一个好习惯吗?

一位朋友告诉我,在方法内部编写注释不是很好。他说,我们应该仅对方法定义(javadocs)进行注释,而在方法主体内部则不应。看来他在书中读到,在代码中包含注释意味着代码中存在问题。我不太明白他的理由。我认为在方法主体中编写注释是很好的,它可以帮助其他开发人员更快更好地理解它。请提供您的意见。

63
Srini Kandula

您的朋友是错误的,很少有程序员会同意他的观点。无论何时何地,您都应该写评论,以帮助他们更好地理解。

151
mqp

忽略你的朋友。根据需要发表评论。但是,请努力使您的代码不言自明,以便需要注释没有。请记住,您的计算机没有执行注释,因此注释很容易与实际发生的情况不同步。

我倾向于用一段注释来解释一个特别棘手的逻辑,否则这将需要一些脑筋来阅读。然后,我将尝试使逻辑更清楚,并消除解释的需要。

90
Michael Petrotta

好的代码可以自我记录。一个方法应该只做一件事,而通过方法名称和注释规范,这件事应该很明显。因此,在解释逻辑的方法中需要注释表明该方法应分解为单一职责方法。

现在,为了现实。您面临着一个复杂的意大利面条式代码库,并且您试图对维护人员保持友好。您没有时间或权限来重构800万行代码,即使您这样做,也可能会产生细微差别,因为一切都很复杂。你是做什么?

44
Mark Peters

令我惊讶的是,有多少人不同意这种观点。

  1. 好的代码应该是自记录的,因此您应该仔细选择方法名,变量名等。
  2. 您的方法不能太长,以至于无法在一个屏幕中看到整个方法和注释

也就是说,也有例外。但是它们是例外。唯一的例外是数量很少。如果您做违反直觉的事情,您实际上只需要内联解释代码。

在您的方法中可能需要注释的一种典型情况是,当您应用本地技巧来优化速度时,但是在初读时,这可能会给另一个程序员带来一些麻烦。这是添加评论的好地方。

但一般来说:不,请不要在方法中添加注释。

24
markijbema

我认为他在谈论这样的情况:

public void upload() {
    // destination Host
    String Host = ....
}

通过使用更明确的变量名而不是注释可以使代码更好的地方:

public void upload() {
    String destinationHost = ....
}
18
Douglas

我相信您的朋友指的是Robert C. Martin的“清洁代码”。但是,我认为他有点简化了情况。本书讨论了为方法赋予清晰和描述性的名称,我们都应该知道,但是永远不能重复。该书还建议通过将可以给其明确描述性名称的任何代码块包装到自己的方法中,以使方法非常小。因此,如果您认为一段代码需要注释以说明其功能,则应将其设为具有适当名称的单独方法。从理论上讲,如果您所有的方法都在5行之内,并且它们都具有良好的描述性名称,那么不必在注释中进行解释就可以清楚地看出它们的作用。

但是,这并不意味着您不应在方法内部包含注释。关键是评论不应多余。他们应该添加信息。如果您有一种方法可以完成某件事,并且从名称中可以明显看出该事,那么您就不需要注释来说明它的作用。但是,最好有一条评论来解释为什么以这种特定方式执行其操作是很有意义的。您可能需要一个注释来解释为什么您选择一种算法而不是另一种算法,或者为什么选择一种数据结构而不是另一种数据结构。换句话说,您希望代码本身解释其工作方式,并且希望注释解释您的设计决策的原因,即。 e。为什么事情以这种特殊方式完成。

该书建议重构错误代码,而不是对其进行注释。从理论上讲,这当然是个好主意,但实际上您可能没有时间或基础架构,例如带有适当单元测试集的工作单元测试框架。有时您会遇到凌乱的代码库,您需要在昨天开始工作,而前进的唯一方法是尝试理解这些凌乱的代码并将它们注释为自己做笔记的一种方式。

16
Dima

是的,您绝对可以在Java方法内部编写注释。

Sun的代码约定 所示:

Java程序可以有两种注释:实现注释和文档注释。实现注释是在C++中发现的,由/*...*///分隔。文档注释(称为“文档注释”)仅适用于Java,并以/**...*/分隔。可以使用javadoc工具将Doc注释提取到HTML文件中。

因此,方法中的注释是实现注释。

8
zengr

我强烈不同意您的朋友,并认为内联函数注释是编写良好代码的重要组成部分。函数注释旨在使代码的客户可以更好地理解代码应该做什么—参数和返回值的含义,期望其在进入和退出时具有的不变式等。但是,内联注释主要针对代码的维护者,理想情况下是针对代码原始作者的一系列心理说明。他们可以查看他人阅读过的复杂方法,并了解原始作者的想法。它们也使诊断错误变得更加容易,因为如果注释描述了代码的意图和意图,那么发现故障时发现一段代码是错误的要容易得多。

我个人认为内联注释很有用,因为它们迫使我向自己证明我将要编写的代码可以正常工作。通常,我会养成不编写任何代码而没有先明确说明意图和意图的习惯的习惯。很多时候,这可以防止我在代码中犯傻的错误,因为我会发现我的解释不正确或没有考虑到Edge的情况。

当然,每个人都有自己的编码学科,也许有些人发现更容易编写没有内联注释的代码,而是将代码分成多个较小的方法。但是,根据经验,我发现内联注释在开发和调试过程中非常宝贵,对于在我移至另一个项目很长时间之后就必须查看和维护我的代码的其他人非常有用。

6
templatetypedef

您的朋友很可能会表达这样的观点,即注释本身不是“代码气味”,而是“ 除臭剂 “。这不是特定于方法内注释的,但对于方法内注释,它可能比对序言注释更真实。

当您写评论时,通常是在解释一些东西。当某些事情需要解释时-嗯,这不是不言自明的。出色的代码不言自明的。因此,当您添加评论时,您可以掩盖它无法解释的失败,而无需使其变得不解释。因此,每次您这样写评论时,代替更改代码-通过重命名,方法提取等-改为make不言自明,您没有达到理想。

但是我们所有人都一次又一次地缺乏完美。而且,添加解释性注释通常比保留难以理解的代码更好,这通常更好。

6
Carl Manaster

好的评论解释了为什么不怎么做。这是这里的关键区别。大多数人都可以跟随您的操作,但是为什么执行此操作需要额外的注释。这些评论应尽可能接近操作。

3
Bill Leeper

在注释您的代码(或其他人的文档非常糟糕的代码)时,您可能经常会遇到纯粹的disgusthatewrath的感觉。 。该代码可能会以令人沮丧且出乎意料的方式运行,并且您可能必须添加一些非常邪恶的技巧才能使其在一定期限内起作用。

在所有这些情况下,通常都通过用一些沉重的脏话注释代码的各个部分来表达您的感受(请参阅 Linux内核fuckcount )。这些注释必须存在于方法中,因此它们不会出现在自动记录的API中,因此您的老板,客户或任何其他与源代码无关的人都不会看到它。

但是,您的程序员同伴在研究源代码时会感觉很好救济幸福。 (当然,您可以为自己添加注释,或在某种程度上将源代码用作通信介质,#TODO: add more examples here

当然,您可能会争辩说,这类注释不应该放在首位,或者应该在最终发行版之前将其删除,但是这些天软件项目的发行周期很短,有些注释仍然有用以后每夜都会进行很多构建,因此也许您的朋友应该开始学习阅读(并写)两行之间

2
codecraft

拥有不需要注释的代码真是太好了。当您获取,保存和删除内容时,我们非常了解发生了什么,不需要注释。

有时,代码会变得凌乱,并且是重构的候选者,因此您可能必须同时注释。

今天,我有一行代码无法完成预期的工作。显然.net数据表不认为导入的行是新记录。当您从表中插入记录时,什么也不会发生。导入的行必须先更改其状态。只需提供一个简单的注释,所以当我从现在开始六个月后再回想一下,“我到底需要什么呢?”我会知道的。

1
JeffO

程序员通常认为在其他程序员不清楚代码在做什么的时候,将注释放在方法中。程序员有时也会在方法中放入TODO注释。但是,的确是这样,如果方法中的注释过多,则可能需要退后一步,以为您做的事情过于复杂。换句话说,您可能想避免对其他程序员显而易见的东西发表评论,因为这样很难与他们一起阅读代码。

为了积极接受您的朋友的建议,您应该记住,我们可以通过适当地命名变量和方法来避免过多评论,并保持每个方法的规模小,并确保它们不会占用太多人员。

1
knoguchi

我认为他之所以这么说是因为他认为函数应该足够简短,以至于每个函数都只封装一个概念操作。

我不一定要坚持这种信念(出于各种原因,包括阅读这样的代码可能会成为一场噩梦),但是如果这样做的话,可能会得出结论,每个函数只有一个注释,因为只有一个注释每个功能一个概念,每个概念一个注释。

无论哪种方式,无论何时何地,当代码的选择或行为不明显时,我都会使用注释,这通常与性能考虑因素或深奥的数学有关。这类东西通常并不立即与功能的使用者有关,因此我认为将其从文档中隐藏实际上是一个好主意。

1
Rei Miyasaka

我相信您的朋友正在谈论javadoc,如果它在您的方法声明上方(并用一个额外的星号装饰),它将从您的注释生成文档,如下所示:

/**
   get a webpage for a given url 
   @param url: the url to get
   @returns String: the http-source 
*/
public String getWebpage (String url) {
... 

如果将此注释放在方法中,那将毫无用处。

因此-根据经验:将注释放在方法上方的Java源中。

异常可能会发生。我同意:使用简短的方法,编写自我记录代码。但是,javadoc作为一种工具鼓励重复注释,因为否则它在文档中看起来太裸了。 :)

1
user unknown

我承认这一点,即从头开始编写的方法中,只能在标头中记录其功能。然而。

我发现注释经常插入发现错误的地方,而忽略了细微的差别即使该方法仅具有单一职责-老实说,在遗留代码中很少出现这种情况。此外,我认为没有理由要使用长度为40个字符的变量名(即使仅在两个地方使用),因为简短的变量名带有简洁的注释可以在以后更容易地消化和重用。简洁明了是最好的,但最重要的是,它是与其他程序员交流的一种手段,就像电子邮件,信件和诗歌一样。并为此添加引号:

“我只是把这封信加长,因为我没有时间将它缩短。”

布莱斯·帕斯卡(Blaise Pascal),(1623-1662年)省级字母

1
M. Tibbits

注释只会使代码对程序员更友好,请记住不会执行注释。

如果几个月后您要阅读代码,这些注释将使阅读代码更加容易。

这将使代码可维护,并且查看该代码的任何其他程序员都将很容易理解您已实现的逻辑。

这并不意味着即使对于只有几行代码的方法,也不必始终添加注释。

例如,以下代码是自解释的,不需要任何注释即可使其功能清楚

public String getName(){
    return name;
}

当方法很大时,请添加注释,以便任何程序员每次查看时都更具可读性。

请记住,在编写代码时,您可能会认为代码是可以自我解释的,但是六个月后查看时,您六个月前添加的注释绝对可以帮助您或任何其他程序员快速理解代码。

0
Alpine

内联注释的问题在于它们必须与代码一起维护(对于函数/方法/模块/类级注释也是如此,但程度不高);上帝知道仍然有多少源代码,这些注释与它们所记录的代码完全没有关系,而IMO与根本没有任何注释一样或多或少。

理想情况下,内联文档应限于以下情况:

  • 解释经过高度优化或“棘手”的代码,以及why的理由,说明该代码经过高度优化或“棘手”(“我们缺少性能要求X,性能分析表明存在瓶颈)部分;下面的优化获得了Y%的效果”);

  • 参照标准或要求(“ DTED 0柱间距为30弧秒”);

  • 确定需要进一步分析/开发的代码(“ TODO”);

代码记录的第一定律-不要记录明显的东西。代码文档第一定律的推论-编写尽可能明显的代码。

0
John Bode

首先,您的问题是专门面向Java的,这会极大地影响答案。

必需的注释量与您使用的语言高度相关。

  • 诸如Java=和C#)之类的某些语言非常适合自我记录代码的概念。在这些语言中,您将尽最大的努力使代码本身尽可能具有可读性和描述性,并且然后仅针对您在语言中无法原生描述的内容添加行内注释。

  • 某些语言(例如SQL)更难以阅读。语法,求值顺序,嵌套等可能使以自记录方式进行设计更具挑战性。同样的基本方法仍然适用:尽可能多地使用该语言,然后添加注释以弥补不清楚或令人困惑的区域。

总体而言,您不能100%取消注释,但是您的目标应该是通过使代码更具自描述性,尽可能删除need来删除注释。这些努力的结果通常是总体代码更少,组织代码更好。无论是否仍然存在注释,这都意味着您的代码将更加可维护和易于使用-这实际上是注释在任何方面都旨在提供的帮助。

0
STW

Javadoc(甚至是Delphi自动完成提示)应该更改人员编码方式(而不是为javadoc添加功能)的想法是很荒谬的。

问问您的朋友,javac或javadoc中哪个先出现?

这就像是要问先到的是母牛还是奥利里夫人


另外,javadoc应该适合于实现您的类和函数的人员,代码中的注释适用于维护您的代码的人员。尤其是使用您的私有方法时,没有必要一定要查看您的代码以了解其作用。那就是文档的目的。但是,如果某人由于一个错误而需要进行调整,则需要在方法中对此进行注释。

他显然假设90%的代码实际上是错误修复程序,但它们都是不好的。我从没看过《实用的程序员》,但我可以假设他没有引用那本书。

0
Peter Turner

既然聚会结束了,我就把我的两分钱丢掉。当我描述特定的业务逻辑时,或者当我不得不添加一些东西来覆盖无法预见的Edge案例时,我会使用注释。

代码会随着时间的流逝而发展,以解决事前未知的问题,因此,当您应用创可贴时,与其假定它是已知的why而不是将其放在创可贴上,有时它会有所帮助在代码中添加一个小块,上面写着“哦,顺便说一下,我必须解决这个问题,这里是bugtracker参考,以便您可以跟踪周围的谈话”,在我的情况下(因为我使用FogBugz),它看起来像这样:

_//Case: 1234 ~ Throttling based on unusual activity per ABC request.
Throttler myThrottler = new Throttler( oldActivity );
_

管他呢。因此,我的观点是,看起来不合时宜且不易读的内容可能是内联文档的好地方。收集知识是一件美丽的事情。

但是我的第一点是我的业务逻辑。我实际上在存储过程中有一个块,我将要重写此AM,该AM前面有一些业务规则。

_/****************************************************************
author  yourstruly
date    2010-11-18
descrip intended use is to blah blah blah
        ended up over actual measured blah blah blah according to blah blah blah
        rules from the customer are:
        If the sum of the blah blah blah is higher than the blah blah blah
        and the blah blah blah contain blah blah blah,
        and the blah blah blah is non-zero,
        recalculate the blah blah blah to fit within the blah blah blah

        Additional rules for us internally: 
        if the blah blah blah originally read blah blah blah don't blah blah blah (set to zero)

        rewritten here with (1) traceable statements for the where clauses.
        If 
            the blah blah blah(1) is higher than the blah blah blah (2)
        and the blah blah blah (3)
        and the blah blah blah is non-zero (9)
        and the blah blah blah is lower than the blah blah blah (4)
        and the edited blah blah blah is higher than the blah blah blah (5)
        then recalculate the blah blah blah (6)
        // See note lower in this document on the math

        If 
            the blah blah blah(1) is higher than the blah blah blah (2)
        and the blah blah blah (3)
        and the blah blah blah is higher than the blah blah blah (7)
        then set the blah blah blah to zero (8)

        (7) dictates the same as (4) but it's easier to do (7)
****************************************************************/

Sorry for the blah blah blah's but proprietary rules and all that ;)
_

突然间,您看到我的代码中嵌入了要求(!)作为注释,我可以将注释称为/*(1)*/(我这样做),以便可以轻松地为下一位员工追溯(确实如此,他能够立即找到需要调整的部分),然后如果有人想知道规格是什么,他们可以从上方阅读评论,如果有人想知道伪代码是什么,在那里,如果有人想将伪代码转换为代码,那么您就可以了。对我来说,这更具可读性(对于我而言),因为它保留了原始请求(从电子邮件中删除),并且无需过多考虑即可快速收集思路,并允许使用简单的转换形式伪成真实代码。

是的,有一些内联注释说这样的东西在伪代码中无法按预期工作,因为需求与数据不完全匹配,因此我们需要调整数据。但这就是我的意思。我们在线记录了Edge案例,并且将伪代码留在了适当的代码中以遵循逻辑,因此我们都知道原始要求是什么

0
jcolebrand