it-swarm.cn

“评论是代码的味道”

我的一个同事认为任何使用代码内注释(即,不是javadoc样式方法或类注释)都是 代码气味) 。你怎么看?

100
Fishtoaster

仅当注释描述了代码在做什么时。

如果我想知道某个方法或块中发生了什么,我将阅读代码。无论如何,我希望所有从事给定项目的开发人员至少对开发语言足够熟悉,以阅读所写内容并了解其工作情况。

在某些极端优化的情况下,您可能使用的技术会使某人难以跟踪您的代码在做什么。在这些情况下,注释可以并且应该不仅用于解释为什么要进行这种优化,还可以用于注释代码在做什么。一个好的经验法则是让其他(或多个其他人)熟悉实现语言和项目的人查看您的代码-如果他们既不理解为什么又怎么做,那么您应该同时评论原因和方式。如何。

但是,代码中尚不清楚的是您为什么要做某事。如果您采取的方法对于其他人来说可能并不明显,那么您应该在注释中说明为什么您做出了自己的决定。我怀疑您可能甚至没有意识到需要注释,直到进行代码审查之类的事情之后,人们才想知道为什么您用X而不是Y-您可以在代码中捕获所有看它的人的答案。在将来。

不过,最重要的是在更改代码时更改注释。如果更改算法,请确保更新注释,以说明为什么使用算法X而不是Y。过时的注释是更大的代码味道。

167
Thomas Owens

此刻,这让我特别恼火,我这个周末花了一些时间,看了一个非常有名,非常干净,没有注释的实现研究算法的代码(实际上并没有发布过)。我对此非常熟悉,坐在我旁边的那个人是发明家,而代码是几年前由其他人编写的。我们可以几乎跟随它。

很显然,您的同事经验不足。

110
Paul Nathan

评论应说明原因,而不是原因。

使用重构通常可以更好地处理How类型的注释。就我个人而言,我通常避免评论赞成重构。

之前:

# convert to cents
a = x * 100

# avg cents per customer 
avg = a / n

# add to list
avgs < avg
t += 1

后:

total_cents = total * 100
average_per_customer = total_cents / customer_count

track_average(average_per_customer)
75
Sam Saffron

我宣布你的同事是异端!我的异端燃烧靴子在哪里?

强迫注释是不好的,并且会引起维护麻烦,注释不能替代名称明确的方法,类,变量等。但是有时 为什么 对于必须在六个月内维护代码的可怜白痴来说,这是一种非常有价值的方式-特别是当那个可怜白痴最终成为您时。

我正在处理的代码中的一些实际注释:


    // If this happens, somebody's been screwing around with the database definitions and
    // has removed the restriction that a given alarm may have only one entry in the 
    // notifications table.  Bad maintenance programmer!  Bad!  No biscuit!



    // If an alert is active on our side but inactive on theirs, that might mean
    // they closed the alert.  (Or that we just haven't told them about it yet.)  The
    // logic comes later; for now, we'll just compile it in a list.



    // If we know for a fact that an alarm isn't getting through, we're going to whine pretty
    // aggressively about it until it gets fixed.

32
BlairHippo

理想情况下,代码应该被很好地编码,以使其具有自动解释性。在现实世界中,我们知道有时也需要注释非常高质量的代码。

您绝对应该避免的是“注释代码冗余”(注释不会在代码中添加任何内容):

i++; // Increment i by 1

然后,如果有一个好的(并且保持/保持一致的)代码设计和文档,那么注释就没什么用了。

但在某些情况下,注释可以帮助提高代码的可读性:

while( foo )
{
     if( dummy )
     {
     }
     else // !dummy
     {
     }
} // end while( foo )

别忘了您还必须维护和保持评论同步...过时或错误的评论可能会给您带来极大的痛苦!而且,通常,注释过多可能是不良编程的征兆。

29
Wizard79

将方法或过程分类定义为“代码气味”是“狂热气味”。该术语正在成为新的“被认为有害”。

请记住,所有这些事情都应该作为指南。

许多其他答案对于何时发表评论提供了很好的建议。

我个人很少使用评论。说明非显而易见的过程的目的,并将偶然的死亡威胁留给可能正在考虑自己进行更改并需要数周调整的任何人。

