硬核干货——《中小企业 AI 实战指南》免费下载! 了解详情
写点什么

你写注释吗?写你就输了

  • 2020-07-20
  • 本文字数:5078 字

    阅读完需:约 17 分钟

你写注释吗?写你就输了

本文最初发布于 Level Up Coding 官方博客,经原作者授权由 InfoQ 中文站翻译并分享。


我并不是提倡不写代码注释,只是建议不要过于依赖注释,这样可以使代码更干净、更有表现力,这也能提高开发人员的水平。我自己也在寻求编写更简洁的代码,我尽力不编写糟糕的注释,并在可能时重构代码。



这篇文章的标题可能会让你情绪激动,但请先耐心听我说完。在适当的位置写下适当的注释可能非常有用,但是没有什么比无用的注释更让代码混乱了。在某些情况下,我敢说,注释可以弥补我们在代码中没有完全表达出来的意思。因此,写注释不值得赞美,而是应该停下来问问自己,是否有更好的方式可以用代码来表达自己。


带有少量注释的清晰而富于表现力的代码,要比带有大量注释的混乱而复杂的代码好得多。如果你已经把代码弄得一团糟,不要花时间写注释来解释,而是要花时间梳理代码。如果每次写注释的时候,你都冥思苦想,觉得自己的表达能力不足,那么最终你就会写出简洁明了的代码,完全没有必要写注释。鼓励自己用代码表达。

为什么对注释如此不屑?

因为它们会说谎,还会把代码弄得乱七八糟。虽说并非总是如此,也并非有意如此,但却经常如此。糟糕的代码和带有大量注释的代码之间有很高的相关性。注释存在的时间越久就越容易偏离它们所描述的代码——在某些情况下,它们可能是完全错误的。实际上,随着代码库和团队的增长,维护注释成了不可能的事情。


注释不同于《辛德勒的名单》。它们不是“纯善的”。事实上,注释充其量是一种必要的恶。——Robert C.Martin


当谈论关于注释的话题时,很重要的一点是,我们要看一下什么是恰当的注释,什么是糟糕的注释,这样我们才能学会写更好的注释,或者完全避免注释。

恰当的注释

并不是所有的注释都是不好的——有些注释实际上非常必要。

出于法律目的的注释

有时候,你可能需要出于法律目的编写特定的注释,比如开源项目的创作许可。一些现代化的 IDE 和文本编辑器会自动将它们折叠起来,保持工作区的整洁。

魔术表达式

如果你有一个复杂的 SQL 或正则表达式,它以神奇的方式做了一些令人兴奋的事,那么请务必注释,以便让读者更容易理解,因为我们都不是 Regex 忍者。


// 匹配电子邮件地址的正则表达式var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;return re.test(String(email).toLowerCase());// 注意:添加一个富于表现力的函数名,注释就变得没有必要了function validateEmail(email) {     var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;    return re.test(String(email).toLowerCase());}
复制代码

说明意图

在某些情况下,注释有助于解释决策或特定解决方案背后的意图。例如,测试套件中的一条注释告诉我们添加这行代码是为了降低死锁的几率。


for x in range(1, 500):    # 这是运行多个并行测试时预防死锁的最好方法  time.sleep(0.5)  runTest(x)
复制代码

结果预警

用注释说明代码可能会产生严重的或可怕的后果,甚至鼓励这样做。在本例中,开发人员让读者知道,当与回调函数一起使用时,QT 函数不是线程安全的。一般来说,如果一条注释可以避免某个人在编程时陷入绝望,那么它就是有用的。


"""  许多Qt函数都不是线程安全的。如果你使用回调函数,  即使你在所有绘制调用代码的周围都加上锁,你也会遇到段错误,  因为Qt的主事件循环仍在运行,并且使用了没加锁的资源。"""from multiprocessing.pool import ThreadPoolimport sysfrom threading import Lockimport timefrom PyQt5 import QtCore, QtWidgetsclass Task(QtCore.QObject):    updated = QtCore.pyqtSignal(int, int)    ...............    ...............
复制代码

TODO 注释

这些注释可以帮助我们标记那些我们认为应该做,但是由于某些原因没有做到的事情。它可能会提醒你删除废弃的特性,或者请求其他人查看某个问题。它可能是要求其他人想一个更好的名字,或者是提醒他们根据计划事件做出修改。


