2025 AI基础设施风向标,不看必后悔!#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:503246

评论

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

文献解读-临床试验-第二十一期|《输注piggyBac修饰的CD19 CAR-T细胞后产物衍生性淋巴细胞瘤的研究》

INSVAST

基因数据分析 生信服务

万界星空科技机械加工MES功能介绍

万界星空科技

mes 万界星空科技 机加工MES 机械加工

MES使用后对工厂车间产生的重大影响

万界星空科技

生产管理系统 mes 云mes 万界星空科技 车间管理

MobPush REST API 概述

MobTech袤博科技

Java 开发者 产品动态

聚焦智慧出行,TDengine 与路特斯科技再度携手

TDengine

(内含福利!!) 8月17日,邀您共赴南京Unstructured Data Meetup!

Zilliz

AI Milvus Zilliz 向量数据库 RAG知识库

IT研发、运维、技术等相关人员为什么要参加DevOps培训?

雅菲奥朗

DevOps 运维 开发 DevOps认证 DevOps培训

智能化数据安全分类分级实践

鲸品堂

企业号2024年7月PK榜

融云 2024 ChinaJoy | 你有一个必逛的展位 @W4 馆 B786

融云 RongCloud

某交通运输企业SRE Foundation团体培训圆满结束

雅菲奥朗

DevOps SRE SRE培训 SRE认证 SRE Foundation

App如何利用推送消息有效实现拉新促活?

HarmonyOS SDK

HarmonyOS

系统整容纪:揭秘Java编程之美:掌握这些编码规范,让你的代码一跃成为行业典范

京东科技开发者

云电脑赋能多场景融合:ToDesk云电脑、无影云、青椒云综合评测

小喵子

无影云电脑 云电脑 ToDesk ToDesk云电脑 云电竞

【YashanDB知识库】EXP导致主机卡死问题

YashanDB

yashandb 崖山数据库 崖山DB

直播预约丨《袋鼠云大数据实操指南》No.4:数据服务API实战解读,助力企业数字化跃迁

袋鼠云数栈

大数据 直播 API 数据服务 数据服务平台

活动回顾|Unstructured Data Meetup 北京场

Zilliz

AI Milvus Zilliz 向量数据库 RAG知识库

广告在线模型系统负载均衡策略实践

京东科技开发者

跨境电商物流解决方案供应商,专业为您服务

api开发

MobPush REST API的推送 API之创建推送

MobTech袤博科技

Java 开发者 产品动态

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