为了清楚起见,编码标准:注释每一行代码?


142

我曾在一家生产至关重要的软件的商店工作过,还处理过一些注释规则,这些规则旨在保持代码的可读性并可能挽救生命。以我的经验,尽管要求变成了脑筋急转弯的工作,需要从清单中剔除,但这并不能帮助我专注于编写可理解的代码。这也分散了我的同行审阅者的注意力,使我无法就如何使代码更易于理解进行更有意义的对话。

我还对没有注释的学生代码进行了评分,并查看了为什么应将它们标记为忽略它们。

我知道使用好名,使结构简单,函数简短,并关注模块将使代码易于理解,从而可以最小化注释。

我也理解注释应该解释为什么代码会执行此操作,而不是如何执行。

鉴于所有这些,甚至有可能编写出能够抓住这一想法的良好编码标准?与同行评审有关但不会变成漫不经心的清单活动,不会产生比以下内容更有用的注释:“您忘了在第42行发表评论”。

在清单中被视为一行时,此规则可能需要的代码示例:

/* Display an error message */
function display_error_message( $error_message )
{
    /* Display the error message */
    echo $error_message;

    /* Exit the application */
    exit();
}

/* -------------------------------------------------------------------- */

/* Check if the configuration file does not exist, then display an error */
/* message */
if ( !file_exists( 'C:/xampp/htdocs/essentials/configuration.ini' ) ) {
    /* Display an error message */
    display_error_message( 'Error: Configuration file not found. Application has stopped');
}

如果有可能在标准文档中正确表达这一点,但可能不是这样,我想遵循以下思路:

考虑对代码的每一行,每个序列,语句,部分,结构,函数,方法,类,程序包,组件,...的注释。接下来考虑重命名和简化以消除对该注释的任何需要,因此您可以将其删除。在评论很少的情况下签入。重复直到截止日期。然后再重复一些


21
评论不作进一步讨论;此对话已转移至聊天
maple_shaft

32
“注释不适合扩展讨论”,对于代码注释更是如此。:)这些/* Display an error message */评论很可怕,实际上会影响可读性。
Andrea Lazzarotto

我们需要我们的IDE具有隐藏注释的选项。阻止和内嵌注释分别隐藏的选项。这样,您就可以同时拥有这两种选择中的最佳选择。放入很多注释,但可以选择隐藏它们以使代码看起来干净整洁。
Doug.McFarlane

1
@ Doug.McFarlane我认为vim应该存在。当然,它在文件级别和块级别都可以-rtfm-sarl.ch/articles/hide-comments.html
Michael Durrant

Answers:


171

迈克尔·杜兰特(Michael Durrant)的回答是恕我直言,还不错,但这并不是从字面上回答这个问题(正如他本人所承认的那样),因此,我将尝试给出一个答案:

我也理解注释应该解释为什么代码会执行此操作,而不是如何执行。

鉴于所有这些,甚至有可能编写出能够抓住这一想法的良好编码标准?

显然,您可以为代码审查编写清单,其中包含诸如以下问题

  • “如果有评论,它是否解释了代码为什么要这样做?”
  • “代码的每一行-在其上下文中-是不言自明的以至于它不需要注释,或者如果不需要,它是否伴随着注释来弥补这一空白?或者(最好)是否可以更改代码,以便它不再需要评论了?”

如果愿意,可以将其称为“编码标准”(或者不可以,如果您认为术语编码标准应保留给脑死亡规则的列表使用,则可以轻松回答是否满足这些规则,以及如何格式化代码)应该看起来像,还是在哪里声明变量)。没有人会妨碍您将清单的重点放在语义问题上,而不是走简单的路线,只把正式的规则放进去。

归根结底,您应该确定您的团队需要这样的清单。要解决此类问题,您需要具有一定经验的程序员作为审阅者,并且需要在专家团队中找出它是否真的可以提高代码的可读性。但这是您必须与团队共同努力的事情。


45
谁对此表示反对?这是关键软件开发答案。与大多数程序员的工作环境相比,这是一个不同的世界。在这些情况下,要求每一行代码都有自己的注释的编码标准不是正确的答案。都没有放弃的评论。OTOH,使注释受代码审查完全是关键软件的正确标准。它使代码更易于检查和维护,但这是有代价的。与编写不良软件引起的数百万美元的诉讼相比,这笔钱简直是小巫见大巫。
David Hammen

