代码质量
格式化
- 自动格式化只改表面语法
- 统一引号、空格、换行、尾逗号
- 排序
import、折断超长行 - 行宽约定:80、88、100
- Prettier 覆盖 JS、TS、CSS、Markdown
prettier --check只报告,--write改写.prettierrc提交进版本库- Black:Python,刻意少给配置
ruff format与 Black 风格兼容gofmt -l .列出不合规文件gofmt随 Go 工具链分发,没有开关- rustfmt、clang-format、StyLua
.editorconfig统一缩进与换行- IDE 保存时格式化
- 纯格式化提交单独一次,减少 diff 噪音
.git-blame-ignore-revs跳过格式化提交
静态检查
- 静态分析不运行代码就读出问题
- 规则集与预设按项目启用
- Ruff 规则码:
E501、F401、SIM102 ruff check报告,--fix自动修[tool.ruff.lint]配select与ignore- ESLint 的 flat config
- ShellCheck 抓引号与变量展开
- clang-tidy、golangci-lint
- 行内豁免:
# noqa: F401 - 行内豁免:
eslint-disable-next-line - 每条规则自带文档,解释为什么
- 误报用
noqa行内豁免,别全局关规则 - 类型检查:mypy、pyright、
tsc --noEmit - semgrep 在 AST 层匹配危险模式
semgrep -l python -e "..."- 格式化器管排版,linter 管语义
测试
- 单元、集成、端到端三层
- 测试金字塔:单元多、端到端少
- pytest 发现
test_*.py与test_* pytest -k按名字筛选用例pytest -x首个失败即停pytest --lf只跑上次失败- fixture 准备与清理资源
pytest.raises断言异常monkeypatch与unittest.mock.patch- mock 数据库、HTTP 等外部依赖
pytest-vcr录制并回放真实请求- TDD:先写失败的测试
- 回归测试:修 bug 前先复现
- 属性测试:Hypothesis 的
@given - 属性测试只验证写下的性质
coverage run -m pytest与coverage htmlcoverage xml喂给 agent 补测试- 行覆盖与分支覆盖
- 覆盖率是下限,不是目标
提交前钩子
.git/hooks/pre-commit是可执行脚本- 非零退出码中止提交
git commit --no-verify跳过钩子- pre-commit 框架统一管理钩子
.pre-commit-config.yaml的repos与hookspre-commit install写入钩子pre-commit run --all-files全量跑pre-commit autoupdate升级钩子版本- 默认只检查暂存的文件
- 未暂存改动先 stash 再还原
language: system调用本机工具commit-msg检查提交信息格式pre-push放慢检查core.hooksPath指向仓库内钩子- 钩子可被跳过,CI 才是底线
持续集成
- workflow 放在
.github/workflows/ on: push与on: pull_requeston: schedule用 cron 定时跑jobs定义并行任务runs-on与steps描述执行过程actions/checkout拉代码actions/setup-python装运行时strategy.matrix组合多版本actions/cache缓存依赖- CI 跑 check 模式,不改代码
- 格式化用
--check而非--write - 失败状态阻止合并
- 分支保护配 required checks
secrets在 fork PR 中不可用- 状态徽章显示在 README
- 覆盖率上传 Codecov 看趋势
- 持续部署:构建产物并发布
命令入口
- 命令越长越没人记得住
justfile定义 recipejust lint代替长命令just --list列出全部 recipe- recipe 可依赖其他 recipe
- 每行 recipe 默认独立 shell
set shell改成bash -ucmake依赖 tab 缩进.PHONY声明伪目标npm run读package.json的scriptsuv run在项目环境执行- Hatch 的
tool.hatch.envs.*.scripts - 约定
check汇总全部检查 #注释作为 recipe 说明- recipe 应幂等可重复
正则表达式
- 正则描述一组字符串
.匹配任意单字符[abc]、[^abc]、[a-f]- 量词
?、*、+、{N} - 锚点
^与$ - 分组
(...)与捕获 - 贪婪
.*与懒惰.*? - 命名分组
(?P<name>...) - 反向引用
\1 - 前瞻
(?=...)与后顾(?<=...) - Python 的
re.match、search、fullmatch re.sub的替换模板- 原始字符串
r""保留反斜杠 grep -E与grep -P的方言- Vim 基本正则的
\+与 PCRE 的+ go test -run用正则筛测试- 不拿正则解析 HTML 与 JSON
重构与自动修复
- 重构不改变外部行为
- 小步提交,每步保持测试通过
- IDE 的 rename 基于符号而非文本
- extract function 与 inline
ruff check --fix修机械问题eslint --fix修 JS 常见模式cargo clippy --fix- semgrep
--autofix批量改 - ast-grep 用
$X匹配节点 - codemod 处理跨文件迁移
- 文本替换会误伤注释与字符串
- 格式化提交与逻辑提交分开
- 大改前先补基线测试
- 清理死代码与兼容层
容易混淆的问题
- 格式化器与 linter 各管什么
--check与--write分别用在哪- pre-commit 与 CI 谁负责拦
pytest -k与go test -run匹配什么- 覆盖率 100% 是否说明测试可靠
re.match与re.fullmatch的差别.*与.*?在替换里的结果- 替换引用写
$1还是\1 - 重构与重写的边界
- semgrep 与 grep 的匹配层