有什么比花时间写注释更令人感到兴奋的事情吗?如果我没有猜错,你可能会说:“不好意思,所有事情都比写注释更令人感到兴奋”。如果有人要你给代码加上注释,对你来说就像是一种侮辱。你的代码写得如此优雅,它已经足以说明它要做的事情,注释是多余的,代码就是一切。

无论是开源项目还是专业软件开发,代码注释通常有两种形式:要么没有和要么毫无用处。任何领域或使用任何编程语言的程序员,无论他们来自世界的哪个地方,似乎都不喜欢给代码写注释。如果你想讲故事,可能会选择不同的人生道路(比如去当作家?)。

这种不情愿甚至形成了某种范式和哲学观点,认为代码注释实际上是有害的,任何试图逃避它的人现在都可以愉快地重新讨论这些主张。但是,稍微夸张一点说,我们实际上是在用这种方式破坏信息。虽然代码注释有时候确实会适得其反,但真正有害的是我们对它的看法。

说到底,代码注释就像是错误处理,我们很早就被告知它很重要,但却无法理解其中的原因。我们越来越厌烦为同样的老师、主管或烦人的队友做这件事。但就像错误处理一样,如果做得好,我们就是从中获益最多的人。但要做到这一点,我们需要面对一些严酷的事实,并承认根本不存在所谓的自解释代码。

所以,让我们来戳破其中的一些泡沫吧!

自解释的代码是不存在的

反对给代码写注释的人认为,“代码应该好到不需要任何多余的解释”。好的代码确实不需要注释来描述变量或函数是干什么用的。

// bad start:int a = 4 * OFFSET;// but don't use a comment to tell what it does:int a = 4 * OFFSET; // initial foo value// instead choose a name telling it itself:int initial_foo = 4 * OFFSET;

确实,有意义的变量名根本不需要注释,但这实际上更像是一种体面的编码风格,而不是文档。当这种片面的观点变成反对使用代码注释的普遍理由时,问题就出现了。

问题是,即使变量、方法、类、函数、模块的名称是自解释的,但这些并不能描述出代码的全局面貌,也不一定能说明各部分代码为什么要那么写。当然,清晰的实现往往会让我们产生一种错觉,认为不需要再写注释了。当你花了几个小时甚至几天时间解决了手头的问题,那些代码在当下可能是完美的,然后你把它们打包、提交。

但是一个月后会怎样?你能记住多少细节?它们还是那么有意义吗?

软件开发困难重重

当然,有人可能会争辩说:“代码就在那里,你看一下就明白了”。如果我们说的是某块代码是干什么用的,那么或许这么说是有道理的。但对于任何超出这个范围的东西,深挖代码可能是在浪费时间,就像在阅读一本没有索引的书,你要从头读起,才可能找到你需要的东西。

而且,这不仅仅是为了了解别人的代码,或者向别人解释你的想法。当你重新查看旧代码或者修复错误时,你的脑子里是不是经常犯嘀咕,或者因为 git blame 显示了你的名字而感到惊讶?然而,再往后,它们可能被忘得一干二净,然后你会再次相信一切都应该是自解释的,所有的细节都应该是明确无误的。

无论你怎么努力,软件本身并不会完全自解释。这既不是你的错,我也不是想要质疑你的能力,这与人类本身有关,我们低估了软件的复杂性,而且人类的思维具有波动性。注释的目的不是为了指出代码中存在的缺陷,而是为了抵制编程语言本身存在的缺点。即使是最干净的代码也不可能自己解释写代码的人在写代码时在想些什么。有可能一切都是完美的,但仍然会出错。注释并不是干净代码的替代方法,而是代码的固有组成部分。

代码注释解析

在进一步讨论我们的问题之前,先让我们来看看不同的代码注释风格。

/*** Javadoc-style documentation comment.*/void foo(void) {if (bar \u0026gt; 10) {/* regular comment */...}}

常规注释就是编程语言本身定义的注释。根据经验,它们不应该被广泛使用,因为它们倾向于用来解释代码在做什么。

另一方面,文档注释从外部角度描述了全局变量、函数和模块。在函数体内部,它们基本上就是常规注释,工具通常会忽略它们。如果在函数内部有一些值得描述的东西,看看是否可以把它们放进函数描述本身。

文档注释本质上就是常规注释加上一些额外的附件,例如额外的正斜杠/// doc comment、感叹号//! doc comment或者/*! multiline doc comment /,或者Javadoc注释中的附加星号/* doc comment */。实际上,其他编程语言和工具也支持Javadoc,所以这里就以它为例子。