4
明智的答案。如果我们可以找到真正的编码规则,则不需要程序员。我们只需要机器代码。有可能发生!:(

4
@DavidHammen:感谢您的评论。实际上,我认为这不仅适用于“关键软件开发”。往往由不同的人维护和发展了数年的每一款软件,都会从对下一维护程序员的理解中受益。
布朗

5
对于任何编码,这都是很好的建议,而不仅仅是由不同人员维护的代码。即使您是唯一使用脚本/程序的人,将来您也必须在一年的时间内修改代码,这将使您很清楚(以及不必解密不透明的代码所节省的时间)。
Anthony Geoghegan

5
您可以将“当前最受好评的答案”编辑为更客观的内容吗?并非每个读者都会知道这些答案的投票历史。
candied_orange

151

严重的反模式导致代码质量较差清晰度较低

顺便说一句,读者的标题最初是“评论每一行代码?” 您可以想象我们当中包括我在内的许多人的本能反应。后来我改名了更长的标题。

开始时,我想念您的问题,评论中有很多重复的内容,但是,好吧,如果您对多人的评论有足够的限制...但是然后又重复了:人们会犯错误,无法注意到不一致之处,等等。最终会有分歧。经过反思,我认为问题要大得多:

开发人员将倾向于编写更糟糕的代码。他们将使用更多隐秘的名称和结构,因为“其内容已在注释中解释-见!”。

考虑:

living_room_set = tables + chairs.

现在考虑:

set = tbls+chrs # Make the set equal to the table plus the chairs

您不仅要拥有更多的神秘名称和更多的可读性,而且还必须来回查看代码,什么是集合?左看代码,右看注释,什么是tbls,左看代码,右看注释,什么是chrs,右看注释。ch!

摘要

如果您被迫担任开发人员的当前职位(如果是以前的COBOL编程专家,我肯定见过很多!),但要花很多时间,精力和精力来反对评论反模式使用参数:

  • 仅更改一项时,代码和注释便会彼此不同步

  • 评论可能会描述一个人的想法,但可能是错误的,从而掩盖了错误

  • 代码变得更难阅读

  • 好的代码变得很难编写

  • 倾向于使用更多神秘名称

  • 过多的字符需要阅读代码和注释

  • 不同的编辑使用不同的样式

  • 与编码相比,要求更高的英语水平

  • 花费时间和资源并从长期价值中减去 *

再加上争取更好的代码而没有这样的注释,-实际上有一个标准(!)-所有变量名都必须是full_english_words-有一个!因此,请将“标准”能量用于编写良好的代码和测试的标准。

两个棘手的问题之一是命名问题-不要一边用注释跳过问题。

鉴于其他问题之一是过早的优化,并且一般而言,优化可能导致模糊的“为什么采用这种方式”代码,因此,尽管上述警告仍然适用,但在这方面,对于看似较差的代码的解释性注释可能是有益的。

* 明天的代码


8
我不相信您回答了这个问题。问题不在于每行都有评论。它正在询问如何告诉开发人员注释代码而又不使他们注释每一行。
hichris123 '16

7
是的,我不是在回答特定的标准问题,而是试图帮助人们不要走这条路。因此,这可能不是特定问题的答案,确实包含有价值的建议,很难在评论中提出。
Michael Durrant

1
另一个难题是什么?
David Grinberg


1
您可以避免每一个避免评论的理由,但是StackExchange不允许足够长的评论(heh)让我在这里解决所有问题。简而言之:过度评论就像选民欺诈一样:确实会发生,但很少发生;您最后一次真正看到它的时间是什么时候?写出好的评论不应该只是事后的想法。如果做得正确,它将有助于开发过程。是的,这需要资源,但是收益是更好的代码。通过牺牲注释以获得更好的变量命名标准,您将永远无法获得相同的收益。是的,评论每一行都是胡说八道。
kmoser

23

我认为编码标准文档不是指定已经是常识的地方。编码标准的目的是保证在合理的人可能不同意且没有单一明显的正确答案(例如命名约定,缩进等)的问题上保持一致(并避免争论)。

这样的评论在客观上是没有用的,并且可能是由于没有经验的开发人员,或者是曾经使用过构建系统的开发人员以机械方式检查注释的存在(确实很糟糕,但是确实存在)。在这两种情况下,解决方案都是教育,可能需要通过代码审查。

如果您开始将各种“最佳实践”添加到编码标准中,那么您将最终重复出现在多本书中的内容。只需向有问题的开发人员购买“干净代码”,“代码完整”和“实用程序员”,并保持代码标准精简即可。


63
经过40多年的学习,我在球拍中学到的许多东西之一是常识根本不是常识。
John R. Strohm

10
没有常识。
whatsisname

1
in_programming no。real world哦,是的,但这仅是对真实世界中知识的称呼
Michael Durrant

@ JohnR.Strohm:我的经验比您的经验要积极得多,但是我也看到了如何通过机械地执行规则来积极地阻止使用常识。
JacquesB '16

我对这个答案有99.9%的同意。编码标准旨在成为开发人员在Code Review上进行辩论时要指出的内容。代码审查是为了丰富产品而不是发动战争。没有代码标准的代码审查激起了如此多的战争。我敢说,如果您不能自动检查编码标准中的项目,则应该在其中。进行代码审查是时候向其他经验不足的开发人员传授“常识”。现在不是争夺变量命名的时候。的Linux /内核/ gen_init_cpio.c线335
安德鲁牛逼Finnell

19

这不可能。您本质上想做的几乎是机械化良好的判断力。

在编写关键软件(例如用于生命支持医疗系统的软件)时,大量清单和其他清单几乎是不可避免的。不仅聪明的人都会犯错,而且这些设备的许多软件都是由不太擅长工作的人编写的,因此“系统”必须能够防范草率的工作,使其安全牺牲适销性。

最好的选择是忽略严格的编码标准进行评论,并以身作则来领导团队。努力产生适当注释的高质量代码,以显示他人的良好注释。与其尝试找到描述如何编写注释的终极方式(它们本身常常是判断调用),不如通过自己的代码审查每天向其他人展示您的意思。当其他成员阅读您的代码时,如果他们觉得有用,他们也会效仿。如果他们做不到,那么没有标准可以帮助他们写出更好的评论。


1
+1表示“您正在努力使良好的判断力化”,-1表示“您唯一的选择就是只希望获得最好的成绩”,这使我无法投票。 教育训练你的团队是一个选项,也。标准可以进行判断。
通配符

1
@Wildcard也许您可以解释标准如何进行判断?那不是那时的指南吗?标准是“在比较评估中用作度量,规范或模型的思想或事物”。一个人如何才能使用一种内在的主观性,那么主观性取决于谁在阅读它,以此来衡量质量?
Andrew T Finnell

1
@Wildcard:问题是,当您进入受管制的行业时,该过程在所有方面都至高无上,拥有一个过程比该过程是否值得更重要。一切都必须归结为某种形式的复选框,每个复选框都必须是特定且可验证的,并且您在复选框中拥有的余地越多,则在审核中遇到麻烦的风险就越大。
whatsisname '16

这是一个陌生的世界,请记住,规则是由对软件领域知识不多的官僚编写的,并且您通常最终会使用存在的系统来证明自己并要求自己,而不是作为确保高质量产品的手段。
whatsisname

1
@whatsisname我很高兴有其他了解的人。您的回复写得比我以前努力的要优雅,准确。该陈述with systems that exist to justify and require themselves rather than being a means to an end to ensure quality products正是我试图说明的。感谢您为我找到我的话。我是真的 我们必须将提高质量的想法与遵循流程的想法区分开,因为它们是不同的。这就是为什么我们有QA,S​​tackoverflow和非常宽容的客户的原因。
Andrew T Finnell

14

更新资料

我在报价中的回应强调:

我认为,指出注释的问题的答案不应在编码标准中解决,然后列出一系列防御性问题加以解决,这是唯一正确的答案。

这里的问题是,编码标准就是标准。非常主观的想法应该不会是在编码标准。它可以是“最佳实践”指南中的,但是在“代码审阅”期间不能针对开发人员使用该指南。我个人认为,编码标准应尽可能接近自动。当所有代码都可以自动执行时,在代码审查中浪费了很多时间来争论命名,间距,制表符,括号,注释等。甚至对答案tables,并chairs可以实现自动化。LINT'ers允许使用字典,每个概念的大写检查(变量,函数,方法,类等)。

在接受“拉取请求”之前,甚至可以由Robot LINT'er实施JavaDoc检查。许多开源项目都可以做到这一点。您提交“拉取请求”,该代码是使用Travis-CI文件(包括“静态分析”)构建的,并且必须通过所有可以客观表达的编码标准。没有人会抱怨“做错了”或“没有提供评论”,或者用错误的方式命名变量等。这些讨论没有任何价值,最好留给第三方机器人处理,这可以使我们的情感编码首当其冲。

要真正回答这个问题,我们必须解决如何编写一个标准,该标准解决如何回答以下问题:该评论是否有价值?编码标准不可能规定评论的“值”。因此,人类必须通过该清单。在编码标准中仅提及注释会创建清单,原始海报要避免。

这就是为什么注释通常不由编译器处理并去除的原因。它们的价值无法确定。有关评论是否有价值?是还是不是?。回答这个问题很困难。只有人类有机会正确回答它,即使如此,阅读它的人也只能在阅读时回答它。评论内容的价值受天气,他或她的家庭生活,他们刚刚参加的上次会议影响不大,一天中的时间以及所喝咖啡的量的影响。我相信情况会越来越清晰。

如何在任何标准中正确表达?除非可以持续,公平地应用标准,否则标准就没有用。

我认为编码标准应尽可能保持客观。变量被称为IS目标的方式。可以根据字典轻松地检查它们的正确拼写,语法结构和大小写。除此之外,还有“小便比赛”,由最有力量的人或“眉头殴打”赢得。我个人不做某事而感到挣扎。

当我发表评论时,我总是评论以第三人称与我的未来自我交谈。如果我在5年后回到此代码,我需要知道什么?什么会有所帮助,什么会造成混淆,什么会使代码过时?生成可搜索的公共API的文档代码和为未知的第三方提供价值的注释代码之间存在差异,即使该第三方是您自己也是如此。

这是一个很好的石蕊测试。如果您是该项目的唯一成员。您知道您将是该项目中唯一的一个。您的编码标准将是什么?您希望您的代码是干净的,自我解释的,并且将来对您自己可以理解。您是否会对自己进行代码审查,以了解为什么没有对每一行都发表评论?您是否会查看在签入的100个文件上创建的每个注释?如果没有,那为什么要强迫别人?

我认为在这些讨论中遗漏的是,Future You也是该项目的开发人员。在询问价值时,明天的您也是可以从评论中获取价值的人。因此,在我看来,团队规模并不重要。团队经验并不重要,它会经常变化。

没有大量评论代码对此进行审查,这阻止了起搏器坠毁并杀死患者。一旦谈论影响代码的注释,您现在谈论的是代码而不是注释。如果只需要缺少一条评论杀死某人,那么在此过程中还会有其他气味。


已经提供了针对这种严格编码方式的解决方案,作为编写软件本身的一种方法。它与评论无关。评论的问题在于它们对产品最终的工作方式没有影响。嵌入心脏起搏器后,世界上最好的评论无法阻止软件崩溃。或使用便携式EKG测量电信号时。

我们有两种类型的评论:

机器可读注释

注释样式,例如Javadoc,JSDoc,Doxygen等,都是注释一组代码提供的公共接口的所有方法。该界面只能由其他单个开发人员(两人团队的专有代码),未知数量的开发人员(例如JMS)或整个部门使用。可以通过自动化过程读取此代码,然后该过程将以不同的方式读取这些注释,例如HTML,PDF等。

这种类型的注释易于创建标准。这是确保每个公共可调用方法,函数,类均包含必需注释的客观过程。标头,参数,说明等。埃尔。这是为了确保其他团队可以轻松找到和使用代码。

我正在做一些看起来很疯狂的事情,但实际上并非如此

这些注释可帮助其他人查看为什么以某种方式编写此代码。也许正在运行代码的处理器中会出现数字错误,并且总是四舍五入,但是开发人员通常会处理四舍五入的代码。因此,我们发表评论以确保开发人员接触代码可以理解为什么当前上下文在做某事通常看起来是不合理的,但实际上是故意编写的。

导致许多问题的原因是这种类型的代码。它通常没有注释,后来被新开发人员发现并“修复”。从而破坏了一切。即使这样,评论也仅用于解释为什么不真正防止任何破坏。

不能依靠评论

注释最终是无用的,不能被信任。注释通常不会更改程序的运行方式。如果确实如此,那么您的过程会引起更多的问题,而应该这样。评论是事后的想法,只能说什么。代码很重要,因为这就是计算机处理的全部内容。

这听起来可能很愚蠢,但请忍受我。这两条线中的哪一条真正重要?

// We don't divide by 0 in order to stop crashes.

return 1 / n;

在此示例中,重要的是我们不知道“ n”是什么,也没有检查n是否为0,即使存在,也没有阻止开发人员将n = 0检查后的0 放在那的情况。是没有用的,没有任何自动化可以捕捉到这一点。没有标准可以捕捉到这一点。评论虽然很美(对某些人而言)与产品的结果无关。

测试驱动开发

产品有什么结果?必须严格检查在其中编写代码可以真正保存或杀死某人的行业。这是通过代码审查,代码审查,测试,测试,代码审查,单元测试,集成测试,试用,分阶段,几个月的测试,代码审查和单人试用,分阶段,代码审查,测试,然后可能最终完成的。投入生产。评论与此无关。

我宁愿没有注释的代码,有规范的代码,有经过验证的规范的单元测试,对在生产设备上运行代码的结果的研究,然后有据可查的未经测试的代码,也没有任何可比较的代码。代码反对。

当您试图弄清为什么某人以某种方式做某事时,文档记录是不错的选择,但是,多年来,我发现文档通常用于解释为什么“聪明”的事情做了,而实际上并不需要这样写。

结论

如果您在一家需要对每一行都进行评论的公司工作,我保证项目中至少有两名软件工程师已经用Perl,Lisp或Python编写了自动文档程序,该程序确定了该行的工作方式,然后在该行上方添加一条注释。因为这是可行的,这意味着注释是无用的。找到编写这些脚本的工程师来自动记录代码,并以此为依据来证明“每一条注释”都在浪费时间,没有价值并可能造成伤害。

一方面,我正在帮助一位密友进行编程任务。他的老师已规定必须记录每一行。因此,我可以看到这种思考过程的来源。只是问问自己,您要做什么,这是对的吗?然后问问自己;有什么办法可以通过这个过程“游戏”系统吗?如果有,那么它真的增加了任何价值吗?不能自动编写单元测试来测试代码是否符合特定规范,并且如果可能的话,那也不是一件坏事。

如果某个设备因为要在人体内而必须在某些条件下工作,那么确保它不会杀死它们的唯一方法是进行数年的测试,同行评审,试验,然后再也不要更改代码。这就是为什么NA​​SA仍在使用此类旧硬件和软件的原因。当涉及到生与死时,您不只是“做些改动并签入”。

评论与挽救生命无关。评论是针对人类的,即使编写评论,人类也会犯错。不要相信人类。恩,不要相信这些评论。评论不是您的解决方案。


3
评论的问题在于它们对产品最终的工作方式没有影响。如果阅读和编写代码的人为因素很重要,那我认为确实会影响代码的最终工作方式,但最终代码却不会影响代码的执行方式。我会说代码的问题仅仅是因为它过时了,然后比没有代码更糟糕
Michael Durrant

1
在这里,我们有一个计时员,他想每天提供我们所做工作的报告,以便他可以优化我们的工作。无论如何,我们对每天需要花费15分钟填写他的表格的事实感到有些生气,因此我们通过从日志中填充垃圾来实现此目的的自动化。
joojaa

1
“我们不将0除以阻止崩溃”的注释还有一个额外的问题 语法上尚不清楚“为了”一词是否适用于除法动作或其否定。如果使用“我们避免除以0以...”,则可以避免这种歧义。:)
通配符