重构所有内容,直到幼儿园可以理解为止,这可能不会有效地利用您的时间,并且可能不会表现得更简洁。

注释不影响运行时间,因此要考虑的唯一负面问题是维护。

26
Bill

这里的主要问题是术语“代码气味”的含义。

许多人(包括您在内,我认为)都知道代码的气味接近错误或至少需要修复。也许您认为它是“反模式”的同义词。

这不是这个词的意思!

代码气味隐喻源自 Wards Wiki ,它们强调:

请注意,CodeSmell暗示可能出了问题,而不是确定性。完美的习惯用法可能被认为是CodeSmell,因为它经常被滥用,或者因为有一种更简单的替代方法在大多数情况下都可以使用。调用CodeSmell并不是攻击。这只是一个迹象表明必须仔细观察。

因此,注释是代码气味的意思是什么:它意味着当您看到注释时,您应该停下来思考:“嗯,我感觉到有一些可以改进的提示”。也许您可以重命名变量,执行“提取方法”重构-也许注释实际上是最好的解决方案。

这就是注释成为代码气味的含义。

编辑:我只是绊倒在这两篇文章,这比我更好地解释了:

23
Rasmus Faber

在某些情况下,好的命名,重构等功能都无法替代注释。看看这个真实的例子(语言是Groovy):

  response.contentType="text/html"
  render '{"success":true}'

看起来很奇怪,不是吗?可能是复制粘贴错误?哭了一个错误修正?

现在与注释相同:

  // DO NOT TOUCH THE FOLLOWING TWO LINES; the ExtJS UploadForm requires it exactly like that!!!
  response.contentType="text/html"  // must be text/html so the browser renders the response within the invisible iframe, where ExtJS can access it
  render '{"success":true}'         // ExtJS expects that, otherwise it will call the failure handler instead of the succss handler
23
user281377

我认为规则很简单:想象一个完全陌生的人看到您的代码。您可能会在5年后对自己的代码陌生。尽量减少为了解这个陌生人的代码而付出的精力。

21
LennyProgrammers

拥有正确评论的一个好主意是从编写评论开始。

// This function will do something with the parameters, 
// the parameters should be good according to some rules.
myFunction(parameters)
{
    // It will do some things to get started.

    // It will do more with the stuff.

    // It will end doing things with the stuff.
}

这样一来,您就可以轻松提取方法,甚至摆脱注释,
只要让代码告诉这些事情即可!看看如何以一种很好的方式重写(剪切/粘贴):

// This function will do something with the parameters, 
// the parameters should be good according to some rules.
myfunction(parameters)
{
  var someThing = initializedWithSomething;

  doSomethingWith(someThing);

  doMoreWith(someThing);

  endDoingThingsWith(someThing);

  return someThing;
}

// This function will do some things to get started,
// the parameters should be good according to some rules.
doSomethingWith(parameters)
{
  parameters.manipulateInSomeWay();
  ... etc ...
}

... etc ...

对于无法分离的事物,请不要提取方法并在注释下键入代码。

我认为这是将注释保持在最低限度的一种有用方法,对每一行进行注释确实没有用...仅记录一行有关魔术值初始化或有意义的地方。

如果参数使用过多,则它们应该是您的类中的私有成员。

11
Tamara Wijsman

我认为答案是通常的“取决于”之一。仅仅为了注释代码而注释代码是一种气味。注释代码是因为您使用的模糊算法的速度快一个数量级,因此可以节省维护程序员(通常是我在编写代码后的6个月内),以节省半天的时间来确定代码的工作方式。

10
Brandon
// Dear me in the future. Please, resolve this problem.

要么

// You think this code was written by somebody else. 
// No, it wasn't. You ([some name]) did it.
10
Zzz

代码注释绝对不是“代码气味”。这种信念通常来自这样一个事实,即评论可能会过时(过时)并且难以维护。但是,有很好的注释来解释为什么代码以某种方式做某件事对于维护很重要(通常很重要)。

好的注释可以使您更容易理解代码在做什么,更重要的是,为什么要以特定的方式进行代码。注释应供程序员阅读,并且应清晰准确。难以理解或不正确的评论比根本没有评论要好得多。

