五种应该避免的代码注释

五种应该避免的代码注释

在酷壳,有很多文章都提到了代码注释,如:《十条不错的编程观点》、《优质代码的十诫》、《整洁代码的4个提示》、《惹恼程序员的十件事》等等。今天,某国外的程序员在这里列举五种应该避免的程序注释,我觉得比较有道理,但我觉得有少数几个观点也并不绝对。所以,我把原文的这五种应该避免的程序注释罗列在下面,并放上原作者和我的个人观点作为比较。希望对大家有用。

一、自恋型注释

(注:原文为Proud,我觉得“自恋”更好一点)

public class Program
{
    static void Main(string[] args)
    {
        string message = "Hello World!";  // 07/24/2010 Bob
        Console.WriteLine(message); // 07/24/2010 Bob
        message = "I am so proud of this code!"; // 07/24/2010 Bob
        Console.WriteLine(message); // 07/24/2010 Bob
    }
}

原文:这样的程序员对于自己的代码改动非常骄傲和自恋,所以,他觉得需在在这些自己的代码上标上自己的名字。其实,一个版本控制工具(如:CVS或Subversion)可以完整地记录下所有的关于代码的改动的和作者相关的一切信息,只不过不是那么明显罢了。

陈皓:我同意原文的观点。在我的团队里也有这样的事情发生。有段时间我认真思考过这样的事情,是否应该把这样的事情在代码中铲除出去。后来,我觉得,允许这样的行为并不一定是坏事,因为两点:

  1. 调动程序员下属的积极性可能更为重要。即然,这种方式可以让程序员有骄傲的感觉,能在写代码中找到成就感,为什么要阻止呢?又不是什么大问题。
  2. 调动程序员的负责任的态度。程序员敢把自己的名字放在代码里,说明他对这些代码的信心,是想向大家展示其才能。所以,他当然知道,如果这段他加入的代码有问题的话,他的声誉必然受到损失,所以,他敢这么干,也就表明他敢于对自己的代码全面的负责。这不正是我们所需要的?!

所以,基于上述考虑,我个人认为,从代码的技术角度上来说,这样的注释很不好。但从团队的激励和管理上来说,这样的方式可能也挺好的。所以,我并不阻止也不鼓励这样的注释。关键在于其是否能有更好的结果。

二、废弃代码的注释

public class Program
{
    static void Main(string[] args)
    {
        /* This block of code is no longer needed
         * because we found out that Y2K was a hoax
         * and our systems did not roll over to 1/1/1900 */
        //DateTime today = DateTime.Today;
        //if (today == new DateTime(1900, 1, 1))
        //{
        //    today = today.AddYears(100);
        //    string message = "The date has been fixed for Y2K.";
        //    Console.WriteLine(message);
        //}
    }
}

原文:如果某段代码不再使用了,那就应该直接删除。我们不应该使用注释来标准废弃的代码。同样,我们有版本控制工具来管理我们的源代码,在版本控制工具里,是不可能有代码能被真正的物理删除的。所以,你总是可以从以前的版本上找回你的代码的。

陈皓:我非常同意这样的观点。只要你是废弃的,就应该是删除,而不是注释掉。注释并不是用来删除代码的。也许你会争论到,在迭代开发中,你觉得被注释的代码很有可能在未来会被使用,但现在因为种种问题暂时用不到,所以,你先注释着,然后等到某一天再enable它。所以你注释掉一些未来会有的程序。在这样的情况,你可以注释掉这段代码,但你要明白,这段代码不是“废弃”的,而是“临时”不用的。所以,我在这里提醒你,请不要教条式地在你的程序源码中杜绝这样的注释形式,是否“废弃”是其关键。

三、明显的注释

public class Program
{
    static void Main(string[] args)
    {
        /* This is a for loop that prints the
         * words "I Rule!" to the console screen
         * 1 million times, each on its own line. It
         * accomplishes this by starting at 0 and
         * incrementing by 1. If the value of the
         * counter equals 1 million the for loop
         * stops executing.*/
        for (int i = 0; i < 1000000; i++)
        {
            Console.WriteLine("I Rule!");
        }
    }
}

原文:看看上面的例子,代码比注释还容易读。是的,大家都是程序员,对于一些简单的,显而易见的程序逻辑,不需要注释的。而且,你不需要在你的注释中教别人怎么编程,你这是在浪费时间去解释那些显而易见的东西。你应该用注释去解释你的代码功能,原因,想法,而不是代码本身。