1
“不要为了制止崩溃而除以零”实际上告诉了我很多有关编写它的人的心态。您不编写代码以避免崩溃!您编写代码以使代码正确无误,而不会崩溃只是正确的一小部分。如果要计算的注射药物量最终被零除,则您不会返回某些虚拟值,例如99999 ...
immibis

1
@AndrewTFinnell我的意思是,如果您有时有时会被零除错误,则添加“ if(divisor == 0)return <something>; //避免被零除”不会使您的代码更正确。相反,您需要找到除数为何为零的原因并加以解决。设计了一些算法,所以不可避免要使用零除数,但是这是个例外(在这种情况下,您可以返回“无法计算结果”的值)。
immibis

12

在谈论评论时,有两点不同。它们不相同,区别很重要。

文档向您介绍一段代码的外向位-接口。

通常,工具可以使您以“独立”方式阅读它们,即您不会同时查看基础代码。

所有接口都应记录在案(例如,每种方法,不包括私有方法),并应描述输入,输出以及任何其他期望,限制等,尤其是不能通过约束,测试等表达的东西(究竟有多少细节以及它的去向取决于项目)。

好的文档可以使潜在的消费者决定是否,何时以及如何使用代码。

源代码中的注释有不同的用途。他们在那里供人们查看源代码。它们主要描述实现。