当然,你也可以使用常规注释,并忘掉那些时髦的标签。不过,一些文档生成器(如 Doxygen 或 Sphinx)可以直接根据注释创建 PDF、HTML 或手册页,大多数现代 IDE 为它们提供了额外的显示支持,省得你老是进行上下文切换,而且还可以为你提供一些有用的信息。

除了注释的后处理之外,注释的格式并不重要,重要的是你想要表达什么。

冗余的注释聚焦在错误的信息上

我们已经得出结论,即不应该记录代码在做什么,而是记录为什么要这么做以及怎样做,但这究竟意味着什么呢?

人们不喜欢写注释的一个常见原因是“它们只是在陈述已经很明显的东西”,所以注释是多余的。对于一般性的注释,确实难以反驳,特别是在面向对象语言的封装方面。一些简单的函数,比如 get_temperature() 的一般性描述可能如下所示:

/*** Returns the temperature.*/int get_temperature(void) {return temperature;}

这里的注释确实没有增加太多的价值,它本质上只是重复了函数的名字,只是在说明这个函数的作用。这不是我们想要的,我们想要的是代码没有告诉我们的东西。

这个函数非常简单,所以写注释是绝对没有必要的。但话又说回来,软件开发当中没有什么东西是真正简单的。如果你够仔细,就会发现每个函数都有值得写的东西,而这些东西并不能从它的名字甚至是简单的一两行代码中看出来。

/*** Returns the temperature in tenth degrees Celsius* in range [0..1000], or -1 in case of an error.** The temperature itself is set in the periodically* executed read_temperature() function.** Make sure to call init_adc() before calling this* function here, or you will get undefined data.*/int get_temperature(void) {return temperature;}

事实证明,这个看似简单的函数有很多额外的信息可以写。如果只是看代码,可能无法明显地看出其中的信息,包括内部数据处理和程序流程。当然,深挖代码最终会获得同样的信息,但这样会浪费很多时间和脑力。

有人可能会说,我们没办法为这些实现细节写注释。为什么要这样?为什么不详细说明那些现细节,让别人可以更容易地理解代码在做什么?

每个函数都有自己的特点,至少会有一个细节、副作用、异常、限制,等等,它们都值得写出来,这意味着你可能需要从不同的角度来看待这个函数,才能找出它们。为此,你不可避免地要沉浸在代码隐藏的细节当中,这样才可能发现一些之前没有想到过的特殊情况。因此,代码注释不仅可以帮助读代码的人理解代码,还能帮助写代码的人更好地了解代码的内部细节。

如果你确实找不到有用的信息,那么应该问问自己为什么要写这些代码。这些代码存在的理由是什么?而这些理由就是有用的信息。之前的例子也可以是这样:

/*** Returns the temperature.** This is for testing purpose only and should* never be called from a real program.*/int get_temperature(void) {return temperature;}

请注意,这段代码与之前完全相同,于是这又把我们引向了另一个问题“看似自解释的代码的注释通常都很简单”:它可能含糊不清,可能会导致错误的假设和潜在的缺陷。指出这些细节并消除潜在的歧义对于提升代码质量来说至关重要,这说明注释应该成为代码的重要组成部分。

同样,如果不深入研究代码,就无法发现每个函数的特点。当然,在这些不起眼的细节中,总有一些比另外一些更值得我们注意,并不是说函数所涉及的东西都会很有趣。认知偏差的范围很广,有些东西在这个时刻对你来说是显而易见的,并不意味着对于其他人来说也是这样——包括未来的你。

让注释成为代码的一部分

现在我们来看看另一个人们不喜欢写代码注释的原因:当代码发生改变时,注释会过时。但其实这只是一个偷懒的借口,在写代码时通常不会考虑将来会不会再去修改代码,一旦代码被提交并合并,就是确定和完美的,并永远保持原样。

代码注释的另一个更大的问题是,它们被视为独立于代码的东西,完全与代码相分离。但如果我们将其视为代码的组成部分,或者一种补充实体,那么只要代码发生变化就会很自然地去调整注释。

打破恶性循环

没有人喜欢糟糕的代码注释,但排斥写注释对解决这个问题并没有任何帮助。修复开发人员和代码注释之间的不正常关系是改善这种状况的唯一方法,而将注释视为代码的组成部分是改善这种关系的第一步。

毫无疑问,在形成这种思维方式之前需要进行练习。从长远来看,这对提升代码质量来说是有益而无害的。

英文原文:

https://hackaday.com/2019/03/05/good-code-documents-itself-and-other-hilarious-jokes-you-shouldnt-tell-yourself/