陈皓:非常同意。最理解的情况是你的代码写得直接易读,代码本身就是自解释的,根本不需要注释。这是最高境界。注释应该说明下面的代码主要完成什么样的功能,为什么需要他,其主要算法怎么设计的,等等。而不是解释代码是怎么工作的。这点很多新手程序员都做得不够好。别外,我需要指出的是,代码注释不宜过多,如果太多的话,你应该去写文档,而不是写注释了。

四、故事型注释

public class Program
{
    static void Main(string[] args)
    {
       /* I discussed with Jim from Sales over coffee
        * at the Starbucks on main street one day and he
        * told me that Sales Reps receive commission
        * based upon the following structure.
        * Friday: 25%
        * Wednesday: 15%
        * All Other Days: 5%
        * Did I mention that I ordered the Caramel Latte with
        * a double shot of Espresso?
       */
        double price = 5.00;
        double commissionRate;
        double commission;
        if (DateTime.Today.DayOfWeek == DayOfWeek.Friday)
        {
            commissionRate = .25;
        }
        else if (DateTime.Today.DayOfWeek == DayOfWeek.Wednesday)
        {
            commissionRate = .15;
        }
        else
        {
            commissionRate = .05;
        }
        commission = price * commissionRate;
    }
}

原文:如果你不得不在你的代码注释中提及需求,那也不应该提及人名。在上面的示例中,好像程序想要告诉其它程序员,下面那些代码的典故来自销售部的Jim,如果有不懂的,你可以去问他。其实,这根本没有必要在注释中提到一些和代码不相干的事。

陈皓:太同意了。这里仅仅是代码,不要在代码中掺入别的和代码不相干的事。这里你也许会有以下的争辩:

  1. 有时候,那些所谓的“高手”逼着我这么干,所以,我要把他的名字放在这里让所有人看看他有多SB。
  2. 有时候,我对需求并不了解,我们应该放一个联系人在在这里,以便你可以去询问之。

对于第一点,我觉得这是一种情绪化。如果你的上级提出一些很SB的想法,我觉得你应该做的是努力去和他沟通,说明你的想法。如果这样都不行的话,你应该让你的经理或是那个高手很正式地把他的想法和方案写在文档里或是电子邮件里,然后,你去执行。这样,当出现问题的时候,你可以用他的文档和邮件作为你的免责证据,而不是在代码里干这些事。

对于第二点,这些需求的联系人应该是在需求文档中,如果有人有一天给你提了一个需求,你应该把其写在你的需求文档中,而不是你的代码里。要学会使用流程来管理你的工作,而不是用注释。

最后,关于故事型的注释,我需要指出也有例外的情况,我们团队中有人写注释喜欢在注释或文档里写一些名人名言(如 22条经典的编程引言编程引言补充Linus Torvalds 语录 Top 10 ),甚至写一些小笑话,幽默的短句。我并不鼓励这么做,但如果这样有利于培养团队文化,有利于让大家对工作更感兴趣,有利于大家在一种轻松愉快的环境下读/写代码,那不也是挺好的事吗?

另外,做为一个管理者,有时候我们应该去看看程序员的注释,因为那里面可能会有程序员最直实的想法和情绪(程序员嘴最脏??)。了解了他们的想法有利于你的管理。

五、“TODO”注释

public class Program
{
    static void Main(string[] args)
    {
       //TODO: I need to fix this someday – 07/24/1995 Bob
       /* I know this error message is hard coded and
        * I am relying on a Contains function, but
        * someday I will make this code print a
        * meaningful error message and exit gracefully.
        * I just don’t have the time right now.
       */
       string message = "An error has occurred";
       if(message.Contains("error"))
       {
           throw new Exception(message);
       }
    }
}

原文:当你在初始化一个项目的时候,TODO注释是非常有用的。但是,如果这样的注释在你的产品源码中出现了N多年,那就有问题了。如果有BUG要被fix,那就Fix吧,没有必要整一个TODO。

陈皓:是的,TODO是一个好的标志仅当存在于还未release的项目中,如果你的软件产品都release了,你的代码里还有TODO,这个就不对了。也许你会争辩说,那是你下一个版本要干的事。OK,那你应该使用项目管理,或是需求管理来管理你下一个版本要干的事,而不是使用代码注释。通常,在项目release的前夕,你应该走查一下你代码中的TODO标志,并且做出决定,是马上做,还是以后做。如果是以后做,那么,你应该使用项目管理或需求管理的流程。