注释总是在基础代码中读取。

评论应说明令人惊讶的决定或复杂的算法,或未采取的选择(和推理)。他们在那里,以便将来的开发人员可以了解其前任的思维过程,并掌握手头的信息,否则他们可能会忽略这些信息或花费大量时间进行搜索,例如

# 'map' outperforms 'for' here by a factor of 10  

// This line works around an obscure bug in IE10, see issue #12053  

-- We are going to recursively find the parents up to and including the root node.
-- We will then calculate the number of steps from leaf node to root node.
-- We first use a WITH clause to get the ID of the root node.

您不能从没有注释的情况中推断出任何内容,并且注释当然可能与周围的代码一样错误,甚至更多。作者和读者都必须做出判断。

注释每一行显然是更多可疑的附加价值工作,这伴随着机会成本。如果你有一个规则说每一行加以注释,你会得到,但在重要的部分费用被评论很好

但这比这还糟:如果注释了每一行,那么注释的目的就无法实现。注释变得杂乱无章,使代码难以阅读:模糊而不是澄清。此外,不加选择的评论使真正重要的评论更难被发现。

注释和文档均未提供对其描述的代码质量的任何度量或保证;它们不能代替真正的质量检查。他们的目的是前瞻性的,即希望他们能帮助与之互动的人避免犯错。