请记住,TODO 注释不是在系统中留下糟糕代码的借口。本质上,每一行代码都是一种负担——最安全、最快的代码是根本没有代码。


现在,大多数优秀的 IDE 都提供了特殊的指令和特性来定位所有的 TODO 注释,所以不太可能漏掉它们。尽管如此,你也不希望代码中到处都是 TODO。所以要经常浏览一下,删除那些你能删除的。

糟糕的注释

这个清单比较长,但在本节中,我们将看到一些更为老生常谈而又随处可见的注释。

明知故问的注释

有些注释的意思显而易见,即它们没有增加任何实际的价值,而且大多是噪音。


下面是一个开源项目的代码片段,其中包含大量明知故问型的注释,这些注释使代码变得混乱而晦涩。它们所提供的信息并不比代码本身多,而且在某些情况下,阅读注释的时间甚至比阅读代码长。


/*** 与该容器相关的集群*/protected Cluster cluster = null;/*** 人类可读的容器名 */protected String name = null;/*** 该容器的父容器*/protected Container parent = null;/*** 创建一个Loader配置父类加载器*/protected ClassLoader parentClassLoader = null;
复制代码

不清不楚的注释

如果你写注释是为了符合公司规定,或者你只是觉得有必要添加一些注释,那么你在注释时就不会进行适当的思考。所以,如果你真的写了一条注释,花点时间让它对阅读它的人有所帮助。


def load_config():  try:    do_useful_stuff()  except Exception as ex:     # 如有异常,退回到默认状态。
复制代码


在这个例子中,作者想要传达一些有关异常情况的重要信息。但这条注释没能解释清楚我们将退回到什么样的默认状态。如果一条注释要求我们转到另一个模块来找出默认值,那么它就没有发挥应有的作用。

注释掉代码

在团队准备好删除代码之前先将其注释掉似乎是一个好主意,但是不要这样做。注释代码是一种弊端,团队中的其他成员不会删除它,因为他们会认为它很重要。我们不是都在使用源码控制吗?所以我们不需要保留旧的代码。我们可以跳到任何我们想要的版本。

噪音注释

有些注释毫无意义,纯粹是噪音。时间久了,我们的大脑就会走马观花,我们也会开始跳过那些需要注意的重要注释。考虑一下下面的例子,其中的注释提供了很多价值吗?


-----------------------------# Exhibit A# 默认构造函数def get_todays_date():  return date.today()-----------------------------# Exhibit B# 返回月份的天# @return: 月份的天def get_day_of_month()  return day_of_month
复制代码


用编写干净代码的决心取代制造噪音的诱惑,你将成为一个更好、更快乐的程序员。

强制性注释

这肯定会引起争议。如果规定每个函数都需要一个 Java 文档或 Python docstring,是不是有点傻?大多数时候,类或函数名已经告诉我们注释所描述的内容,它们是多余的。在这个例子中,注释的数量比代码的数量还多——这让我很恼火。


class ComplexNumber:     """     这是一个用于复数的数学运算类。          属性:        real (int):复数的实部。        imag (int):复数的虚部。    """      def __init__(self, real, imag):         """         ComplexNumber类的构造函数。          参数:           real (int):复数的实部。           imag (int):复数的虚部。          """      def add(self, num):         """         该函数用于复数求和。          参数:            num (ComplexNumber):要加的复数。                  返回值:            ComplexNumber:包含和的复数。        """          re = self.real + num.real         im = self.imag + num.imag           return ComplexNumber(re, im)   help(ComplexNumber)  #访问类的docstring help(ComplexNumber.add)  # 访问方法的docstring 
复制代码

使用好的函数名或变量名

你可以使用更具表达性的函数和变量名替换注释,从而使代码更简洁。考虑下面的例子,第一个例子中的注释就变得没有必要了,因为有一个更好的函数名可以准确地告诉读者这个函数做了什么。


# 检查日期是否是过去的日期def check_date(date):   if date < today:     return true    return false 
def is_past_date(date): if date < today: return true return false
复制代码

注释不能弥补代码的糟糕

编写注释有一个比较常见的原因是糟糕的代码。我们以前都见过这种情况,在某种程度上,我们自己也犯过这样的错误。我们写一个模块或类,我们心里知道它混乱而无序。我们知道它一团糟。所以我们对自己说,“哦,我最好加下注释!”不!你最好把代码梳理清楚!


