`

注释源代码表明你写的代码还不好

阅读更多
原文地址:
http://www.urubatan.info/2008/11/commenting-source-code-is-only-for-the-weak/

你们中的许多人可能不同意我的看法,但是当你阅读完了本篇文章,你将可能同意这点:
注释你自己的源代码是你写的代码不好看的标志。真正的程序员是写他人能读的代码!

但是记住我谈论的是说明代码是干什么的那样的注释,而不是诸如Javadoc那样的文档。

举一个例子:如果你不了解抑或不是一个Java程序员,你能很快地说出以下的代码是干什么的吗?


public String write(StringBuilder fle, StringBuffer con) {
  File f = new File(fle.toString());
  FileReader fr = new FileReader(f);
  BufferedReader br = new BufferedReader(fr);
  String lin;
  while((lin=br.readLine())!=null){
    con.append(lin).append("\n");
  }
  return con.toString();
}


困难吗?这只是一段非常简单的代码,但是我们可以让它变得再好一点...

public String read(StringBuilder fle, StringBuffer con) {
  //Opens the file with the name container in the fle parameter
  File f = new File(fle.toString());
  //Create a file reader, then a buffered reader to make our work easier
  FileReader fr = new FileReader(f);
  BufferedReader br = new BufferedReader(fr);
  String lin;
  //Read each line of the file until it is null
  while((lin=br.readLine())!=null){
    //Put the content read into the buffer pointed by the parameter "con"
    con.append(lin).append("\n");
  }
  //The caller already have the content, because he created the buffer, but I'll return the string anyway
  return con.toString();
}


简单一些了吧,对吗?现在你读着代码中的注释,并且也理解了它,但是代码仍然是不好看。

这种类型的注释就是我在现在谈论的。注释你的源代码表明你是一个非常糟糕的程序员(一个小例外就是遇到不能将代码分解成小片断的很复杂的算法)。

当你在注释你的代码,你实际上是在用一种HACK的方式向他人掩饰你所做的不合格。这表明了你不会写干净的代码。不会写让其他程序员可读的代码!

现在我就就上面写的代码,来重构一下其中的难读的方法。


public String readFileContents(File fileToRead) {
  boolean canReadFile = fileToRead.exists();
  if(!canReadFile)
    return "";
  StringBuilder buffer = new StringBuilder();
  BufferedReader readerForFile = openBufferedReaderForFile(fileToRead);
  readFileContetIntoBuffer(buffer,readerForFile);
  closeFileReader(readerForFile);
  return buffer.toString();
}
private  BufferedReader openBufferedReaderForFile(File fileToRead){
  return new BufferedReader(new FileReader(fileToRead));
}
private void readFileContetIntoBuffer(buffer,readerForFile){
  String line;
  while((line=readerForFile.readLine())!=null){
    buffer.append(line).append("\n");
  }
}
private void closeFileReader(readerForFile){
  readerForFile.close();
}

现在,你注意一下名为readFileContents的方法,你已经知道了它是干什么的,另外,方法的代码很容易理解的,如下面意思所表明的意思:

引用

如果不能读文件,返回null,
为名为fileToRead的File打开Buffered Reader,
将文件的内容读到缓存中去,关闭File Reader readerForFile,
返回buffer.toString();


我所表达的说明了:如果你懂英语,你就能读懂代码,而几乎每个程序员都知道英语,对吗?(我注:当然非英语国家...)

我曾看到有人写了如下的很糟糕的代码,如同下面这个样子:

public String write(StringBuilder fle, StringBuffer con) {
  File f = new File(fle.toString()); FileReader fr = new FileReader(f);  BufferedReader br = new BufferedReader(fr);
String lin; while((lin=br.readLine())!=null){  con.append(lin).append("\n");  }
  return con.toString();
}


这个比我的版本的行数少,但是你要上一段困难的时间试图弄懂这个糟糕的程序员写出的如上的代码片断。

当然,我使用的这个例子非常简单,并且我知道写出清析易读的代码是需要实践的...

但是我给你一个提议,不是一个真正的提议,是一个练习而已...

我写了一个如下的代码示例,你试着将它变成可读的。我会在一两天后贴出我的解决方案。

你们可以直接在文章回复中贴出你们的重构代码。


package blog;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
 
public class VeryBadlyNamedFile {
	private static final char[] asdfg = new char[] {'I', ' ', 'c', 'a', 'n', ' ', 'd', 'o', ' ', 'v', 'e', 'r', 'y', ' ', 'u', 'g', 'l', 'y', ' ', 'c', 'o', 'd', 'e'};
	private String an;
	private BufferedReader rfsdw;
	private FileReader temp;
 
	public VeryBadlyNamedFile(String an, BufferedReader rfsdw, FileReader temp) {
		super();
		this.an = an;
		this.rfsdw = rfsdw;
		this.temp = temp;
	}
 
	public void doIt() throws IOException {
		ctfiidne();
		startDoing();
		try {
			canIDoAnyThing();
		} catch (RuntimeException yicdet) {
			nowReallyDoIt();
		}
	}
 
	private void nowReallyDoIt() {
		firstDoTheOtherThing();
		reallyDoItInternal();
	}
 
	private void firstDoTheOtherThing() {
		rfsdw = new BufferedReader(temp);
	}
 
	private void reallyDoItInternal() {
		while (true) {
			try {
				imDoingIt();
			} catch (Exception e) {
				break;
			}
		}
	}
 
	private void imDoingIt() throws Exception {
		String s = rfsdw.readLine();
		if (s == null)
			throw new Exception("hahaha, I bet you did not understood the code");
		System.out.println(s);
	}
 
	private void ctfiidne() throws IOException {
		File a = new File(an);
		if (!a.exists()) {
			FileWriter wrfedsd = new FileWriter(a);
			wrfedsd.write(asdfg);
			wrfedsd.close();
		}
	}
 
	private void canIDoAnyThing() {
		if (new File(an).exists() && new File(an).canRead() && new File(an).canWrite())
			throw new RuntimeException();
	}
 
	private void startDoing() throws FileNotFoundException {
		File f = new File(an);
		temp = new FileReader(f);
	}
}


现在用一个主程序执行上面的代码:

package blog;
 
import java.io.IOException;
 
public class Main {
	public static void main(String[] args) throws IOException {
		new VeryBadlyNamedFile("c:\\anyFile.any",null,null).doIt();
	}
}


以上的这些例子用的是Java代码,但是本观点适用于任意语言,如果你编程,并且用注释来解释你的代码,那么你是一个可怕的程序员。


快点祈祷上帝的帮助,乞求下一个读了你废话般的代码的的人不是一个知道你住处的连环杀手!

PS.:我真的不认为你不应该注释你的代码,但是 如果你的代码如果没有注释就理解不了,那表明你还不会写程序。

PS2.: 我觉得我应该来些更好的例子。

PS3.: 写出好代码的秘诀就是你写代码即使你知道下一个阅读你代码的人是一个连环杀手,并且知道你住在哪儿。(个人理解就是我们时刻要记住写出的代码是要给人家看的)


------我的分割线------
在现实生活中,我常常遇到还没有达到如作者说的那样
public String write(StringBuilder fle, StringBuffer con) {
  File f = new File(fle.toString()); FileReader fr = new FileReader(f);  BufferedReader br = new BufferedReader(fr);
String lin; while((lin=br.readLine())!=null){  con.append(lin).append("\n");  }
  return con.toString();
}

命名的级别的程序员,变量名完全是一时想到个什么字母单词之类的就敲出的,并且连注释也不写!这样人,阅读了他代码的连环杀手一定会让他死得很难看!

感觉写Ruby代码更是要如此,比如@posts表示你取出来的是一个文章列表,但是我的旁边的那个同事就不注意这些细节,他用@post(他英语不好,但是我觉得是他赖得去理这些)

还有一次是大家一起做一个rails项目,另一个同事做好了他那一块,我要接着在他做的页面中加一个功能,我看他页面中有一个@user,我看正合我用,就直接用,却出错了,找错误花了我好一些时间,原来@user实际上Company类型的,他为什么不直接用@company啊?现在我要用user,是@user.user,你们说,这代码看着像个什么啊? ORZ,他为什么这样写的,因为他做的那个功能叫搜索用户,在页面上显示的是用户的公司。ORZ,我是无语了。

说实话,用rails做项目,我出的错好多都是因为成员们命名不规范导致的,找到这些错误后,很无语...
3
3
分享到:
评论
10 楼 Scriptlet 2009-01-05  
不要非黑即白。
实践中当然要尽量使用有意义的类,变量和方法名称。同时加上一定的说明会显得更有条例。
假设你的论点成立“注视源代码表明你写的代码还不好“,但是”不注释源代码也不能表明你写的代码很好“。
9 楼 xuyao 2008-12-02  
估计你没看过jdk源代码
8 楼 liuqiang 2008-11-25  
犯了原则性的错误,代码注释是必须的,除非你用纯DSL
7 楼 acnono 2008-11-25  
项目大一点  是没有精力让你去读一行一行的代码的。面向对象的思想跟注释代码也有差不多的地方,每个人负责不同的地方,我拿过来你做的部分,我只需要知道它是干什么的,然后用它,没必要去根究它是怎么干事情的。  注释是必须的,读别人代码就会知道。
6 楼 ddandyy 2008-11-25  
再糟糕不过的逻辑.......

想当然的看问题.........
5 楼 elstage 2008-11-25  
如果是一些简单的代码,你写的好,当然可以不加注释。如果是一些复杂的或者难懂的,你还能指望别人光看代码能看明白吗?举个极端的例子,jdk的源程序,如果没有api文档,难道你去理解源程序?
4 楼 funcreal 2008-11-24  
基本的DRY原则。
Don't Repeat Yourself。
代码和注释是一种重复。容易造成以后改了代码而不改注释的问题。
我还见过更疯狂的观点,认为文档和代码也是一种重复,从某些角度来讲,是很有道理的。
3 楼 puroc 2008-11-24  
是的,你说的对。干净漂亮的代码,不是一下子就写出来的吧。项目紧急,人员紧缺的情况下,进度是不允许我对每行代码都斟酌再斟酌的。逻辑稍微复杂点的代码就先写个注释,以免以后重构的时候看不懂。 我为啥说欲言又止呢,我是感觉你说的有道理,但同时我也感觉,加点注释也没啥不好的。
2 楼 qichunren 2008-11-24  
puroc 写道

看完之后,有种欲言又止的感觉。说的有点儿道理。但我还是会在难于理解的地方加点注释。以免以后自己都看不懂。

你有这种感觉:怕自己看不懂
你对自己写的代码都有这种感觉,别说让其他人来看你写的代码了。
所以还是要努力,最起码的一条:可以让变量等富有语义,这点不是很难吧。
1 楼 puroc 2008-11-24  
看完之后,有种欲言又止的感觉。说的有点儿道理。但我还是会在难于理解的地方加点注释。以免以后自己都看不懂。

相关推荐

Global site tag (gtag.js) - Google Analytics