总而言之,您的编码标准可以并且应该需要文档(自动检查有助于发现未记录的功能/方法,但是人员仍然需要检查文档是否有好处)。评论是一个判断电话,您的样式指南应该承认这一点。那些从不发表评论的人,以及那些没有思考而发表评论的人,都应该受到挑战。


记录公共API是一个不错的主意,但是我真的很喜欢解释令人惊讶的决定。如果违反至少令人惊讶的原则至少有正当理由,那将是非常好的。+1
candied_orange

1
+1表示多余的评论。保持信噪比高。
sq33G '16

如果每一行都被注释,则特别是出于注释目的而 +1 会失败。太糟糕了,这可能(经常被用作)根本不发表评论的借口,但是由于您提到的原因加上它是正确的,因为如果每行都被评论,大多数人将自动且可以理解地开始忽略所有评论。
SantiBailors

10

您无法编入评论标准,因为您无法事先知道重要的评论。

但是您仍然要确保代码正确注释,因为这是至关重要的代码。解决方案是为代码审查制定标准-要求代码审查意见具有易懂性。

这不能保证它不会变成毫无意义的检查表,但是至少可以防止它使代码更难阅读。并有可能使其变得更好。

这就需要一种文化,即代码审查本身并不是毫无意义的手势,使代码难以阅读地返回是一件好事,而不是侮辱或烦恼。同样重要的是,一个不清楚的地方并不被视为读者的失败。

在某种程度上,无法阅读的代码是不可避免的。因为作者沉浸在上下文中,并且只有当您知道x,y或z时,才会看到明显的事物。

因此,您将无法制定一条能够给出良好反馈的规则,但是您可以现场检查评论。甚至非程序员经理也可以这样做-因为真正的问题不是写的代码可读性强,而是代码的实际可读性,这只能由阅读它的人来决定。


7
Re 您无法编入评论标准 -可以。您使注释需要进行代码审查,并且必须指出指出注释未解释代码的代码审查项目。这是一项支出,这是大多数编程环境都不想支付的支出。它在关键软件方面有回报。
David Hammen

“ ...仅当您知道x,y或z时才是显而易见的”。您可以指定需要先知道的知识量{x,y,z}才能看到明显的事物,然后(实物机械)),您可以检查当前代码是否成立。在没有的地方,添加注释直到它为止。
Trilarion '16

1
@DavidHammen:这不是评论的标准,而是评论的标准。这就是我接下来建议的解决方案。您不能说它一定要有一定的大小,或者必须使用特定的语法,或者甚至首先需要有用的注释(否则您将获得“向i添加一个”类型的注释)。您可以说审阅者必须对代码和评论发表评论。如您所说,您可以要求解决代码审查提出的问题。但是,要让HAS有责任去做好审稿人。只有审阅者才能判断代码和注释是否足够。
jmoreno '16

@DavidHammen被选中进行审查的人做出判断电话吗?当他们离开时?如果新人们不以相同的方式思考或说英语?如果“审阅者”离开了?您的建议将一些开发人员放在象牙塔的顶上,导致异议,不信任和沟通中断。评论旨在为可以使用它的人们提供见识或澄清。也许乔需要它,但玛丽不需要。玛丽是审稿人时会发生什么?还是乔?还是马克?
Andrew T Finnell

@jmoreno-不将有关注释的规则/准则放入编码标准中意味着程序员必须查看多个来源-并且他们不知道在哪里查看,直到评论回来说注释不合标准。认为编码标准中的所有内容都必须是自动化的是错误的。例如,有意义的名称规则不是自动的。至少还没有。例如xyz,或ij以及k如果是基于准确使用这些名称在其配方期刊论文实现科学算法可以说是相当有意义的名称。
David Hammen

9

注释每一行代码?没有

您所谈论的其他规则的目的就是为了避免这种情况。

对可读代码的注释充其量是多余的,而在最坏的情况下,会使读者放弃寻找注释不存在的目的。

如果您对整个代码进行注释,这是不言自明的,那么您在不给出任何其他信息的情况下将阅读量增加了一倍。我不确定这种冗余是否会奏效。可以想象一个审阅者说42表示“ display_error”,而评论说“显示警告”。但是想象一下代码中的变化。您现在有两个地方要更正。很明显,这种风格具有复制粘贴底片。

