审查清单设计:通用审查清单、语言特定清单、安全清单、性能清单的制定方法

说到审查清单,我见过太多团队把它搞成了「走过场」。一张清单列了上百条,评审时没人真看,最后成了摆设。

其实,好的审查清单不是越多越好。它应该像飞行员起飞前的检查单——每条都关键,漏一条就可能出事。

今天我就聊聊,怎么设计四类核心清单:通用的、语言特定的、安全的、性能的。

通用审查清单:所有代码都该过一遍

通用清单,说白了就是「不管什么语言、什么项目,都得查」的那些点。我习惯把它分成三块:

1. 逻辑与正确性

  • 边界条件:数组越界、空指针、除零操作。我在项目中遇到过,一个简单的 list.get(list.size()) 就能让线上服务挂掉。
  • 状态管理:状态机有没有遗漏的分支?并发场景下状态会不会乱?
  • 异常处理:catch 了异常之后,是吞掉、重试还是抛出去?我见过有人 catch 之后只打了个 log,然后继续往下走——数据全错了。

2. 可读性与维护性

  • 命名:变量名、函数名能不能「自解释」?别用 atmpdata 这种。
  • 函数长度:一个函数超过 50 行?嗯,该拆了。
  • 注释:注释应该解释「为什么」,而不是「是什么」。代码本身就能说明「是什么」。

3. 测试覆盖

  • 单元测试覆盖了核心逻辑吗?
  • 有没有针对边界条件的测试用例?
  • 异常路径有没有被测试到?
我的小技巧:通用清单别超过 15 条。太多的话,评审者会疲劳,反而容易漏掉真正重要的。

语言特定清单:不同语言,不同坑

每种语言都有自己的「脾气」。你想想看,Java 和 Go 的坑能一样吗?

Java 审查要点

  • 空指针防御:所有外部输入、方法返回值,都要考虑 null 的情况。我习惯用 Optional 或者 Objects.requireNonNull
  • 并发安全:HashMap 在多线程下会死循环?是的,JDK 1.7 的 bug。现在虽然修了,但 ConcurrentHashMap 才是正确选择。
  • 资源释放:流、连接、锁,有没有用 try-with-resources?

Python 审查要点

  • 类型提示:Python 3.6+ 支持类型注解了,别偷懒。我见过一个函数返回 list,结果里面混了字符串和数字,调用方直接崩了。
  • 可变默认参数def foo(lst=[]) 是经典坑。默认列表会被所有调用共享。
  • 异常捕获范围:别用 except: 捕获所有异常。至少指定 Exception,否则连 KeyboardInterrupt 都被吞了。

Go 审查要点

  • 错误处理:Go 的错误处理是显式的。检查每个 err,别用 _ 忽略。
  • goroutine 泄漏:启动的 goroutine 有没有退出机制?用 select + context 来控制生命周期。
  • 指针 vs 值:大结构体用指针传递,小对象用值传递。别搞反了。
语言 常见缺陷 审查重点
Java 空指针、并发问题 Optional、ConcurrentHashMap、try-with-resources
Python 类型混乱、可变默认参数 类型注解、默认参数不可变、异常范围
Go goroutine 泄漏、错误忽略 context 控制、err 检查、指针使用

安全清单:别让代码变成漏洞

安全审查,我建议从「攻击者视角」去想。如果我是坏人,我会怎么搞破坏?

输入验证

  • SQL 注入:所有数据库查询用参数化查询,别拼字符串。我见过一个项目,直接把用户输入拼到 SQL 里——还好是内网系统。
  • XSS 防御:输出到 HTML 的内容要转义。别相信前端传来的任何数据。
  • 文件上传:检查文件类型、大小、路径。别让用户上传一个 .jsp 文件然后直接执行。

认证与授权

  • 密码存储:用 bcrypt 或 argon2,别用 MD5、SHA1。彩虹表了解一下?
  • 会话管理:Token 有没有过期时间?有没有刷新机制?
  • 权限校验:每个接口都校验权限,别只在前端隐藏按钮。

敏感信息

  • 日志:别把密码、Token、身份证号打到日志里。
  • 配置:数据库密码、API Key 别硬编码。用环境变量或配置中心。
  • 错误信息:生产环境别返回详细堆栈。用户看到「NullPointerException at line 42」——这不等于告诉人家怎么攻击吗?
我曾经踩过的坑:有一次,我把 AWS 的 Secret Key 直接写在了代码里,还提交到了 GitHub。虽然几分钟后就发现了,但已经被人扫描到了。从那以后,我强制团队用 git hooks 检查敏感信息。

性能清单:别等线上出问题再优化

性能审查,我一般分「必查项」和「优化项」。必查项不过,代码不能上线。

必查项

  • 循环中的数据库查询:N+1 问题。查一次拿到所有数据,别在循环里一条一条查。
  • 大对象创建:频繁创建大对象会导致 GC 压力。考虑对象池或复用。
  • 锁粒度:锁的范围越小越好。别把整个方法锁住,只锁关键代码块。

优化项

  • 缓存使用:热点数据有没有加缓存?缓存过期策略合理吗?
  • 批量操作:能批量就别一条一条处理。比如批量插入、批量更新。
  • 异步处理:非核心流程(发邮件、写日志)能不能异步?别让用户等着。
一个真实案例:我审查过一个报表系统,每次查询要 30 秒。一看代码,里面有个三层嵌套循环,每层都查数据库。改成一次查询 + 内存计算后,耗时降到了 200 毫秒。你想想看,这差距有多大?

清单的维护与落地

清单不是写一次就完事了。我建议:

  • 定期更新:每季度根据线上事故、新语言特性、新安全漏洞,更新清单。
  • 团队共建:别一个人拍脑袋写。让团队一起讨论,大家认可了才会执行。
  • 工具化:能自动检查的,就别靠人肉。比如 SonarQube、ESLint、Checkstyle 可以覆盖大部分通用和语言特定检查。

最后说一句:审查清单是「辅助」,不是「替代」。它帮你记住容易忘的点,但真正的代码质量,还是靠每个人的责任心。