我与之合作的开发人员有一些关于我感兴趣的评论的事情(见下文)。您的个人做法/评论意见是什么?
“我不会在代码中添加注释,除非 它是一个简单的标题或者有一个 平台错误或必要的 解决方法并不明显。码 可以改变,评论可能会变成 误导。代码应为
自我记录的使用 描述性名称及其逻辑性 组织 - 及其解决方案 应该是最干净/最简单的方式 执行给定的任务。如果一个 程序员不能说出一个程序是什么 那么只通过阅读代码 他还没准备好改变它 评论往往是一个拐杖 写一些复杂的或 不明显 - 我的目标是永远 写清洁简单的代码。““我觉得有几个阵营的时候 来评论, 企业家型谁认为他们是 写一个API和一些盛大的 将用于的代码库 几代人来了 思考的工匠般的程序员 代码说它比a更清楚 评论可以,和新手写 详细/不清楚的代码,以便需要 留言给自己说明原因 他们做了一些事情。“
答案 0 :(得分:29)
“自我记录代码”理论存在一个悲剧性的缺陷。是的,阅读代码将告诉您 正在做什么。但是,代码无法告诉您所谓的正在做什么。
我认为可以肯定地说,当代码没有做它应该做的事情时,所有错误都会引起:)。因此,如果我们添加一些关键注释来为维护者提供足够的信息来了解一段代码应该做什么,那么我们就已经让他们能够修复大量的错误。
这给我们留下了要提出多少评论的问题。如果你提出太多评论,那么维护的事情就会变得乏味,并且评论将不可避免地与代码过时。如果你投入的太少,那么它们就没那么特别有用了。
我发现定期评论在以下地方最有用:
1).h或.cpp文件顶部的简要说明,用于解释课程目的的课程。这有助于维护人员快速浏览,而无需筛选所有代码。
2)在执行非平凡函数之前的注释块,解释其目的并详细说明其预期输入,潜在输出以及调用函数时期望的任何奇怪事项。这使得未来的维护者不必破译整个功能来解决这些问题。
除此之外,我倾向于评论任何可能对某人感到困惑或奇怪的事情。例如:“由于等等,这个数组是基于1而不是基于0”。
写得好,评价良好的评论非常宝贵。糟糕的评论往往比没有评论更糟糕。对我来说,没有任何评论表明代码作者的懒惰和/或傲慢。无论你对代码的作用有多么明显,或者你的代码有多么美妙,进入一个代码体并且弄清楚到底发生了什么是一项具有挑战性的任务。做得好的评论可以让人们快速了解现有代码。
答案 1 :(得分:17)
我一直很喜欢重构对评论的看法:
我们在这里提到评论的原因是评论经常被用作除臭剂。令人惊讶的是,您经常查看厚度注释的代码并注意到注释是因为代码不好。
评论引导我们找到错误的代码,这些代码包含了我们在本章其余部分讨论过的所有腐烂的气味。我们的第一个行动是通过重构消除难闻的气味。当我们完成时,我们经常发现这些评论是多余的。
尽管有争议,但对于我读过的代码来说,这是真的。公平地说,福勒并不是说永远不会发表评论,而是在你做之前考虑代码的状态。
答案 2 :(得分:12)
您需要文档(以某种形式;并非总是注释)才能本地了解代码。代码本身会告诉您它的作用,如果您阅读所有并且可以记住它。 (更多内容见下文。)评论最适合非正式或半正式文档。
许多人说评论是一种代码气味,可以通过重构,更好的命名和测试来替代。虽然糟糕的评论(即军团)也是如此,但很容易跳到总结如此,哈利路亚,没有更多的评论。这就把所有本地文档的负担 - 我认为 - 太多了 - 用于命名和测试。
记录每个函数的契约,并为每种类型的对象记录它代表的内容以及对有效表示的任何约束(技术上,abstraction function and representation invariant)。在可行的情况下使用可执行的,可测试的文档(doctests,单元测试,断言),还要写一些简短的评论,给出有用的要点。 (如果测试采用示例的形式,则它们是不完整的;如果它们是完整的,精确的合同,它们可以像代码本身那样进行工作。)为每个模块和每个项目编写顶级注释;这些可以解释保持所有其他注释(和代码)简短的约定。 (这个
(例如,这:
进行n倍的散布 @param n次要的次数 @param x frobulation中心的x坐标 @param y frobulation中心的y坐标 @param z frobulation中心的z坐标
可能就像“围绕中心(x,y,z)重复n次。”评论不一定是读写的苦差事。)
我不像我在这里说的那样做;这取决于我对代码的重视程度以及我希望阅读的代码。但是学习如何以这种方式写作,即使是在偷工减料的时候,也会让我成为更好的程序员。
回到我们为了本地理解而记录的声明:这个函数做了什么?
def is_even(n): return is_odd(n-1)
测试整数是否均匀?如果is_odd()
测试一个整数是奇数,那么是的,这是有效的。假设我们有这个:
def is_odd(n): return is_even(n-1)
同样的推理说这is_odd()
测试一个整数是奇数。当然,将它们组合在一起并且都不起作用,即使每个都有效也是如此。稍微更改它,我们的代码可以正常工作,但仅适用于自然数字,同时仍然在本地看起来像整数一样。在微观世界中,理解代码库是什么样的:跟踪圈内的依赖关系以试图反向设计假设,如果他们打扰,作者可能会在一两行中解释。我讨厌在过去的几十年中,精神上没有思想的程序员让我这样做了:噢,这种方法看起来有副作用来解决战争核心的问题......总是如此?好吧,如果奇怪的crobuncles去饱和,至少;他们呢?更好地检查所有crobuncle处理代码......这将对理解提出自己的挑战。好的文档将这个O(n)指针切换为O(1):例如知道一个函数的契约和它明确使用的东西的契约,函数的代码应该是有意义的,没有进一步的系统知识。 (此处,is_even()
和is_odd()
处理自然数的合同会告诉我们两个函数都需要测试n==0
。)
答案 3 :(得分:11)
我唯一真正的规则是评论应该解释为什么代码存在,而不是它正在做什么或它是如何做的。这些事情可以改变,如果他们这样做,必须保持评论。代码首先存在的目的不应该改变。
答案 4 :(得分:9)
评论的目的是解释上下文 - 代码的原因;这,程序员无法从单纯的代码检查中知道。例如:
strangeSingleton.MoveLeft(1.06);
badlyNamedGroup.Ignite();
谁知道这是为了什么?但只有简单的评论,所有内容都显示出来了:
//when under attack, sidestep and retaliate with rocket bundles
strangeSingleton.MoveLeft(1.06);
badlyNamedGroup.Ignite();
严重的是,评论是针对为什么,而不是如何,除非方法不直观。
答案 5 :(得分:8)
虽然我同意代码应该是自我可读的,但我仍然认为在添加广泛的注释块以解释设计决策方面有很多价值。例如“我做了xyz而不是abc的常见做法,因为这个洞穴......”带有错误报告的URL或其他东西。
我试着将其视为:如果我已经死了并且已经离开而且大学毕业的人必须在这里修复一个错误,他们还需要知道什么?
答案 6 :(得分:6)
我通常也会订阅自我记录代码的想法,所以我认为你的开发者朋友提供了很好的建议,我不会重复,但肯定有很多情况需要注释。
很多时候我认为这可归结为实现与普通或简单抽象的类型有多接近,未来的代码阅读器会对此感到满意,或者更普遍的是代码告诉整个代码的程度故事。根据编程语言和项目的类型,这将导致更多或更少的注释。
因此,例如,如果您在不安全的C#代码块中使用某种C风格的指针算法,您不应期望C#程序员能够轻松地从C#代码读取切换(这可能通常更具声明性或至少更少关于低级指针操作)以便能够理解你的不安全代码正在做什么。
另一个例子是当你需要做一些工作来推导或研究一个算法或方程或某些不会在你的代码中结束的东西,但是有必要了解是否有人需要显着修改你的代码。你应该在某个地方记录这一点,并且在相关的代码部分中至少有一个引用将会有很大的帮助。
答案 7 :(得分:6)
总的来说,我看到用于解释写得不好的代码的注释。 大多数代码的编写方式会使注释变得多余。话虽如此,我发现自己在语义不直观的代码中留下了注释,例如调用具有奇怪或意外行为等的API ......
答案 8 :(得分:5)
如果代码在没有注释的情况下不清楚,首先使代码更清晰地表达意图,然后只根据需要添加注释。
评论有它们的位置,但主要用于代码不可避免地微妙或复杂的情况(固有的复杂性是由于问题的性质得到解决,而不是由于程序员的懒惰或混乱的思维)。 / p>
在代码行中要求评论和“衡量效率”会导致垃圾,例如:
/*****
*
* Increase the value of variable i,
* but only up to the value of variable j.
*
*****/
if (i < j) {
++i;
} else {
i = j;
}
而不是简洁(对熟练的程序员来说很清楚):
i = Math.min(j, i + 1);
YMMV
答案 9 :(得分:5)
我认为您的代码包含多少条或多条评论并不重要。如果您的代码包含注释,则必须像代码的其余部分一样进行维护。
编辑:这听起来有点浮夸,但我认为太多人忘记了即使是变量的名称,或者我们在代码中使用的结构,都只是“标签” - 它们只对我们有意义,因为我们的大脑会看到一串字符,例如customerNumber
,并了解它是一个客户编号。尽管评论缺乏编译器的任何“强制执行”,但它们并没有被删除。它们旨在向另一个人传达意义,一个正在阅读该程序文本的人类程序员。
答案 10 :(得分:4)
我的绝大多数通信都是在类级别和方法级别,我喜欢描述更高级别的视图,而不仅仅是args / return值。我特别小心地描述了函数中的任何“非线性”(限制,极端情况等),这可能会使不警惕的人感到沮丧。
通常我不会在方法内部发表评论,除了标记“FIXME”项目,或非常偶尔某种“这里是怪物”陷阱我似乎无法清理,但我努力避免这些。正如Fowler在 Refactoring 中所说的那样,评论往往表明代码很少。
答案 11 :(得分:3)
我更喜欢使用“Hansel and Gretel”类型的评论;代码中的小注释为什么我这样做,或为什么其他方式不适合。下一个访问此代码的人可能需要这些信息,而且通常情况下,那个人将是我。
答案 12 :(得分:3)
作为承包商,我知道有些人维护我的代码将不熟悉我正在使用的ADO.Net的高级功能。在适当的情况下,我添加了一个关于我的代码意图和MSDN页面URL的简短评论,该页面更详细地解释。
我记得学习C#并阅读其他人的代码我经常对这样的问题感到沮丧,“结肠字符的9个含义中的哪一个这个一个意味着什么?”如果您不知道该功能的名称,您如何查找?! (旁注:这将是一个很好的IDE功能:我在代码中选择一个运算符或其他标记,右键单击然后显示它的语言部分和功能名称.C#需要这个,VB不那么。)
至于“我不评论我的代码,因为它是如此清晰和干净”的人群,我发现有时他们会高估他们非常聪明的代码是多么清晰。认为复杂算法对作者以外的其他人不言自明是一厢情愿的想法。
我喜欢26的评论中的第17条(empahsis补充):
...阅读代码会告诉你确切的 做什么。但是,代码是 无法告诉你它是什么 假设正在做。
答案 13 :(得分:3)
注释是代码的一部分,就像函数,变量和其他所有内容一样 - 如果更改相关功能,注释也必须更新(就像函数调用需要更改,如果函数参数更改)。
一般来说,编程时你应该只在一个地方做一次。
因此,如果通过明确命名解释了什么代码,则不需要评论 - 这当然也是目标 - 这是最干净,最简单的方法。
但是,如果需要进一步说明,我会添加一个注释,前缀为INFO,NOTE和类似的...
信息:如果有人不熟悉该区域,则评论是一般信息。
注意:注释是为了警告潜在的奇怪现象,例如奇怪的业务规则/实施。
如果我特别不希望人们接触代码,我可能会添加一个警告:或类似的前缀。
我不使用,并且特别反对的是更改日志样式的注释 - 无论是内联还是文档的头部 - 这些注释属于版本控制软件,不源代码!
答案 14 :(得分:2)
评论是程序员工具箱的一部分,可以使用和滥用。这不是由你,其他程序员,或任何真正告诉你一个工具总体不好的人。一切都有地方和时间,包括评论。
我同意这里所说的大部分内容,但是代码应该写得如此清晰,以至于它是自我描述性的,因此评论不是需要,但有时会与最佳/最佳实现,尽管可以通过适当命名的方法解决。
答案 15 :(得分:2)
我同意自我记录代码理论,如果我只是通过阅读它无法分辨出代码的作用,那么它可能需要重构,但是有一些例外,我会添加一个注释如果:
答案 16 :(得分:2)
我很少发表评论。我的理论是,如果你必须评论它,因为你不是以最好的方式做事。就像“解决方法”一样,我唯一会评论。因为它们通常没有意义,但是你有理由这样做,所以你需要解释。
评论是IMO低于标准代码的症状。我坚信自我记录代码。我的大多数作品都可以轻松翻译,即使是外行也是如此,因为描述性的变量名称,简单的形式,准确的和许多方法(IOW没有方法可以做5种不同的事情)。
答案 17 :(得分:1)
我写的评论描述了函数或方法的用途以及它返回的结果。我不会写很多内联代码注释,因为我相信我的函数和变量命名足以理解正在发生的事情。
我在很多遗留的PHP系统上开发,这些系统写得非常糟糕。我希望原始开发人员在代码中留下某种类型的注释来描述这些系统中发生的事情。如果您打算编写其他人最终会阅读的难以理解或错误的代码,您应该对其进行评论。
另外,如果我正在做一些看起来不太正确的特定方式,但我知道这是因为有问题的代码是平台的解决方法或类似的东西,那么我会评论警告评论。
答案 18 :(得分:1)
在C语言编程时,我将在头文件中使用多行注释来描述API,例如函数的参数和返回值,配置宏等......
在源文件中,我会坚持使用单行注释来解释非自明的代码片段的目的,或者将一个不能以理智的方式重构为较小的函数的子函数。这是我在源文件中评论风格的an example。
如果您需要多行注释来解释给定代码片段的作用,那么您应该认真考虑一下您所做的事情是否无法以更好的方式完成......
答案 19 :(得分:1)
有时代码确实完成了它需要做的事情,但是有点复杂,并且在第一次有人看到它时不会立即明显。在这种情况下,我将添加一个简短的内联注释,描述代码的目的。
我还尝试提供方法和类文档标题,这对于intellisense和自动生成的文档很有用。我实际上有一个坏习惯,就是让90%的方法和课程都没有记录。当您处于编码过程中并且一切都在不断变化时,您没有时间记录事物。然后,当你完成后,你不想回去找到所有新东西并记录它。每个月左右回来并写一堆文档可能会很好。
答案 20 :(得分:1)
大多数时候,我发现最好的评论是我目前编写的函数或方法名称。所有其他评论(除了你朋友提到的原因 - 我同意他们的观点)都觉得多余。
所以在这种情况下,评论感觉有点矫枉过正:
/*
* this function adds two integers
*/
int add(int x, int y)
{
// add x to y and return it
return x + y;
}
因为代码是自我描述的。没有必要评论这种事情,因为函数的名称清楚地表明了它的作用,并且返回语句也非常清楚。当你将代码分解为像这样的小函数时,你会惊讶地发现你的代码变得清晰。
答案 21 :(得分:1)
这是我的观点(基于几年的博士研究):
评论功能(使用黑盒子的方式,如JavaDocs)和为读取代码的人(“内部评论”)评论实际代码之间存在巨大差异。
大多数“编写良好”的代码不应该需要太多的“内部注释”,因为如果它执行了很多,那么它应该被分解为足够的函数调用。然后,在函数名称和函数注释中捕获每个调用的功能。
现在,功能评论确实是问题所在,在某些方面,你的朋友是对的,对于大多数代码而言,对于完整规范而言,没有像流行API那样记录的经济激励。这里重要的是确定什么是“指令”:指令是那些直接影响客户的信息片段,需要一些直接的操作(并且通常是意外的)。例如,X必须在Y之前调用,不要从UI线程外部调用,要注意这有一定的副作用等等。这些是非常重要的事情。
由于大多数人从不阅读完整的功能文档,并浏览他们所阅读的内容,因此实际上只能通过捕获指令而不是整个描述来增加意识的机会。
答案 22 :(得分:0)
我尽可能多地评论 - 然后,就像我一年后需要的那样。
答案 23 :(得分:0)
我们添加注释,为所有公共类/方法/属性/等提供API参考文档......这非常值得,因为C#中的XML文档具有为这些公共API的用户提供IntelliSense的良好效果。 .NET 4.0的代码合同将使我们能够进一步改进这种做法。
作为一般规则,我们不会在编写代码时记录内部实现,除非我们做了一些不明显的事情。理论是,当我们正在编写新的实现时,事情正在发生变化,当尘埃落定时,评论更有可能不会出错。
当我们回到现有的代码片段时,我们会在意识到它正在考虑弄清楚到底发生了什么时添加注释。通过这种方式,我们最终得出的评论更可能是正确的(因为代码更稳定),并且它们更有可能是有用的(如果我今天回到一段代码,它似乎更多可能我明天可能会再次回到它。)
答案 24 :(得分:0)
我的方法:
评论弥合了上下文/现实世界和代码之间的差距。因此,每一行都以正确的英语进行评论。
我拒绝在最严格意义上不遵守此规则的代码。
使用格式良好的XML - 注释是不言而喻的。
马虎评论意味着草率的代码!
答案 25 :(得分:0)
以下是我编写代码的方法:
if (hotel.isFull()) {
print("We're fully booked");
} else {
Guest guest = promptGuest();
hotel.checkIn(guest);
}
这里有一些我可能会为该代码撰写的评论:
// if hotel is full, refuse checkin, otherwise
// prompt the user for the guest info, and check in the guest.
如果你的代码看起来像散文,那么编写评论就没有任何意义可以简单地重复代码读取的内容,因为阅读代码所需的心理处理和评论几乎是相同的;如果你先阅读这些评论,你仍然需要阅读这些代码。
另一方面,在某些情况下,使代码看起来像散文是不可能或极难的;这就是评论可以补丁的地方。