我想说的是,除了文档之外,代码最好不需要任何注释。

有些样式完全相反,如果您对线条有疑问,可以选择两种:

  1. 代码太复杂了,应该将其重构为一个函数,该函数的名称应具有代码部分的语义含义。它是if算法的复杂还是一部分。(或者聪明的LINQ单线)

  2. 如果无法简化,您将不了解足够的语言习语。

(我个人不是严格的无注释规则的狂热者,但我认为这是一个很好的初始思路。)

鉴于所有这些,甚至有可能编写出能够抓住这一想法的良好编码标准?

至于过程。我们的标准对审稿人功不可没。假设它们不是恶意的,则效果很好。

当他问“什么是变量o?”时,您将其重命名。如果他询问此块是做什么的,请重构或评论。如果有人争论是否清楚,或者审稿人没有弄清,那么就定义而言不是。在极少数情况下,很少有朋友提出类似第二意见的东西。

平均而言,您应该获得团队中普通程序员可以理解的代码。IMO保留了多余的信息,并确保至少其他团队成员可以理解该代码,而我们发现这是一个很好的最佳选择。

另外,也没有绝对值。虽然我们是一小群。在5人小组中容易找到共识。


2
使用代码审查来决定应命名哪些变量,类和方法,这是使人们讨厌公司,企业或方法论的最佳方法。代码审查不应用作强制执行无关紧要的方法。编码标准必须通过自动化过程进行检查。变量名称的长度,圆复杂度,德米特定律都是可以检查的东西。如果有人告诉我将变量从“ i”重命名为indexForThePreviousCollection之类的东西,我会找到另一个工作场所。值大于3个字符的变量会在自动签入之前进行检查。
Andrew T Finnell

3
@AndrewTFinnell在您要命名的任何编程范例中,我都无法编写遵循代码的方法。
candied_orange

2
@AndrewTFinnell好吧,我会礼貌地不同意。“ 使用代码审查来决定 ”,我不知道您是从哪里提取的。我不希望与变量的代码工作ijk所有的地方之后原作者退出。我不理解您对“人类”基因组的观点。我怀疑是否有一种语言只能声明一个语句,或者很难理解两个语句。就像我说过的,我已经看到了复数ifLINQ单线。可以用语义上有意义的名称对它们进行注释或重构,我想这就是您的“良好注释”。
luk32

3
@ luk32我尊重不同意的权利。在我看来,迭代变量在上下文中非常明显。在我理解您的发言的情绪的同时,我相信有太多的实践使这种情绪达到了极致。我们真的需要这样的代码:for (int indexForCurrentDatabaseRow = 0; indexForCurrentDatabaseRow < currentUserRecordSetResults.length; indexForCurrentDatabaseRow = indexForCurrentDatabaseRow + 1)vs for (int i = 0; i < results.length; i++)吗?也许这与偏好和/或花在查看代码上的时间有关。冗长的名字让我闻起来。
Andrew T Finnell

2
我认为名称不应该在代码审查中确定。代码审查通常应该在作者认为足够好之后开始,这也意味着它经过正确注释,易于理解并且变量名称得体。问题是-如果审阅者认为代码太复杂或与变量的含义作斗争,那么代码将很难理解。这是没有争议的-显然至少有一个开发人员-审阅者-不理解这一点。是否需要对其进行重构(以及如何进行重构)或进行适当注释是另一回事。
Idan Arye

9

问题:

鉴于所有这些,甚至有可能编写出能够抓住这一想法的良好编码标准?在同行评审中将是相关的,但不会变成漫不经心的清单活动,该活动不会产生比以下内容更有用的注释:“您忘记在第42行发表评论”。

评论不应试图教育读者使用该语言。应该假定读者比作家更懂该语言,但上下文却比作家少得多。

您的示例中的这段代码的读者应该知道这exit()将退出应用程序-因此使注释多余:

/* Exit the application */
exit();

冗余的意见是违反干的,修改代码不一定传播到评论,留下不反映什么代码实际上做评论。

但是,解释您为什么要做某事的注释可能很有价值-尤其是如果您无法轻松地传达代码本身的含义时。

Python的PEP 8(CPython标准库中的Python样式指南)为内联注释提供了以下指南:

谨慎使用内联注释。

内联注释是与语句在同一行上的注释。内联注释应与语句至少分隔两个空格。它们应以#和单个空格开头。

内联注释是不必要的,并且如果它们表明显而易见,则实际上会分散注意力。不要这样做:

x = x + 1                 # Increment x

但是有时候,这很有用:

x = x + 1                 # Compensate for border

举这样的例子,我个人更喜欢走得更远,并且也会尝试消除这一评论。例如,我可能会得出:

border_compensation = 1
compensated_x = x + border_compensation

使代码自我记录并不是一个新主意

回到实际问题:

鉴于所有这些,甚至有可能编写出能够抓住这一想法的良好编码标准?

我相信PEP 8指南和示例演示了捕获此思想的良好编码标准。是的,我相信这是可能的。


1
“应该假设读者比作家更懂语言。”我很难相信那是正确的态度。我可以假设他们了解的程度很高,但是每个团队都不一样,团队中每个人都不同,因此在这一点上做个笼统的声明似乎并不明智。
Bryan Oakley