上述是你应该避免使用的注释,以及我个人的一些观点,也欢迎你留下你的观点!

(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)

好烂啊有点差凑合看看还不错很精彩 (28 人打了分,平均分: 4.14 )
Loading...

五种应该避免的代码注释》的相关评论

  1. 说说我的经验:
    1.尽量用命名取代注释
    例如:
    void Buf::fun(){
    ….
    if( m_data2Send.size() > 0 && m_lastSent >= m_lastWant2Send ){ // if NEED send && COULD send
    send …
    }
    ….
    }
    可以改成这样而去掉注释同时不降低可读性:
    void Buf::fun(){
    ….
    const bool needSend= m_data2Send.size() > 0;
    const bool couldSend= m_lastSent >= m_lastWant2Send;
    if( needSend && couldSend ){
    send …
    }
    ….
    }
    虽然这两个变量只被用到了一次,因此从复用角度看是不必要的,但是由于它们把原来用注释承载的信息直接融合进了代码里,所以会提高可维护性,特别是当别人在这个if里加入新的条件且没有添加注释时,可以很容易地把新条件和那两个原有条件分辨开来。
    2.如果你发现一个东西很难取名而且需要添加注释时,重新思考这个东西是否包含了太多在概念上并不统一的东西。
    3.对于代码段,如果一段代码只被用到了一次(目前还没出现复用的需要),并且你并不确定近期是否及会怎样进行复用,并且在概念上这段代码没有明显的边界,那么最好不要把它变成函数,因为现在封装时确定的边界未必符合日后的需要。但是为了代码上的清晰,可以用花括号对把这段代码括起来,并加上注释:
    void fun()
    {
    ….
    { // do something
    }
    ….
    }
    内层的那对花括号内的部分应该看作一个微观模块:在概念上是相对独立并且统一于某个概念(即有单一的目标或功能),但是在物理上并没有成为一个可复用的模块(连函数都不是),而左花括号后面的那个注释应该当作模块命名来写,所以应该写尽量短小精悍的短语。
    日后如果发现那里的代码需要复用,那么可以把那段代码提取出来封装为函数,编译时提示未定义的变量即为该函数的参数。当然,如果你发现这个函数需要太多的参数,那么说明耦合太高。

  2. 第一条不太同意陈皓同学的观点,我们曾经有一个同事,水平很烂,几乎没有责任心,却爱在加入各种有用或无用的代码的同时还很装B地加上“added by XXX for _some-reason_”。所以,自恋还可以说得通,但“成就感”、“负责任”这些,恐怕是陈同学一厢情愿了,没见过素质低的,是想象不出能有多低。。。

  3. @sjinny
    谢谢你的分享,很有帮助。

    @islet8
    任何事情都有好都有不好,你我对待些事的差别在于,你看到了在注释中写上自己的名字是自恋和素质低,而我看到了积极的一面,如愿意负责,有Ownership。这就是一个简单的注释,也差不到哪里去,用“低素质”来评价这种行为有点言重了。

    让我们想一想,谁能用自己的真实名字在网上发表言论,能这样做的人一般都有两种情况:1)想展示自己的才华,2)对自己的言行高度负责,3)愿意接受大家的批评。对于有这样心态的程序员,我以为应该鼓励。而不是用“低素质”来给人做定性。

    谢谢你们对本站的关注。

  4. @陈皓
    嗯,我不是否定你的观点,的确就大部分情况来说,你的观点比较符合,但极端环境下,因为正好我身边存在过这样“低素质”的同事,就像你的例子里实名留言的可能大部分是你说的三种情况,但也不排除存在无脑的人根本就没想过实名的意义,就随便留名了。
    另外,可能是个人喜好问题了,我不太喜欢代码里到处有各个同事的名字,就好比王羲之刻一块石碑可以流芳百世,但其他一群人也把自己的名字或字体追加刻上去,就毁了。

  5. 第一种注释以前经常写,以前在一个小公司,最初所有的源码都需要人肉管控,写上名字之后如果有地方不明白,或是代码有误之后很容易就可以找到做原作者。
    后来搭建了svn之后,就不需要这么干了,不过依然有人习惯加上自己的名字

  6. @陈皓
    第一条说的是不是那个人“过度自恋”,以至于每条语句都加上自己名称的注释啊?
    按照我们部门的做法,借助IDE其实有统一的“注释模板”,只有在创建类和给方法加注释的时候,自动生成作者的名字。
    这样应该是考虑便于维护和责任明确,到代码检查和bug统计,或者工作交接的时候更能有的放矢而已。同时也会防止楼上同学说的那样的“烂人”处处“到此一游”的情况出现吧。

  7. 我觉得有时候所谓的“自恋型”注释很有必要。。尤其是在后期维护过程中多个程序员修改同一文件时。。至少不明白的时候可以问哪一位改的代码吧。。

  8. @islet8
    如果你那位同事没有写写自己的名字,也许你还不知道他水平有多烂呢。而且他水平那么烂,你们也可以帮助他提高,或者起码让他知道自己的代码烂。

  9. 个人觉得,如果写上自己的名字,还是很有成就感的,只是一个文件在一个地方写就可以了
    如果是在别人的基础上面改,在svn中留名就好了

    注释的目的是为了维护,别给它加太多的含义

  10. 我说几句呵,我在修改一些现成的代码时,会不自觉的加上 “by jimmy” 字样。意图,只是为了哪天翻看代码时,知道这块是自己对某处擅作了改动。自恋、负责 这些当时都没想到。就是拿来提个醒了

  11. 个人感觉第一种还是可以接受的。因为可以查到什么时间谁动了代码,好坏都可以找到负责人。。。。囧。。虽然希望好的事情多余坏的。。。特别是一些客户拿到code以后他可以很快的去对比merge code。。而且。。。可以看到那些代理人吧你的code给了谁。。。额。。

  12. 第一种我觉的挺好的,毕竟做一个项目,大家都想在里面留下点什么
    第五种的TODO,我觉得有时候也蛮有必要的,比如一个长期开发和维护的项目,一个暂时没能FIX但是有更紧急的任务之类的

  13. 我强烈反对第一种。
    在我的编程经验里,也时常见到这种自我感觉良好的注释。但毫无例外的,它们总是大量出现在公司里那些陈年老项目的烂代码里,由某些个早已离职的程序员留下。那些代码面目可憎,维护起来没有成就感可言,如果你感觉它们问题很多,也只能对着那些陌生的名字生闷气。因为他们除了名字,如果还留有其它注释,那一定是为了误导你。

  14. 第一条许多人提及用svn等版本控制来防止“到此一游”的做法。
    但实际上真正找bug时,很少有人会细查svn,更多的是直接去群里吼:谁改的?赶紧出来解释解释。
    为啥?原因是看那些修改日志可能要牵涉数个改动——而这数个改动可能甚至是跨了100个commit的。
    所以对第一点持保留意见

  15. @HorseLuke
    不用看那么多commit,svn有个功能叫blame,可以很方便的查到某一行是谁,在哪个revision中贡献的~
    我个人讨厌第一类注释~

  16. 一、自恋型注释
    我们之前的项目要求只要改动代码就要写上邮件地址和名称,因为从svn中找出这段代码的更改者还不如从代码中直接看的方便~~

  17. string message = “Hello World!”; // 07/24/2010 Bob
    Console.WriteLine(message); // 07/24/2010 Bob
    message = “I am so proud of this code!”; // 07/24/2010 Bob
    Console.WriteLine(message); // 07/24/2010 Bob

    每行都加。。,领教了

  18. 有时候对于接手别人的代码,并进行修改时,第一类注释是很有帮助的。很多修改并没有相应文档,特别是修改已运行的代码,更是找到问题就直接改了。这类注释应有修改的理由和修改人或修改日期,会很方便后来人知道修改的原因。 当然这是不好的习惯, 应该适度。

  19. 接手别人的代码的时候,他们都没有用版本控制之类的工具,所以经常可以看到第一类注释,XXX年月日XXX修改了这段代码

  20. @islet8

    @陈皓
    我是写java和js的,我在前一家公司工作的时候,我们习惯在方法级注释,或者代码更改时加入名字,目的并非为了炫耀(至少我不是),而是为了当有人需要动这段程序时,如有问题,可以找到前一任编写者询问注意事项。实践表明确实有效,有些程序相对复杂且调用地很多,若需要调用该部分,或重构该部分,需要咨询一下免得出现问题。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注