为什么你应该减少代码注释?

文章主张在编程时应优先考虑使用更有表现力的代码和重构来提高可读性,而不是依赖大量注释。通过示例展示了如何用常量、变量和函数来简化代码,以及类型系统如何减少错误。同时,提到了注释的弊端,如可能过时和不准确,强调了代码文档的重要性。文章提倡在需要解释性能优化或复杂算法时才使用注释。
摘要由CSDN通过智能技术生成

本文首发于:造梦网
欢迎关注公众号:通用代码技术

说一个违反直觉的建议:

在大多数时候,你不应该在你的代码中写注释。

没错,如今现代编程语言提供了许许多多的富有表现力和抽象力的语言工具和特性。

使用这些特性,并对代码进行可读性重构,远比增加大量的代码注释要好得多。

下面看几个例子。

去除注释,增加表现力

简单例子

int status == 5:
  message.markSend()

查看这段代码,并不能直接看出来 5 是什么含义,我们可以添加一条注释来说明 5 代表什么:

# A status of 5 signals message sent
int status == 5:
  message.markSend()

但是更好的做法是,我们可以创建一个具有字面含义的常量来代替这个数字 5. 如下:

MESSAGE_SENT = 5
int status == MESSAGE_SENT:
  message.markSend()

在更复杂的例子中,应该思考其是否可以简化或者重构代码本身,使其变得更易理解。

复杂例子

# 如果当前用户是这段信息的作者,
# 并且这段信息是五分钟前发表的,你可以更新这段信息。
# 或者当前用户是 超级管理员,那么你也可以更新这段信息,
# 并且在这段信息未发表之前你也可以修改。
if (message.user.id == current_user.id and (
    message.deliverd_time() is None or (datetime.now() - message.delivered_time()).seconds < 300
  )) or current_user.type == User.Administrator:
  message.update_text(text);

这段代码我们添加了足够多的注释来解释它,但是我们可以通过使用变量来命名表达式的各个部分以此来简化代码。

FIVE_MINUTES = 5 * 60

user_is_author = message.user.id == current_user.id
user_is_admin = current_user.type == User.Administrator
is_recent = message.deliverd_time() is None or (datetime.now() - message.delivered_time()).seconds < FIVE_MINUTES

if (user_is_author and is_recent) or user_is_admin:
  message.update_text(text);

此时我们可以发现,if 条件读起来就像在读上面的注释一样清晰。所以我们可以去掉上述注释。

当条件足够复杂的时候,你还可以考虑将整个条件单独创建为一个函数:

def can_edit_message(current_user, message):
  FIVE_MINUTES = 5 * 60

  user_is_author = message.user.id == current_user.id
  user_is_admin = current_user.type == User.Administrator
  is_recent = message.deliverd_time() is None or (datetime.now() - message.delivered_time()).seconds < FIVE_MINUTES
  return (user_is_author and is_recent) or user_is_admin

if can_edit_message(current_user, message):
  message.update_text(text);

Oh My God! 一切都是如此的清晰。

类型也可以减少注释

现代语言都具备了丰富的类型系统,增强了语言自身表现能力,从而减少了注释。

// Get the delivered timestamp;
//
// A value of -1 is returned if the
// message has not been delivered.
int64_t delivered_timestamp();

上述代码表示,如果 delivered_timestamp() 出错,那么它将返回 -1 指代错误状态.

这在 Linux 编程中随处可见,因为 linux 内核主要使用了 C 语言进行编写,而 C 语言只有简单的类型系统。

但是在各种现代语言中,增加了一种类似 optional 的类型,它表示可能的含义,即可能是正常的值,可能会错误值。例如在 C++ 17 中新增了 std::optional

std::optional<int64_t> delivered_timestamp();

这样在面对多返回值的函数时,就不需要再单独处理另一种错误情况,std::optional<T> 中就有一个 bool 值来指代函数是否错误。

而且正常情况下 std::optional<T> 类型的变量仍可以当作 T 类型来使用。这样就减少了更多不必要的注释。

注释的弊端

注释并不是越多越好。

注释也会像代码一样出错

当人们对代码进行修改的时候,他们通常不会更新相对应的注释。我们有各种工具来检查代码的错误,例如测试,编译器检查,但是我们没有任何系统来检查注释的错误。

或许有一天 AI 的发展会出现这样的工具,来检查代码是否与注释相匹配,但是那时候程序员这个职业也许就不复存在了。但是不可否认的一点是:我们并不相信注释。

注释可以说谎,但代码不会。

代码文档

代码文档表述了系统的高级架构和公共 API,代码文档不同于注释。

注释表述了代码工作原理的内部结构,也就是代码是如何工作的;

而代码文档表述了如何使用代码。

世界需要更多高质量的代码文档,但不需要更多的代码注释。

Better Code = Better Documentation

应该写注释的几种情况

性能因素

如果代码因为性能原因做出了难以理解的行为,那么它需要一个注释来说明这么做的原因。

使用了数学公式或算法

如果代码使用了特定的数学原理或者特别的算法,你应该在注释中说明其来源。

例如在 Cpython 的源码 中:

结语

与代码注释相比,代码是表达意图的最好方式。

Code > Comments

所以总的来说,如果你需要使用人类语言来解释你的代码,看看你是否可以让你的代码更加人性化,更加易读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

通用代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值