4
没有这一指导,您将让初级程序员提交注释,向他们自己解释琐碎的代码,而中级程序员则使用笨拙的解决方案,只是使初级程序员更容易访问代码。该指南消除了冗余,并确保即使是熟练的程序员也可以继续改进其代码。当我自己重新编写代码时,我可能已经忘记了上下文,但是总的来说,我知道该语言的性能甚至比初次编写时还要好。
亚伦·霍尔

4

我认为,当您看到这种评论时,有时会自己写这种方式,这是因为作者将规范写在评论中,然后逐一实施每个评论。

如果我们面临编写一个编码标准的挑战,而该编码标准所产生的代码在所需功能方面而不是在实际功能方面是可以理解的(这样就可以发现错误),那么我们是否真的在谈论规范的定义,记录和链接方式?最终产品?

编辑----

只是为了澄清。我没有评论最好的评论vs tdd vs单元测试。或建议每行评论是好/坏

我只是建议一个原因,您可能会看到示例中讨论的评论风格。

从这个问题上,关于注释的编码标准实际上是否可以更好地写成某种规格文件的要求。

即,注释用于解释代码的目的,这也是规范


6
在20年中,我从未见过有人用这种方式注释过他们的代码原型,然后用实际的代码填补空白。已经有一种客观的方法来实现您所说的或我认为您所说的。这就是所谓的测试驱动开发。单元测试定义规范以及代码是否符合该规范。全部没有评论。
Andrew T Finnell

9
虽然我认为问题中的代码不是一个很好的例子,但是在“代码完成”中专门提到了先在注释中写出一个过程,然后返回并填充代码的做法。帮助生成可读代码的可能做法,@ AndrewTFinnell。绝对不是闻所未闻的,即使这超出您的经验。
乔什·卡斯韦尔

6
我相信也早于tdd
Ewan

2
您是否在谈论伪代码编程过程?这样做的目的是减少评论。我从不记得那本书应该写注释了。评论产生一个概念性的程序意味着高层次的,而不是低层次的。如果要评论他们打算写的每一行,他们可能只是写了几行。这个想法是为了原型出代码的原理而不是每一行。这本书并不建议对每一行都进行注释。这是这个问题的重点。我可能是错的,但我认为那是第二版。
Andrew T Finnell

2
@JoshCaswell&Ewan,是的,它一种多年前的技术,确实早于TDD。但是,您本打算在以后删除评论!TDD已完全取代它,成为创建符合规范的代码的明智方式。
大卫·阿诺

4

鉴于所有这些,甚至有可能编写出能够抓住这一想法的良好编码标准?在同行评审中将是相关的,但不会变成漫不经心的清单活动,该活动不会产生比以下内容更有用的注释:“您忘记在第42行发表评论”。

显然,这超出了文档范围–涉及代码的结构,选择的算法等。它甚至可能涉及需求分析和设计。

我的第一条规则是“不要记录明显的东西”。#2规则是“写明显的代码”。

对于安全性至关重要的代码(感谢我,我从来没有做过),这是必要的,但远远不够第一步。甚至可能不得不强制要求必须避免使用哪些语言功能(我已经看到了不止一个标准强制要求“ scanf( "%s", input ); 出于任何原因不得使用”)。


情人眼中显而易见。并根据截止日期进行更改。
托尼·恩尼斯

3

自记录代码的最佳实践不是主流共识-尽管易于理解的代码比隐秘代码更好,这是众所周知的,但并不是所有人都同意是否必须始终重构复杂的代码,或者是否可以发表评论。它。

但是,在辩论是关于作品的代码是很难理解-你正在谈论注释行代码。难于理解的代码行应该非常少见-如果您的大多数代码行都像这样复杂,而不是您过度使用了智能资产单行代码,则应该停下来!当然,有时有时候很难理解某行的角色,但这是它在更大的代码段中的作用-该行本身的作用几乎总是很简单的。

因此,您不应该在注释行-您应该在注释代码。特定的注释可能位于它们所引用的行附近,但是这些注释仍在引用较大的代码。他们没有描述该行做什么/为什么这样做-他们描述了该行代码做什么和/或为什么在该代码中需要它。

因此,不是注释行,而是更大的代码段。是否应注释每段代码?否。哈罗德·阿伯森(Harold Abelson)说:“ 必须编写程序供人们阅读,而只能由机器执行 ”。但是注释供人阅读-机器不执行它们。如果您的编码标准强迫在每行代码/代码段上写多余的注释,那么您不仅在负担需要编写它们的开发人员的负担,还在负担着必须阅读它们的开发人员的负担!

这是一个问题,因为当您阅读的大多数评论都是多余的时,您将不再关注它们(因为您知道它们只是多余的垃圾),然后您将错过重要的评论。因此,我说-只写重要的注释,这样当有人在代码中看到注释时,他们就会知道有必要阅读该注释才能理解代码。


1
错过重要评论:+1。开头的句子:“它们不描述”可以使用一些重组以使其易于理解。
candied_orange

3

恕我直言,它应该两者兼而有之。评论每一行都是愚蠢的,因为您最终会看到以下行

  i++;    /* Increment i */

完全不知道为什么要增加i。稍微扩展一下,您将拥有典型的Doxygen注释风格,该注释会产生大量混乱,而没有提供有关代码用途或工作方式的任何想法。(至少就我所见:至少我可以使用这样的系统编写有用的文档,但我并没有屏息。)

OTOH,如果您在函数的开头(或任何逻辑上的分组)处编写了一个良好的注释块,既描述了要完成的工作,又描述了如何做(如果不那么明显的话),那么您将很有用。如果您是我,您甚至可能包括用于相关方程式的LaTeX代码,或对论文的引用,例如:“这实现了WENO方案,用于解决Hamilton-Jacobi方程,如...所述。”


