编译器/linter能验证语法但无法发现业务逻辑问题,如:并行请求是否独立、日志是否含敏感数据、错误是否被故意忽略、迁移是否保护旧数据等。
一个 Pull Request 可以通过编译器、格式化工具和 Linter,却仍然留下一个严重的工程问题。
也许两个独立网络请求被依次等待。也许某行日志包含了凭证或个人信息。也许某个错误被丢弃了,却没有说明这是有意还是无意。也许某个持久化变更对新数据有效,却没有保护已有记录。
这些问题都不一定看起来像语法错误。
代码可以是有效的。测试可以是绿的。这个变更甚至在快速 review 时看起来也是合理的。
这就是我构建 Nice Code 的原因。
编译器 Linter 对能够本地证明的规则非常擅长。
它们可以告诉我们类型是否有效、变量是否未使用、函数是否正确格式化,或者某个已知规则是否被违反。
但有些工程问题涉及上下文:
这条日志包含足够的信息来安全地调试操作吗?
这些异步操作真的是独立的吗?
这个错误是被有意忽略的吗?
这个迁移是否保留了已有数据?
这个性能声明有测量数据支撑吗?
这个测试保护的是真实行为还是只在覆盖一条 happy path?
这些问题涉及意图、所有权、风险和运维行为。它们很难被简化为某条语法规则。
AI 辅助开发让这一点尤其明显。一个生成的变更可能完全合理,却仍然携带了关于并发、错误处理、安全或状态所有权的弱假设。
Nice Code 就是为那一层 review 设计的。
Nice Code 不是要替代编译器、格式化工具、Linter 或测试套件。
它在项目已有的工具之上增加了一层保守的、面向证据的 review。目标不是产生一个单一的质量分数。目标是让反复出现的工程问题变得可见,并提供足够的上下文供人决定接下来该怎么做。
该项目覆盖以下相关模式:
这些模式特意比通用静态分析系统更小。每个模式都应该有来源、反复出现的问题、实用的 review 流程,以及对其能证明和不能证明什么的清晰解释。
公共包提供了一个 Node 兼容的启动器:
npm install --global @sayanmohsin/nice-code
nice-code --changed --project .
安装的命令是 nice-code,而 npm 包的作用域是 @sayanmohsin/nice-code。
对于一次性运行,也可以不全局安装直接调用:
npx --yes @sayanmohsin/nice-code --changed --project .
最终用户不需要安装 Bun、Cargo 或 Rust。启动器会从项目的 GitHub Releases 下载并验证匹配的 Rust 引擎。
Nice Code 默认聚焦于变更工作。
在本地开发期间或提交前运行变更文件检查:
nice-code --changed --project .
当你想要检查更广泛的代码库时,运行一次有意为之的完整扫描:
nice-code --all --project .
这个区分是有用的。完整仓库扫描可能有价值,但它应该是有意为之的,而不是在每次小改动时默默成为其中的一部分。
Nice Code 也可以产生机器可读的输出:
nice-code --project . --all --json > nice-code-report.json
JSON 报告包含结构化的发现结果和扫描信息,可用于自动化、仪表盘或后续 review。
对于 GitHub 代码扫描集成,可以将 SARIF 输出作为 CI artifact 上传:
- name: Run Nice Code
run: nice-code --project . --changed --ci --format sarif > nice-code.sarif
- name: Upload Nice Code report
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: nice-code.sarif
现有项目可以通过一个基线来逐步采用 Nice Code:
nice-code --project . --all --write-baseline
基线使得项目在逐步处理旧有 review 项的同时,能够专注于新的发现结果。
信任取决于了解一个工具实际在说什么。
Nice Code 对发现结果进行分类,这样上下文问题不会看起来和已证实的缺陷完全一样:
FAIL 是高置信度问题,根据项目策略可能需要阻断。
WARN 是可操作的问题,通常需要 review。
REVIEW 意味着需要上下文或工程判断。
PASS 意味着相关检查运行后没有发现。
N/A 意味着该检查不适用于项目或变更。
REVIEW 状态很重要。如果一个工具无法证明某个行为是错误的,它不应该假装它可以。
例如,如果第二个操作依赖第一个操作,那么顺序 await 可能是正确的。如果值已经被清理过,日志语句可能是安全的。如果迁移在其他地方有保护,持久化变更可能是有效的。
工具应该识别问题和证据。开发者仍然需要做出最终决定。
Nice Code 保持 review 路径小而明确。
公开指导记录在源注册表中,并被适配为独立的工程模式。Rust 引擎负责发现、解析、规则、报告和退出决策。Node.js 提供面向用户的启动器,而 Bun 用于开发工具、测试和基准测试。
在 CI 模式下运行时,Nice Code 也可以运行可用的原生项目工具。它们的状态与 Nice Code 自己的发现结果保持独立,因此缺失或失败的原生工具不会与自定义 review 规则混为一谈。
结果可以通过多种方式消费:
因此,同一次 review 可以支持在本地工作的开发者、准备变更的 Agent,或者检查 Pull Request 的 CI 工作流。
没有哪个 review 工具能完美理解每个项目。
但这不意味着答案应该是禁用整个类别的检查。
Nice Code 支持项目特定的配置和例外,但例外应该是狭窄的和有文档记录的。一个好的例外解释为什么某个特定发现在那个位置是安全的。它不应该悄悄地移除整个类别的工程问题。
如果某条规则产生了误报,是因为解析器或启发式算法错了,更好的修复通常是改进 Nice Code 本身。不应该仅仅为了使检查器安静而重写目标项目。
在实践中,每个发现最终都应该落入三个类别之一:
这种分类比假装每个结果都具有同等确定性更有用。
Nice Code 是一个正在演进的项目。
它是一个 review 辅助工具,不是自主的工程权威。它补充原生工具和人工 review,而不是取代其中任何一个。
该项目在声称的内容上刻意保持保守。有些检查可以自动化。有些需要开发者或 Agent 检查周围上下文。还有一些最终是产品或运维决策。
有用的结果不是每个发现都消失。
而是困难的工程问题变得更早可见,并有更清晰的路径来决定如何处理它们。
你可以在这里找到这个项目:
Nice Code on my portfolio
Nice Code 起源于一个简单的观察:通过本地检查是必要的,但并不总是足以使一个变更变得可信赖。
该项目是试图在语法和系统行为之间添加一个小的、实用的 review 层。