在代码中添加清晰准确的注释意味着您不必依靠内存来理解代码部分的“内容”和“原因”。这一点在以后查看该代码时非常重要,否则其他人必须查看您的代码。因为注释已成为代码文本内容的一部分,所以除了清晰书写外,它们还应遵循良好的书写原则。

要写一个好的评论,您应该尽力记录代码的目的(为什么而不是如何),并尽可能清楚地说明代码背后的原因和逻辑。理想情况下,注释应在编写代码的同时编写。如果您等待,则可能不会返回并添加它们。

Sam在24小时内自学Visual C#201 ,pp 348-349。

8
Scott Dorman

如果已以某种特定方式编写了代码,以避免出现库(第三方库或编译器随附的库)中存在的问题,则可以对其进行注释。
例如,注释需要在将来版本中更改的代码,或者在使用库的新版本时,或者从PHP4传递到PHP5时,也可以使用注释。

6
kiamlaluno

即使是写得最好的书,也很可能会有引言和章节标题。记录良好的代码中的注释对于描述高级概念以及解释代码的组织方式仍然很有用。

6
munificent

值得一提的是反模式:

我的印象是,有时会频繁使用FLOSS许可证的示例文件代替文件文档。 GPL/BSDL会生成一个很好的填充文本,此后您几乎看不到任何其他注释块。

4
mario

我不同意写注释来解释代码的想法不好。这完全忽略了代码存在错误的事实。可能很清楚代码does,没有注释。不太清楚代码是假定要做的。如果没有评论,您如何知道结果是否错误或使用不正确?

注释应解释代码的意图,以便在出现错误时阅读注释+代码的人有机会找到它。

我通常发现自己在编写内联注释之前我正在编写代码。这样一来,我就可以清楚地知道我正在尝试编写代码来做什么,并减少了在算法中不会真正知道自己在做什么的迷路。

4
Danny Tuppeny

我将自己回答一个问题。您可以在下面未注释的代码中找到该错误吗?

tl; dr:下一个维护您代码的人可能不像您那样敬虔。

 [org 0x7c00]

 main:
  mov ah, 0x0e
  mov bx, string
  call strreverse
  call print

 stop:
  jmp $

 strreverse:
  pusha
  mov dx, bx
  mov cx, 0

 strreverse_Push:
  mov al, [bx]
  cmp al, 0
  je strreverse_pop
  Push ax
  add bx, 1
  add cx, 1
  jmp strreverse_Push

 strreverse_pop:
  mov bx, dx

 strreverse_pop_loop:
  cmp cx, 0
  je strreverse_end
  pop ax
  mov [bx], al
  sub cx, 1
  add bx, 1
  jmp strreverse_pop_loop

 strreverse_end:
  popa
  ret

 print:
  pusha

 print_loop:
  mov al, [bx]
  cmp al, 1
  je print_end
  int 0x10
  add bx, 1
  jmp print_loop

 print_end:
  popa
  ret
 string:
  db 'Boot up', 0

 times 510 -( $ - $$ ) db 0
 dw 0xaa55
3
Ant

因为有人认为一种方法中包含700行是可以闻到的,所以添加了注释。

之所以有这样的评论,是因为您知道如果不发表评论,就会有人犯同样的错误,但又是一种气味。

插入注释是因为某些代码分析工具要求它也是一种气味。

不会ever进行评论的人,甚至不会为其他开发人员写一点帮助的人,也很奇怪。令我惊讶的是,有多少人没有写下来任何东西,但随后他们转身承认他们不记得三个月前的所作所为。我不喜欢写文档,但我想一次又一次地告诉人们同一件事。

3
MIA

您必须在代码和注释之间保持平衡...通常,我会尝试添加一些可恢复一段代码的注释。不是因为我无法理解代码(嗯,也是),而是因为我可以更快地阅读自己的代码,并在发生重要事件的地方找到特定的部分。

无论如何,我个人的标准是“有疑问时发表评论”。我更喜欢有一条冗余线,而不是一条我将无法理解的完全神秘的线。一段时间之后,我总是可以删除代码审查中的注释(我通常这样做)

另外,注释添加“ caveats”非常有用,例如“注意!如果输入格式不是ASCII,则必须更改此代码!”

2
Khelben

