代码自解释不是不写注释的理由

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

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

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

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

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

自解释的代码是不存在的

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

// 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/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275490.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux汇编中的注释,Linux 汇编器:对照 GAS 和 NASM

Linux 汇编器:对比 GAS 和 NASM转自 http://www.ibm.com/developerworks/cn/linux/l-gas-nasm.html#ibm-pcon与其他语言不同,汇编语言要求开发人员了解编程所用机器的处理器体系结构。汇编程序不可移植,维护和理解常常比较麻烦,通…

你可能不知道的package.json

大家好,我是若川。最近组织了源码共度活动:1个月,200人,一起读了4周源码,参与的小伙伴都表示收获很大。如果感兴趣可以点击链接扫码加我微信 ruochuan12。今天推荐一篇相对简单的文章。前言在上一篇npm init vitejs/ap…

基于上下文的rpn_构建事物-产品评论视频中基于上下文的情感分析

基于上下文的rpnThe word “Social” has taken a whole new meaning in today’s digital era. Simply going out to enjoy is no longer the only “social” criteria. Social now is — giving a peek in your personal and professional life to your connections. Facebo…

可爱的 Python: 使用 mechanize 和 Beautiful Soup 轻松收集 Web 数据

可爱的 Python: 使用 mechanize 和 Beautiful Soup 轻松收集 Web 数据 使用 Python 工具简化 Web 站点数据的提取和组织 David Mertz, Ph.D., 开发人员, Gnosis Software, Inc.从 2000 年开始,David Mertz 就一直在为 developerWorks 专栏 Charming Python 和 XML M…

广西工学院c语言试题答案,广西工学院的C语言考试试题

广西工学院鹿山学院 2005 — 2006 学年第 2 学期课程考核试题 考核课程 《C语言程序设计》 (A卷)考核班级 学生数 印数 考核方式 闭卷 考核时间 120 分钟一、选择题(每题2分,共40分)1. 一个C语言的源程序中, 。A.必须有一个主函数2. 下列数据…

JavaScript 断点调试技巧

大家好,我是若川。最近组织了源码共度活动:1个月,200人,一起读了4周源码,参与的小伙伴都表示收获很大。如果感兴趣可以点击链接扫码加我微信 ruochuan12。之前推荐过很多次调试文章,说明调试的重要性&#…

大学生电子设计大赛案例分析_为大学生设计问答平台—案例研究

大学生电子设计大赛案例分析Dealing with academic-related questions like picking a course, fulfilling a major requirement can be tedious and ineffective when you have to simultaneously balance school work, social activities, and focus on personal growth and …

最新最详细最简洁Eclipse调试PHP配置详解(Xdebug,Zend Debugger)

搬家注:该日志写于2011 年 04 月 07 日,Eclipse,PHP等版本号很多,更新也比较快,请注意文章中的版本。本文不一定帮您解决问题,但能给您一些解决问题的思路及一些概念。 最近开始做SRTP项目WebOS&#xff0c…

按键精灵易语言c,求助(把按键精灵的源码转为易语言的)

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼MoveTo 1203,673IfColor 1203,673,"252489",2 ThenMoveTo 417, 242Delay 10072LeftDown 1LeftClick 1LeftUp 1MoveTo 982, 551Delay 7660LeftDoubleClick 1Delay 10Delay 30LeftUp 1LeftUp 1LeftUp 1MoveTo 1102, 709Del…

入门前端学习路线图【送书】

大家好,我是若川。记得点上方音频听小姐姐配音,超级好听。华章图书又赞助了书籍送福利给大家。本次送4本书的抽奖方式是:截止到9月6日(周一)20:00,在留言区留言任意内容。我会在留言区抽取「1位」关注我公众…

单选按钮设置为被选中状态_为什么要设置错误的按钮状态

单选按钮设置为被选中状态当正确的方法出错时 (When the right way goes wrong) Let’s say you want to create a click effect on an HTML button. The first idea that many people get is to do something that reproduces the feeling of the sound emitted by a real but…

「娃娃分享」-常见自校检分析实例.

自校检是许多软件的保护手段之一,对软件加个简单的壳再增加自校检在一定程序上可以抵挡住一大部分新手,不过,对许多人来说,这个保护已经很弱了。。下面讲几种常见的解决自校检方法,写的粗略,希望大家补充。…

用VC和MinGW导出dll的def和lib(a)文件

为什么80%的码农都做不了架构师?>>> 原文地址:http://zhangyafeikimi.iteye.com/blog/404580 有了dll文件需要导出def文件: pexports zlib1.dll > zlib1.def 有了dll和def文件,需要导出MinGW的.a文件:…

51中断编程c语言,[新人求指教]51C语言编程可否用中断令循环结束提早结束

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼C51_C语言编程控制流水灯硬件电路 p0 接 led 8 个,P33 接按键使用中断2开机灯按1~8逐位闪烁,并循环按键后改为 两灯亮 的流水灯下面写了个程序#include #include #define uchar unsigned char#define uint u…

产品设计美学案例分析_美学在产品设计中的重要性

产品设计美学案例分析重点 (Top highlight)In one of my previous jobs, I had really interesting debates with the CEO regarding whether we should spend more time improving the way our app looks and feels. ‘How could he not care that the design is outdated?! …

即将到来的ECMAScript 2022标准

大家好,我是若川。周末分享一篇相对简单的文章。最近组织了源码共度活动:1个月,200人,一起读了4周源码,参与的小伙伴都表示收获很大。如果感兴趣可以点击链接扫码加我微信 ruochuan12。另外:昨天的推文入门…

c语言中二叉树中总结点,C语言二叉树的三种遍历方式的实现及原理

二叉树遍历分为三种:前序、中序、后序,其中序遍历最为重要。为啥叫这个名字?是根据根节点的顺序命名的。比如上图正常的一个满节点,A:根节点、B:左节点、C:右节点,前序顺序是ABC(根节…

动态库的创建与使用

1、动态库文件的创建 (1)编写源文件 (2)编译生成动态库 g -fPIC -shared -o libfile_operation.so file_operation.cpp 此编译过程分为两步,等同于下面的两个命令: g -c -fPIC file_operation.cpp …

ux设计中的各种地图_UX写作中的移情

ux设计中的各种地图Demetri Martin is a master of comedic situations. If you’ve never seen Demetri Martin是喜剧情境的大师。 如果你从未见过 him before, he has a sort of dry brand of observational humor, relying more on anecdotes than full stories, and often…

字符串搜索。HOJ1530 Compound Words。

stl set实现字符串搜索。。效率一般。(附二分搜索。) Compound WordsTime limit:1sec.Submitted:233Memory limit:32MAccepted:81Source: Waterloo ACM Programming Contest Sep 28, 1996 You are to find all the two-word compound words in a dictionary. A two-word compo…