2
doxygen注释的+1:这恰恰是我反对在我的代码中包含doxygen“文档”。95%的时间只是重复了函数签名中已经显而易见的内容。我也没有见过一个值得的Doxygen文档。编写这些评论会浪费三倍的时间:一次编写评论,一次再次阅读它们,一次调试由陈旧的评论内容造成的问题。
cmaster

1
你不是在矛盾自己吗?我想我们都同意,对于函数来说,从黑匣子的角度描述其功能至关重要-“这些输入输入,函数执行此操作,然后这些输出输出”。它形成了编写该功能的人与使用该功能的人之间的契约。Doxygen的目的只是以一种可解析的方式将这些注释的格式标准化,并使之可搜索/可索引。那么,为什么你想有一个“很好的注释块”,但希望它在一个标准的,人类和机器可读的格式?
格雷厄姆

正如@Graham所说,使用注释标准(例如JSDoc,JavaDoc和Doxygen)是为了提供可搜索和人类可读的文档。此答案中提到的代码行与Doxygen无关。我什至无法想象有一个规则集可以解析该注释并在输出的文档中产生一个条目。当您查看JMI文档,Java标准库等时,它们都是使用与Doxygen非常相似的工具生成的。这就是它的目的。没有什么在这里说
Andrew T Finnell

我没有对此进行补充-为了满足加拿大的要求,我工作的一家公司让开发人员编写了一个预处理器,该注释与OP的示例完全一样。我认为我们的代码是“向我加1”或类似的代码。它是FORTRAN,因此类似地将循环称为“ C LOOP FROM 1 to 10”。该代码已加载,且无用注释。我在维护代码时删除了所有这些废话。没有人对我说什么。
托尼·恩尼斯

2

是时候恢复流程图了!(不是真的,但要等一会儿)

前几天,我找到了旧的流程图模板。我只将它用于家庭作业和笑话(您必须喜欢一个很好的愚蠢流程图)。但是即使到了这个时候,大多数仍在使用流程图的商业程序员仍从代码中自动生成它们(这完全破坏了流程图的原始目的,这是编写更好代码的助手,并且在机器代码中非常有用。但是,使用高级语言时,流程图已从拐杖变成了霍布勒,为什么?流程图的抽象与代码相同,因此显示的注释很麻烦,因为它们与代码处于同一抽象级别。好的注释与代码的抽象级别不同,最简单的方法是使用注释来说明代码处理内容的原因。


很遗憾地通知您,流程图从未消失。
Ant P

好的注释与代码的抽象层次不同。听见!
candied_orange

1
尽管这可能是不错的建议,但似乎只有一个句子,但似乎并没有解决所提出的问题。
布莱恩·奥克利

0

我将回答上述问题:

鉴于所有这些,甚至有可能编写出能够抓住这一想法的良好编码标准?

是。所见即所得。一个好的编码标准从字面上是“ 对于读者来说清楚以下代码的作用以及原因 ”。

换句话说,我的代码审查评论从字面上看是关于代码可读性的1-1,这是由于我的心理状态

作为读者,我(更好的是,作为最低标准,是一个经验不足但很合理的读者的心理模型),我不会理解以下代码的目的或工作方法

通常,当人们听到“我作为高级开发人员,希望您不要傻瓜,他们一开始没有读懂此代码或为何有此代码或什么内容时,人们很容易上手”这需要更高的可读性”这样做,所以需要解释”。

这将论述从“您没有遵循毫无意义的标准”转变为“您的代码具有导致实际问题的特定可读性缺陷”。

需要明确的第二个标准是“凌晨2点紧急测试”。

当您在没有手机的智利安第斯山脉度假时,如果您没有使用此代码的经验,您的备份人员能否在凌晨2点紧急生产桥接电话中调试该代码时找出该代码的问题?

这听起来可能是主观的,但实际上实际上很容易衡量:召集一个随机的初级团队成员,预期该团队将在生产紧急情况下在夜间进行调试,并请他们解释未注释的特定代码如何工作以及为什么这样做那里。


0

这个答案涵盖了大多数问题,但是有一件重要的事情。

我想从以下方面捕捉一个想法:考虑每行代码,序列,语句,部分,结构,函数,方法,类,包,组件,...的注释。

有一些工具可以从代码生成文档,例如doxygen。如果使用这样的工具,则注释文件,函数,类等是有意义的。即使函数名是自解释的,我仍在这样做是为了保持一致性,因为阅读文档的人们将不胜感激。


1
但是,至少以我的经验,由此类工具生成的“文档”通常总比没有文档价值少,因为它无法为用户提供有用的信息(并导致他们浪费时间尝试提取非文档,存在的信息),但愚弄开发人员以为他们已正确记录了他们的代码。
jamesqf

@jamesqf是的,如果没有记录一半的功能,而另一半则记录得很糟糕。但是,如果开发人员正确地注释了他们的功能,类等,则doxygen可以生成非常好的文档。
BЈовић16

-1

许多现有的答案都非常详细,但我认为重要的是要回答:

... [评论]与同行评审有关,但不会变成无意识的清单活动...

对我来说,可能是标准的唯一评论可以通过询问缺少的评论来回答。换句话说:IDE或文档软件使用的注释。

话虽如此,这取决于开发人员使用哪些工具,并且并非此类软件使用的所有注释都一样有用

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.