我认为代码注释起步很糟糕。这些日子我不知道,但是当我第一次在学校学习编程的时候,我得到了“编写一个在单独的行上打印数字一到十的程序。请确保您注释代码”的本质。如果您不添加注释,则会被打下标记,因为注释您的代码是一件好事。

但是,对于这样一个微不足道的过程,有什么要说的呢?所以你最终写经典

i++; // add one to the "i" counter.

只是为了获得一个不错的成绩,并且,如果您一点都不喜欢,就会立即对代码注释发表意见。

代码注释不是一件好事。这是有时必要的事情,而在最上面的答案中的托马斯·欧文斯(Thomas Owens)提供了对必要情况的很好的解释。但是,这些情况很少出现在家庭作业类型的作业中。

在许多方面,当不能在编程语言的有效部分中明确说出需要说的内容时,添加注释应被视为最后的选择。尽管对象命名可能会过时,但是各种人为和计算机缺乏反馈的机制使忘记维护注释变得容易,因此注释比活动代码更快地过时。因此,在可能的情况下,始终应该选择更改代码以使其更清晰,而不是使用注释注释不清晰的代码。

2
Alohci

读此书时,我想起了几十年前我第一次读到的东西(从更长的列表中保留下来,并通过影印件保存):

真正的程序员不写注释-如果很难写,应该很难阅读

闻起来有点老。

2
Murph

当然注释是代码的味道...

每个程序员最终都会知道我们所有人 发疯 由于工作量,调试或我们碰到的疯狂而已。

“做这个!”您的项目经理说。

您回答:“无法完成。”

他们说:“那么我们会找其他人去做。”

您说:“好的,也许可以做到。”

然后花接下来的X天数..周..月..试图找出答案。在整个过程中,您将尝试失败,并且尝试失败。 我们都这样做。真正的答案是有两种类型的程序员,一种是注释的,另一种是不注释的。

1)这样做的目的是通过编写文档以备将来参考,注释掉不起作用的失败例程(发现有用的例程后,气味并没有删除它们)来使自己的工作变得更容易,或者通过注释分解代码格式化为希望使其更易于阅读或理解。说真的,我不能怪他们。但最后,它们会折断,然后您便有了:// dammit this code sucks! swear! curse! i hate it! i am going to write something here to vent my anger!!!!

2)那些不假装自己是超级英雄,或 居住在山洞中 的人。他们只是鲁re地无视他人,而对代码或以后可能具有的含义则不太在意。