/* 这段代码糟透了。我知道,你知道,每个人都知道。我们假装什么都没发生,然后继续前进。以后你叫我白痴好了。*/
复制代码

小结

我并不是提倡不写代码注释,只是建议不要过于依赖注释,这样可以使代码更干净、更有表现力,这也能提高开发人员的水平。我自己也在寻求编写更简洁的代码,我尽力不编写糟糕的注释,并在可能时重构代码——将我的代码从宜家的一幅画变成梵高的作品。


所以让我们约法三章,不要写这么多注释。


原文链接:


Every time you comment code — you’ve already failed.


2020-07-20 13:503408

评论

发布
暂无评论
发现更多内容

非凸底仓增强算法上线国盛证券,开启智能交易新纪元

非凸科技

数字藏品 NFT 系统的开发

北京木奇移动技术有限公司

NFT开发 软件外包公司 音乐NFT

从几个方面深入分析信创堡垒机的作用

行云管家

信创 数据安全 堡垒机 国产化

JixiPix Premium Pack for mac图像处理工具

Geek贝

前端热更新:静默引擎重构中国互联网敏捷生态与数字化转型范式

xuyinyin

CTF竞赛教会我的那些大学没教的事:从理论到实战的蜕变

qife122

CTF竞赛 实战技能

CST圆极化贴片天线阵列 --- 时域T-solver, 分组激励法 By zone(Grouping)

思茂信息

电磁 天线 CST Studio Suite

技术分享 | 基于 Amazon Codepipeline 的静态网站自动部署

伊克罗德信息科技

【社招】斑马、问界、长城、一汽、鉴智招人

Y11

安全 简历优化 找工作

在AI时代挖掘真实需求:从CSV转HTML工具看用户痛点与创新方向

qife122

数据分析 需求挖掘

Spring框架中的Component与Bean注解

码语者

Java spring bean Component

vivo Pulsar 万亿级消息处理实践(3)-KoP指标异常修复

vivo互联网技术

Java 大数据 消息队列 pulsar Kafk

淘宝API文档:淘宝商品详情API接口

tbapi

淘宝数据采集 淘宝API 淘宝商品详情API接口 天猫API 天猫商品详情api

从Rust模块化探索到DLB 2.0实践|得物技术

得物技术

rust DLB

Vectorworks 2023 for mac(3D建筑设计软件)

晨光熹微

SQLPro for MSSQL for Mac(MSSQL数据库客户端)

晨光熹微

法律AI或将颠覆行业,AlphaGPT带来法律工具新革命

科技汇

NocoBase 本周更新汇总:支持自定义聚合变量

NocoBase

开源 低代码 零代码 无代码 版本更新

AI 在英语口语练习中的核心应用

北京木奇移动技术有限公司

软件外包公司 AI口语练习 AI英语学习

开发加密货币预付卡 App

北京木奇移动技术有限公司

软件外包公司 区块链外包公司 区块链支付

助力律师团队持续增长,iCourt跨界论坛走进华为探讨法律行业发展方向

科技汇

宋泽致“全体员工”的一封信——野火不惧寒风,山花终将灿烂

中烟创新

施工SaaS创业的血泪教训:现金流不健康,我们是怎么陷进去的

前鼻音

配得准才是真降本:AI破解零售补调困局

第七在线

Cisdem Duplicate Finder for Mac重复文件查找工具

Geek贝

Mac 软件

体育活动LED大屏:点燃赛场激情

Dylan

LED LED display 世界杯 体育 LED屏幕

反向海淘系统新篇!Hoobuy同款系统来袭

tbapi

淘宝代购系统 反向海淘系统 淘宝代购系统开发 反向海淘集运系统 hoobuy系统

Google Search Console 做SEO分析之“已发现未编入” 与 “已抓取未编入” 有什么区别?

村头的猫

搜索引擎 SEO 建站 SEO工具 SEO 优化

A Better Finder Attributes 7 for Mac文件批量重命名工具

Geek贝

猫头虎 推荐:国产开源AI工具 爱派(AiPy)|支持本地部署、自动化操作本地文件的AI办公神器

猫头虎

人工智能 大模型 AI编程 AI 编程 猫头虎

大数据-36 HBase 增删改查 列族详解 实测

武子康

Java 大数据 hadoop 分布式 HBase

你写注释吗?写你就输了_语言 & 开发_Tameem Iftikhar_InfoQ精选文章