写出好维护的代码 — 通过注释让代码更容易维护

2025年11月27日

💎 加入 E+ 成長計畫 與超過 800+ 位工程師一同在社群成長,並獲得更多深度的軟體前後端學習資源

要让代码库变得更容易维护,有良好的文档会很有帮助;对代码来说,除了额外写相关的技术设计文档,在代码中的注释 (comment) 也是文档的一种。

每当提到在程序中写注释 (comments),在社群中就会听到有人表示「如果有注释就代表写不够清楚,应该要重构而不是加注释」。

然而,真的是这样吗?

事实上,许多维护过大型代码库的人,会同意代码要写清楚,但同时也同意注释有其存在的必要性。把代码写清楚,跟写注释两者是不冲突也不互斥的,当有写得清楚的代码,搭配对的注释,两者是能相辅相成,共同提升代码的可维护性。

在这篇文章,我们会详细来谈,为什么推荐在代码中写注释,以及注释该怎么写、哪些注释不该写 (没错,即使推荐写注释,也不代表推荐什么注释都要加,审慎地写才会对可维护性有帮助)。

为什么推荐在代码库中写注释?

首先,让我们先来谈为什么推荐写注释。过去社群中很多人认为不用写注释,是基于「程序本身写得够清楚,就不用注释」这个理由。然而程序本身或许可以清楚表达该程序代码做的事,但不能解释「为什么」要这样写,也不能解释在什么情境可能比较适合某个方法。对于这些相对后设 (meta) 的内容,注释就是很好的帮手。

更进一步说,好的软件设计,应该要把复杂度藏起来,要藏起复杂度,我们需要抽象化 (详见 写出好维护的代码 — 抽象化 (abstraction) 时该注意什么? 一文),让其他使用该段代码的开发者,可以不用去管背后的细节。因此,如果一个开发者,还要去读代码的细节才能懂如何用该函数或方法,那就失去抽象化的意义。

举例来说,假如今天某个函数的接口中有 startend 两个参数,只看参数名称,其实没办法知道 startend 是否分别包含该数值 (例如 end 为 10,是到 10 之前,还是刚好到 10?),也没办法说明如果 start > end 程序代码会如何处理。

如果写注释,开发者就可以不用去看该函数的实现细节,也能知道这些对使用来说很关键的信息,这才能达到抽象化的意义。因此不论程序本身写的清楚与否,好的抽象化搭配好的注释,都会对整个程序库的维护有帮助。

没时间写注释不再是借口

另一个很常见的不写注释的理由,是因为「没时间」。在开发时,很多开发者会认为写注释的优先顺序比较低,因此会想把时间花在写新功能,而不是为已经开发好的功能写注释,这很可以理解。

然而在软件开发中,永远有写不完的功能,如果说因为要开发新功能而没时间写注释,就永远不会有注释。从长远的角度来看,这样的代价是程序库的可维护性会降低。如果从效益与成本的角度来看,写注释的时间,会远比其他开发者花在弄懂没注释的程序所花的时间要少很多。

进一步说,现在有 AI 协助,写注释所需要的时间成本,跟过去比起来大幅降低。现在甚至可以直接在 Cursor 或 Claude Code 等工具,帮忙写程序代码时,就顺便写注释,或者可以新增一个 /add_comment 的指令,然后一键请 AI 帮忙写好,开发者只需要检查即可。

因此,如果你在的团队,过去也很常会因为时间为由不写注释,推荐可以试着导入 AI 工具,并让团队成员知道写注释对长期程序库的健康来说,投资报酬率很高。

什么该写成注释?有哪些推荐的注释种类?

在理解为什么要写注释后,接着让我们来谈什么该写成注释。

如上面已经有提到的,注释的最大好处在于,可以捕捉到程序代码没办法传达的信息,这能够让未来要维护这段程序代码的开发者,能够更快速地上手。特别对于团队中加入的新成员,程序代码中的注释可以大幅降低读程序的认知负担 (cognitive load),以及减少未知。

如果没有记录下这些脉络与原因,未来的开发者就不会知道为什么当初是这样写,这变得只能猜测原作者的意图。这不仅更耗时,也可能会因为理解错原本的意图,导致在维护该段程序代码时出错。很多时候,未来要维护程序代码的是自己,许多人在写完某段程序代码几个月后,可能忘了自己当初为什么这样写,所以写注释不仅是帮助其他开发者,也很可能是在帮助未来的自己。

因此通过注释,把最重要的「为什么」记录下来,对于未来的维护者来说,会非常宝贵。以我们先前实际的经验为例,过去曾看过一段程序代码觉得写得很怪,因为不是按照该框架推荐的方式写;但好在那段程序代码有注释,谈到相关原因,而在读那段注释时,发现原本记下的原因后来已经不存在了,所以那时就放心重构,而不是卡在思考「为什么这段这样写?假如要重构的话,会不会有什么没考虑到」的泥淖中。

推荐写的注释种类

先前 Redis 的作者 antirez 曾经写一篇《Writing system software: code comments.》文来分析他认为推荐写的注释种类,其中有几个是我们特别推荐的。

第一种,接口注释,antirez 把这个称为函数注释 (function comments),但如果仔细看定义,这类注释是适用于任何接口,不只是函数。所谓的接口注释,就是让维护者可以只看接口,不需要去看程序代码的实现细节,就完整掌握这个模块在做什么。这是推荐在程序库中,一定要写的注释类型。

以下面这段来说,即使把实现细节忽略,也能完全明白这个函数在做什么。

/* 在当前节点的子树中寻找最大的键。如果内存不足则回传 0,
 * 否则回传 1。这是一个辅助函数,供下面不同的迭代函数使用。*/
int raxSeekGreatest(raxIterator *it) {
    // 实现细节忽略...
}

第二种,设计注释 (design comments) 与原因注释 (why comments),这两类注释的核心重点,都是要解释某一段程序为什么是这样设计。这类注释能够协助未来的维护者理解,某段可能不是那么显而易见的写法,之所以这样写的原因,这对于维护来说帮助很大。

第三类,教学注释 (在 antirez 文章中的 teacher comment 与 guide comment 都有类似作用),这类注释的目的是解释一些可能对熟知程序库的人没帮助,但是对于刚加入团队的人来说很有用的信息。这类注释不像前一类,会特别解释不显而易见的原因,而是偏向教学的方式,解释程序代码的运作。

在 antirez 的文章中,有更多类别的注释,不过以我们的实务经验来说,上面这三大类别是从可维护性角度来说,最值得写成注释的内容。

阅读更多

如果你想更了解如何写好注释、什么该写注释、什么不该写,还有写注释时有什么注意事项,我们在 E+ 的主题文都有详谈。E+ 的《写出好维护的代码》系列文与课程,也会谈其他有助于写好程序的要点,欢迎加入 E+ 观看 (链接)

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們