26、注释的艺术:注释不能美化糟糕的代码、用代码来阐述、好注释与坏注释。
说实话,我见过太多团队把注释当成“代码遮羞布”了。
代码写得一塌糊涂,然后扔一堆注释上去,仿佛这样就能把烂代码洗白。嗯,这其实是个天大的误区。今天我们就来聊聊注释这件事——它到底该怎么用,什么时候该写,什么时候千万别写。
注释不能美化糟糕的代码
先记住一句话:注释永远无法弥补烂代码带来的伤害。
我早年接手过一个遗留系统,里面有个方法长达 800 行,开头赫然写着:
// 这个函数处理订单、库存、物流、支付、退款、积分、优惠券、发票……
// 别问我为什么这么长,我也没办法,老板催得紧
// 如果你要改,请先烧三炷香
你想想看,这种注释除了表达绝望,还有什么价值?
真正的问题不是缺少注释,而是代码本身已经坏掉了。你花半小时写一段漂亮的注释解释一段烂逻辑,不如花半小时把那段逻辑重构掉。
用代码来阐述
我个人习惯是:能用代码表达的东西,绝不用注释。
举个例子,下面这段代码你肯定见过:
// 检查用户是否有权限删除这条记录
// 如果用户是管理员,或者用户是这条记录的创建者,则允许删除
if (user.role === 'admin' || user.id === record.creatorId) {
// 执行删除
}
其实这段注释完全可以删掉,把代码改得更直白:
if (user.isAdmin() || user.isCreatorOf(record)) {
record.delete();
}
看到了吗?好的命名 + 好的抽象,注释自然就消失了。我在项目中经常跟团队说:注释是代码的“拐杖”,能扔掉就别拄着。
为什么会这样?因为注释和代码是两套系统,它们会随着时间推移而“分道扬镳”。代码改了,注释没改——这种事我见得太多了。最后注释反而成了误导。
好注释与坏注释
当然,我不是说注释完全没用。有些场景下,注释是必要的。我们来分分类。
好注释长什么样?
我总结了四种值得写注释的场景:
| 类型 | 说明 | 示例 |
|---|---|---|
| 法律信息 | 版权声明、许可证等 | // Copyright 2024 xxx Corp. All rights reserved. |
| 意图说明 | 解释“为什么这么做”,而不是“做了什么” | // 使用二分查找而不是线性扫描,因为数据量超过 10 万条 |
| 警示后果 | 提醒后续开发者某些操作的副作用 | // 注意:这个方法会清空缓存,调用前请确认 |
| TODO 标记 | 记录已知但暂时无法解决的问题 | // TODO: 这里需要处理并发冲突,v2.0 修复 |
我曾经在一个支付系统里写过这样一条注释:
// 为什么这里要 sleep(100)?
// 因为下游的银行接口有反重放攻击机制
// 同一笔交易在 100ms 内重复请求会被直接拒绝
// 这是跟银行对接时踩过的坑,别删
这种注释就很有价值。它解释了“为什么代码看起来有点奇怪”,而且包含了上下文和血的教训。
坏注释长什么样?
说白了,大部分注释都是坏注释。我列几个典型:
- 冗余注释:
i++ // i 加 1—— 这种注释纯粹是浪费行数 - 误导性注释:代码改了,注释没更新,比没有注释更可怕
- 日志式注释:
// 2024-01-15 张三修复了空指针异常—— 请用版本控制,别写在代码里 - 位置标记:
// ========== 初始化部分 ==========—— 说明你的函数太长了,该拆了 - 注释掉的代码:整段整段地注释掉,又不删。我问你,这段代码还能用吗?没人知道
知识体系图
下面这张图梳理了注释的核心逻辑,你可以对照着检查自己的代码:
最后说几句
注释这件事,说到底是个“度”的问题。我见过完全不写注释的项目,也见过注释比代码还多的项目——两者都让人头疼。
我的建议很简单:先让代码自己说话。说不清楚的地方,再用注释补充。
你想想看,如果一段代码需要三行注释才能看懂,那它大概率需要的是重构,而不是注释。把精力花在让代码更清晰上,比花在写注释上划算得多。
1. 这段注释是在解释“为什么”还是“是什么”?
2. 如果删掉注释,代码本身是否依然清晰?
3. 这段注释会不会随着代码变更而过时?
4. 有没有办法通过改名或重构来消除这条注释?
公众号:蓝海资料掘金营,微信deep3321