代码自解释不是不写注释的理由相关推荐

  1. 自解释的代码根本不存在,老老实实写注释吧

    作者 | Sven Gregori 译者 | 薛命灯 有什么比花时间写注释更令人感到兴奋的事情吗?如果我没有猜错,你可能会说:"不好意思,所有事情都比写注释更令人感到兴奋".如果有 ...

  2. 我的代码很好,不需要写注释

    作者 | Sheetal 译者 | 弯月 责编 | 王晓曼 有时候,我们会写一些非常有创意的注释,而有些注释确实让人不得不佩服 程序员的想象力.看到下面这些注释,相信每个人都会捧腹大笑. [1] #想 ...

  3. 优秀的程序员真的不写注释吗? | 原力计划

    作者 | 沉默王二 责编 | 王晓曼 出品 | CSDN博客 前言 我在很多地方看到这样一个观点,"请停止写注释,因为只有烂的代码才需要注释."这个观点非常巧妙,它让我想起了孟子的 ...

  4. python如何注释一段代码_Python 中如何写注释

    在写 Python 代码的时候,一个很好的编码实践就是使得你的代码简洁,易懂.组织代码,设置变量,以及给函数有意义的名字,都是几个不错的方法. 另外一个提高代码可读性的方式就是使用注释.一个注释就是可 ...

  5. 反思代码能力提升点:foreach循环层数;命名契合;分块写;写注释;分步骤;多沟通

    1.foreach循环 最好不要超过四层  超过四层之后  之后再看容易看晕 分开写循环   尽可能的简化  扩展性也好一些 2.命名一定要考虑好  还是很重要的  最好名字的意思与其他的变量能够立马 ...

  6. 吴恩达机器学习 神经网络 作业1(用已经求好的权重进行手写数字分类) Python实现 代码详细解释

    整个项目的github:https://github.com/RobinLuoNanjing/MachineLearning_Ng_Python 里面可以下载进行代码实现的数据集 题目介绍: In t ...

  7. 吴恩达机器学习 逻辑回归 作业3(手写数字分类) Python实现 代码详细解释

    整个项目的github:https://github.com/RobinLuoNanjing/MachineLearning_Ng_Python 里面可以下载进行代码实现的数据集 题目介绍: In t ...

  8. 程序员写代码要写注释吗?写你就输了

    前言:在职业发展道路上,需要不断提升自己,需要学习资源的,一起学习交流的欢迎加群[443128517],小编准备了学习视频,学习线路,自学书籍,职业发展视频.也可以加美女老师七七的微信.二维码放在下面 ...

  9. “穷X”事件程序员致歉:以后老实写代码,正紧写注释

    (点击上方公众号,可快速关注) 转自:新浪科技 tech.sina.com.cn/i/2017-11-20/doc-ifynwnty5776053.shtml 新浪科技讯  19日晚间,技术论坛出现了 ...

最新文章

  1. 水晶报表弹出用户密码输入框问题的解决
  2. clion 查看内容窗口_CLion精华笔记
  3. 天池实验室Python能力测验
  4. MyEclipse/Eclipse中properties文件中文乱码问题解决
  5. Android之UI线程与子线程交互设计的5种方法
  6. LeetCode 网易-1. 分割环(前缀和 + 哈希)
  7. 【读书笔记】非暴力沟通
  8. Git 提交错了不用慌,这三招帮你修改记录
  9. 机器人水下赌场争霸战!中国团队创造历史,在美国登顶世界第一
  10. 游戏开发之C++多继承及虚继承(C++基础)
  11. spark streaming之 windowDuration、slideDuration、batchDuration​
  12. 机器人方队解说词_创想机器人博物馆介绍配音解说词
  13. Scratch二次开发6:如何保存作品到自己的服务器
  14. 计算机ppt听课记录,怎样做好听课记录.ppt
  15. 简单三步搭建电影网站 :安装MacCMS10 1-3
  16. 小米摄像头 rtmp_如何使用外部摄像头进行Amazon Live
  17. python instagram 爬虫
  18. chr python用法_使用Python内建chr, ord实现的简单的加/解密
  19. Property ‘validationMessageSource‘ threw exception
  20. 录音实时转写软件哪个好?这三个软件帮你搞定录音如何转文字

热门文章

  1. 网页制作代码模板_科普:关于网页设计的4个基础小知识
  2. 阿里云服务器ECS按ctrl+alt+delete无法登录
  3. PING检查网络是否畅通
  4. Android develop 国际化
  5. 【随笔】Win7下GVIM的安装与配置
  6. 全国计算机等级考试题库二级C操作题100套(第74套)
  7. 卷积核和全连接层的区别_「动手学计算机视觉」第十六讲:卷积神经网络之AlexNet...
  8. 等压线上怎么画风向_战场上骑兵应该怎么拔刀?从清人佩刀为何总是刀柄向后说起...
  9. 下载的java游戏怎么运行不了_java运行环境下载
  10. 网络知识:详解各种路由器组网方法!