现在不要误会我..自记录变量和函数可以完全避免这种情况..信任我永远做不到足够的代码清理。但简单的事实是,只要保留备份,就可以[〜#〜]始终[〜#〜]删除注释。

1
Talvi Watia

注释和代码之间存在很大的根本区别:注释是人们与他人交流思想的一种方式,而代码主要是用于计算机的。 “代码”中有许多方面也只适用于人类,例如命名和缩进。但是评论是由人类严格为人类编写的。

因此,撰写评论与任何书面交流一样困难!作者应该清楚地了解受众是谁,以及他们将需要哪种文本。您怎么知道谁会在十年,二十年后阅读您的评论?如果此人来自完全不同的文化怎么办?等等,希望大家都理解。

即使在我所居住的同质小文化中,也很难与他人交流思想。人为交流通常会失败,除非是偶然的情况。

1
user15127

我认为在代码中不使用some注释是一种代码味道。虽然我同意代码应该尽可能地自我记录,但是您遇到了某个问题,无论代码编写得如何好,您都会看到毫无意义的代码。我已经在业务应用程序中看到一些代码,其中的注释几乎是必需的,因为:

  1. 您需要根据情况做一些事情,并且没有很好的逻辑。
  2. 更改法律后,您可能会在一两年内更改代码,而您想迅速找到它。
  3. 过去有人编辑过代码,因为他们不了解代码在做什么。

此外,公司风格指南可能会告诉您以某种方式做某件事-如果他们说您应该有注释,概述函数中正在执行的代码块,然后包含这些注释。

1
rjzii

我必须同意你的同事。我总是说,如果我注释我的代码,这意味着我担心[〜#〜] i [〜#〜]无法弄清楚我自己代码将来。这是一个坏兆头。

我在代码中添加注释的唯一其他原因是调用似乎没有意义的内容。

这些评论通常采用以下形式:

//xxx what the heck is this doing??

要么

// removed in version 2.0, but back for 2.1, now I'm taking out again
0
Ken

这是我的经验法则:

  • 编写代码,并将代码的简短摘要存储在单独的文档中。
  • 将代码放置几天,以进行其他操作。
  • 返回代码。如果您不能立即了解该执行的操作,则将摘要添加到源文件中。
0
Maxpm

向您的同事介绍 精简编程 技术。

0
SK-logic

代码注释在适当的地方提供了函数参数和返回值的单位,结构字段,甚至局部变量,都非常方便。记住火星轨道器!

0
dmuir

不,注释不是代码的味道,它们只是可以滥用的工具。

注释的示例:

//我认为这是厘米。需要进一步调查!

//这是做X的聪明方法

//此处的列表保证为非空

0
Andres F.

但是,根本无法理解的代码更大代码气味…

请给我简单的代码,但是
如果这不是一个选择,我宁愿使用带有注释的“脏”代码
比没有注释的脏代码。

0
Ian

大部分的话都是从我的嘴里拿出来的。但是我想总结一下:注释的重点是对代码的作用进行高层描述/解释。

此外,以下是一些我如何使用注释的示例:

  • 作为标题,以指示一段代码的一般目的
  • 注意我从哪里抄写了代码,从而避免了窃
  • 偶尔在方块的尽头,以提醒他们是什么方块的结尾
  • 指出看似可疑的代码是什么目的(例如,当开关盒掉了的那些奇怪的时间)
  • 解释算法背后的数学
0
Stewart

到目前为止,没有人在此线程中说过这一点,所以我将:

类型名称,变量名称,函数名称,方法名称和注释只是有关代码的元数据,与编译器生成的机器代码无关(当然,导出和调试符号的名称除外)。

类型名称和变量名称是您的名词,函数和方法名称是您的动词,并用它们来描述要完成的步骤。评论适用于其他所有内容。

一些例子:

double temperature; // In Kelvins.


/**
 * Returns true if ray hits the triangle
 */
bool castRayOnTriangle(Triangle t, Ray r)
{
    //...
    if (determinant == 0)
    {
        /* The ray and the triangle are parallel, no intersection possible.*/
        return false;
    }
    //...
}


/* X algorithm. Visit http://en.wikipedia.org/... for details.*/
<implementation of something difficult to understand for the layman algorithm. >

如果不进行更新,注释可能会过时,但是变量和函数名也可能过时。最近,我在C结构中遇到了bufPtr字段,该字段与缓冲区或指针无关。而且我看到了一个inflateBuffer函数,它不会对压缩的数据进行解压缩,而是完整的GZIP文件...这些与过时的注释一样令人讨厌。

0
Calmarius

在团队中进行编程似乎没有太多答案。我是一名高级开发人员,我倾向于写评论,以解释本来我不容易理解的内容。

我将其视为死后团队交流或教育的一种形式。我鼓励团队仔细研究他们正在使用的代码,但也许还没有写过以更好地理解它。

本周的几个示例(PHP代码):

//Pattern for finding jpeg photos
//Case insensitive pattern for jpg and jpeg
const PATTERN_PHOTO = "*.{[jJ][pP][gG],[jJ][pP][eE][gG]}";

我希望名字PATTERN_PHOTO在以后的代码中解释其作用会很有帮助,但是如果没有注释,对于初级开发人员来说,此特定模式的作用是多么清楚?

相同的代码集:

//Ignore . and .. directories in Linux
if($file != "." && $file != "..")

期望我们的开发人员了解PHP,但不希望他们了解我们用于托管的Linux OS。

因此,我发现这些注释实际上可以在很少的时间里提高我们团队的整体效率。

  • 人们很少因为不了解代码的工作原理而重写代码。 “我不知道它是怎么做到的,所以我把它修好了。”认真地说,我之前不得不处理这个问题。
  • 有关单个代码段的问题较少。只需回答一次问题,通常需要查找代码和时间让我重新熟悉它。有时我会在相隔一个多人的星期中得到相同的问题。 (是的,上面的例子很简单
  • 鼓励和引导其他开发人员自己学习。我希望他们会遇到//Ignore . and .. directories in Linux他们可能会跳上Google并突然对Linux有所了解。
0
Chris