避免写注释
高效能程序员的修炼
如果用很多的注释来“装饰”代码是件好事的话,那么在代码中加入大片大片的注释便是锦上添花了。对吗?事实上并不完全是这样。过犹不及,好心也会办坏事。
'*************************************************
' Name: CopyString
'
' Purpose: This routine copies a string from the source
' string (source) to the target string (target).
'
' Algorithm: It gets the length of "source" and then copies each
' character, one at a time, into "target". It uses
' the loop index as an array index into both "source"
' and "target" and increments the loop/array index
' after each character is copied.
'
' Inputs: input The string to be copied
'
' Outputs: output The string to receive the copy of "input"
'
' Interface Assumptions: None
'
' Modification History: None
'
' Author: Dwight K. Coder
' Date Created: 10/1/04
' Phone: (555) 222-2255
' SSN: 111-22-3333
' Eye Color: Green
' Maiden Name: None
' Blood Type: AB-
' Mother's Maiden Name: None
' Favorite Car: Pontiac Aztek
' Personalized License Plate: "Tek-ie"
'*************************************************
我经常跳过开发者写的注释,懒得看它们!他们似乎并不明白,其实他们的代码已经告诉我程序是怎样工作的;我需要注释告诉我的是,程序为什么这样工作。代码注释已经被广泛地误解和滥用,以至于你都开始怀疑它们原本的价值——注释还有存在的必要吗?你在期待什么?要当心!这里有一段完全没有注释的代码:
r = n / 2;
while ( abs( r - (n/r) ) > t ) {
r = 0.5 * ( r + (n/r) );
}
System.out.println( "r = " + r );
明白这段代码想要做什么吗?它看起来一清二楚,但到底是干什么用的呢?
让我们加上一行注释:
// 用“牛顿-拉夫逊”近似法求解n的平方根
r = n / 2;
while ( abs( r - (n/r) ) > t ) {
r = 0.5 * ( r + (n/r) );
}
System.out.println( "r = " + r );
这个应该就是我想要的了。不是吗?它介于完全没有注释与每隔一行就规规矩矩写上史诗般的注释这两种极端之间,看起来是一个不错的折中——对此你满意吗?
未必!与其添加注释,我更愿意把这段代码重构成这样:
private double SquareRootApproximation(n) {
r = n / 2;
while ( abs( r - (n/r) ) > t ) {
r = 0.5 * ( r + (n/r) );
}
return r;
}
System.out.println( "r = " + SquareRootApproximation(r) );
我连一行注释也没有加,但这段神秘的代码现在已经非常容易理解了。
尽管注释本身说不上是好还是坏,它们却常常被用作支撑代码的“拐杖”。你应该总是专注于编写代码,而忘了还有注释这种东西的存在。这会迫使你竭尽全力使用最简单、最直白、最能进行自我说明的方式把代码写出来。
为了让你的程序员同伴们更容易阅读和理解你的代码,你需要不断地改进你的代码,但如果你已经重写、重构甚至重新设计了很多遍——当你已经一筹莫展,已经想不出任何办法可以让你的代码变得更加浅显易懂——这时候,也只有在这时候,你才应该在百般无奈之下加上些注释来解释你的代码。
就像Steve Yegge指出的那样,这是初级开发者与高级开发者之间的一个关键差别:
坦率地说,要是在以前,让我一下子看太多的代码会让我崩溃,它的复杂度已经超出了我能接受的极限。而当我不得不在那些代码的基础上继续工作的时候,我通常会重写它们,或者至少也会写上大量的注释。现如今,当我碰到这种情况的时候我会披荆斩棘快速通过,而不会(过多地)抱怨。当我在脑子里有了一个明确的目标并且有一段复杂的代码要写时,我会把时间花在实现代码上面,而不是(用注释)写下它的故事、讲给我自己听。
初级开发者依靠注释来讲故事,而实际上他们应该依靠代码本身。注释是“旁白”,它们有其自身的价值,但绝不能用来代替(故事里的)情节、人物和场景。
或许这才是关于代码注释不可告人的小秘密:要想写出好的注释,你必须是一位优秀的作家。注释跟代码不一样,它不是写给编译器看的。注释是用来和其他人交流想法的文字。尽管我跟(大多数)程序员同伴们关系很好,但我必须承认,与其他人有效地沟通真的不是我们的强项。我曾经收到过我们团队里一位程序员发来的电子邮件,内容只有3段文字,但着实把我搞得晕头转向。我们能相信这样的人会在代码里写出清晰、易懂的注释吗?于是我想,或许让我们中的一些人去做那些他们擅长的事情会更好些——那就是,为编译器写代码,并且尽可能写得清楚些,而只把注释当作是最后没有办法的办法。
写出好的、有意义的注释是很难的。就像写代码一样,它是一门艺术;或许写注释还要更艺术一点!就像Sammy Larbi在“Common Excuses Used To Comment Code and What To Do About Them”(给代码加注释的常见理由以及应对方法)一文中所说的那样,如果你觉得你的代码在没有注释的情况下显得过于复杂、很难被人理解,那只能说明你的代码写得太糟糕了。重写你的代码吧,直到它不再需要任何注释。如果经过努力,你仍然觉得注释是必需的,那你就务必加上注释。切记,小心!