代码注释:程序员最大的自 我感动
"好的代码是自解释的,注释是失败的证明。"
—— 这句话害了多少人?
当注释成为代码的遮羞布
每次看到代码库里这种注释,我都替作者尴尬:
// increment i by 1
i++
这是注释?还是在侮辱读者的智商?
我敢说,每个程序员都写过这种注释。但问题是,为什么我们还在假装这是一种"好习惯"?
注释的三大谎言
谎言一:注释越多代码越可读
去GitHub上翻各种"star过万"的知名项目,你会看到一个有趣的现象:
- 烂项目的注释:比代码还多
- 好项目的注释:少得可怜
为什么?因为真正好的代码,命名就是注释。
# 烂:
def calc(d):
# calculate discount
return d * 0.9
# 好:
def calculate_discount(amount: float) -> float:
return amount * DISCOUNT_RATE
看到了吗?第二个版本根本不需要注释。函数名、变量名、类型提示,已经把一切都说清楚了。
谎言二:注释不会过时
哈。
你见过最离谱的注释是什么?我见过这种:
// TODO: Remove this hack after fixing issue #1234
// 这个问题已经被标记为 won't fix
// 所以这个hack永远不会被移除了 lol
注释是代码的墓碑。你永远不知道代码改了N轮之后,哪个注释还在原地假装有用。
谎言三:写注释是基本素养
很多团队把"代码必须有注释"写进规范。
然后呢?
/**
* Gets the name.
* @return the name
*/
public String getName() {
return name;
}
这种注释,写了等于没写,还浪费了维护的人。
什么才是注释的正确打开方式
1. 解释"为什么",而不是"是什么"
// 烂注释:
// iterate through the list
for (let item of items) { ... }
// 好注释:
// 使用for...of而不是map,因为这里不需要返回值
// 而且for...of在大量数据时性能更好
for (let item of items) { ... }
注释应该解释代码背后的意图和上下文,而不是把代码翻译成人话。
2. 解释那些"不正常"的选择
// 不用strings.ToLower而是手动比较
// 因为ToLower会分配新内存,这在热路径上是不可接受的
// 参考: https://github.com/xxx/performance-issue
这种注释才有价值。读者能理解:哦,原来是有特殊原因的,不是因为作者傻。
3. 复杂的业务逻辑,需要注释
# 这里的计算逻辑:
# 1. 首先过滤掉状态为deleted的记录(业务规定)
# 2. 然后按照创建时间排序,取最新的前100条
# 3. 如果用户设置了只看VIP,则在此基础上再过滤
# 4. 最后还要按照某个复杂的权重算法重新排序
#
# 为什么这么复杂?历史遗留,详见:http://wiki/legacy-reason-123
这种注释就是救命用的。没有它,后来者(包括三个月后的你自己)根本看不懂这段代码在干嘛。
4. 标记未完成和已知问题
# BUG(2024-03): 当amount超过1亿时会溢出
# TODO: 等后端支持高精度Decimal后再修复
# HACK: 临时绕过高并发时的race condition
这种注释有价值,但一定要带足够的上下文!否则就是给自己和后人埋坑。
自文档化代码:一场美丽的骗局
有人会说:"别写注释,让代码自文档化!"
这句话害人不浅。
确实,好的命名、合理的结构、适当的抽象,能让代码更容易理解。但这不代表注释就是多余的。
现实是:
- 总有一些复杂的业务逻辑,代码本身说不清楚
- 总有一些"不得不"的hack,需要解释背景
- 总有一些历史遗留的坑,需要说明来由
"代码自文档化"是理想状态,但不是现实。
我的注释规范
经过多年毒打,我总结出的一套注释原则:
1. 能用代码表达的就别用注释
- 函数名 calculateTotalPriceWithTaxAndDiscount() 比任何注释都强
- 变量名 expiredAt 比 // expiration date 强100倍
2. 注释必须回答"为什么"
- 如果只是说明代码在做什么,删掉
- 如果解释了背后的业务原因、performance 考量、历史遗留,保留
3. 过期注释是技术债务
- 每次code review,发现注释和代码不一致,直接删或改
- 不要留着"万一有用"
4. 注释的敌人是复制粘贴
- 多少注释灾难源于"ctrl+c / ctrl+v"
- 宁可少写注释,也不要复制旧注释
5. 复杂算法的核心思路要写
- 那种你看三天都看不懂的算法,配上核心思路注释
- 但别写成逐行翻译,要写成"设计思路"
最后的真心话
我见过太多程序员,代码写得稀烂,注释写得贼多。
这就像一个人衣服穿得邋里邋遢,却花半小时写了个牌子解释自己为什么这样穿——完全没有抓住重点。
好的代码不需要注释,烂代码配什么注释都没救。
与其纠结"这段代码该不该加注释",不如先问问自己:
- 命名够不够清晰?
- 函数职责够不够单一?
- 逻辑能不能简化?
如果这些都做好了,注释自然是多余的。
如果没做好,堆再多注释也只是在给自己擦屁股,还是那种越擦越脏的擦法。
代码是写给人看的,注释同理。先把代码写好,再考虑注释的事。