本层判断标准

只看名字,能不能判断它属于哪个业务、做什么、返回什么?

答「不能」,说明得读完实现才懂,先改名字。改完名字还说不清它做什么,说明这个函数在做两件事,该拆开——那不是命名问题。

已经交给检查工具的四类

把规则写进配置,评审时没人再逐行看。四条命令挂进 make check,本地和持续集成跑同一条,见质量门禁。

拦什么规则工具查不到的边界
函数、变量、参数的大小写风格Python N802 / N803 / N806;TS naming-convention 的 variableLike;C# IDE1006;Go revive 的 var-namingJava 没有随构建工具附带的命名检查。不装 Checkstyle,这一项只能靠评审看
类型、类用 PascalCasePython N801;TS naming-convention 的 typeLike;C# IDE1006泛型参数、枚举成员的写法各语言不同,默认规则不统一管
包名、模块名Go revive 的 var-naming(小写、无下划线);Python N999TS 与 Java 的文件名规则不在 ESLint 内置规则里,要另装插件
缩写整词大写,如 ScopeID 不写 ScopeIdGo revive 的 var-naming,默认表含 ID、URL、HTTP、API其余语言没有内置缩写表。TS 可以用 naming-convention 的 custom 正则逐条加,成本高于收益,本仓库不加

.golangci.yml(在格式化配置上增加 revive)

原先只开了 errcheck、govet 这些,它们都不看名字。revive 的 var-naming 才管包名、下划线和缩写。默认表里的 ID 与 URL 不要删。

version: "2"

linters:
  enable:
    - errcheck
    - govet
    - ineffassign
    - staticcheck
    - unused
    - revive

  settings:
    revive:
      rules:
        - name: var-naming
          severity: error
        - name: exported
          severity: warning

pyproject.toml(在格式化配置上追加 N)

用 extend-select 在基线之上追加,不要重写 select——重写会把质量门禁里那几项静默关掉。命名只加 N 一组;复杂度相关的那两条由复杂度那一页负责。

[tool.ruff.lint]
# 基线:select = ["E", "F", "I", "B", "S", "C901"]
extend-select = ["N"]

frontend/eslint.config.mjs(加在 eslintConfigPrettier 之前)

recommended 不含这一条。把占位参数写成 _note 时,要加 leadingUnderscore: "allow",否则会误报。

{
  rules: {
    "@typescript-eslint/naming-convention": [
      "error",
      { selector: "function", format: ["camelCase"] },
      {
        selector: "variableLike",
        format: ["camelCase"],
        leadingUnderscore: "allow",
      },
      { selector: "typeLike", format: ["PascalCase"] },
    ],
  },
},

.editorconfig 的 [*.cs](常量用 PascalCase)

不符合时诊断号是 IDE1006。要让它阻断,命令里带 --severity warn,见本节末尾。

[*.cs]
dotnet_naming_rule.constants_should_be_pascal_case.severity = warning
dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
dotnet_naming_rule.constants_should_be_pascal_case.style = pascal_case_style

dotnet_naming_symbols.constants.applicable_kinds = field
dotnet_naming_symbols.constants.required_modifiers = const

dotnet_naming_style.pascal_case_style.capitalization = pascal_case

四条命令(并进 make check 的对应目标)

golangci-lint run
ruff check --select N .
npm --prefix frontend run lint
dotnet format csharp/App.csproj --verify-no-changes --severity warn

工具查不到的边界:这些规则只认形状,不认含义。handleData 能过全部四条检查,因为它的形状完全合规。名字说的是不是业务含义,工具看不出来——下一节有一条命令把它筛出来。

工具查不出的三类,评审改看什么

检查跑绿之后,评审时只剩三个问题。前两类用一条命令就能从改动差异里筛出来,第三类要打开调用处读一遍。

类别可识别现象评审动作
通用词占位名字里出现 data、info、manager、handler、utils、helper、common、process在改动差异里跑一次搜索,命中的逐个要求改
缩写与领域不符要打开导入的文件名才能猜出缩写含义,例如 gc()、ns()要求换成领域词:笔记、所属范围、检索模式
名字说的是实现不是含义parseJsonToList、callApiV2。调用方换一种数据来源,名字就错了问一句「它返回的东西,业务上叫什么」

筛出通用词的命令(对本次改动跑)

在仓库根目录执行,只扫新增行。-U0 去掉上下文,命中处不回显旁边没改的代码。命中不等于必须改,但每一条都要给出留或改的理由。

git diff main...HEAD -U0 \
  | grep -nE '^\+.*\b(Data|Info|Manager|Handler|Utils?|Helper|Common|Process|Do)[A-Z_a-z]*'
评审时看这些 评审时只看四类:名字里有没有通用词、缩写看不看得懂、名字跟不跟着业务走、新出现的顶层目录名说没说职责。每条给一个具体的替换建议。
不要再讨论这些 大小写、下划线、包名风格、缩写整词大写。这四类已经进 make check,红了就改,不写进评审意见——写进去等于把工具的活挪回给自己。

工具查不到的边界:上面那条 grep 只抓英文通用词。汉语拼音名(yonghu、bijixiangqing)它抓不到,评审时要逐个看。

助手交出来的样子

func handleData(d interface{}) interface{} { ... }
func processInfo(req *Request) (*Response, error) { ... }
type Item struct {
    Data map[string]interface{}   ← 什么都装得下,也就什么都不说明
}
var mgr = NewManager()

认它的办法:只看名字,能不能说出它属于哪个业务、做什么、返回什么。这四个名字形状全部合规——长度、缩写、大小写,工具一条都挑不出来,正因为它们形状合规。工具认形状,业务含义只有人能判;handleData 能过全部四条检查,这句反过来说就是:形状检查对命名里的业务含义毫无帮助。

必须死守的四条

这四条工具判不了,也不能靠「以后注意」。

一个词只指一件事同一个概念在仓库里只允许留一个名字。列名 scope_id 与代码里的 scopeID 算同一个词,文档里不许出现第二个说法。违反后果:后面的改动在两种写法之间漂移,检索和重构都会漏掉一半。
不做无依据的缩写缩写只能来自领域术语,或该语言的内置缩写表。判据:把这个名字发给一个没读过这段代码的组员,问他能不能说上来是什么。违反后果:新人接手先花时间建一张自己的缩写表。
拼音不进仓库变量、函数、文件、分支都不许。判据:跑 git ls-files | grep -E '[a-z]+(yi|xiang|shu|biao)',输出应为空。违反后果:检索时得同时试两种拼法。
名字跟文件里已有的写法一致新文件跟同目录已有文件的风格,不引入第二套。判据:看同一个包里有没有两种命名风格。违反后果:评审时要先判断谁对,多一轮往返。

工具查不到的边界:第二条在数学与算法代码里放宽。n、m、x 这类符号是领域惯例,改成 itemCount 反而更难读。放宽只限这些符号本身,不扩展到业务代码。

各语言的大小写总表

不要跨语言抄写法。Java 的 MAX_PACKET_SIZE 抄到 Go 和 C#,会同时违反这两门语言各自的检查。

语言函数、方法类型、类常量文件
GoOpenNoteMaxPacketSizenotes.go
TypeScriptlabelNotemaxPacketSizenote-store.ts
Pythonload_noteNoteMAX_PACKET_SIZEnote_store.py
JavaloadNoteNoteMAX_PACKET_SIZENote.java
C#LoadNoteStoreMaxPacketSizeNoteStore.cs
RustopenNoteMAX_PACKET_SIZEnote.rs

Rust 里把函数写成 Open,编译器报 non_snake_case,代码格式里的 cargo clippy -D warnings 会因此失败。排版工具不改名字,改名字由人负责。

什么时候允许例外

下面四种是本仓库承认的例外,其余按必须死守的四条处理;用例外时在评审意见里写明属于哪一种。

允许 循环与索引的 i、j、k;数学与算法里的 n、x;数据库已有列名与第三方接口字段名(scope_id 在 SQL 里保持下划线写法,不为了统一改成 scopeId);测试里的占位参数 _note(TS 需配 leadingUnderscore: "allow")。
不允许 拼音与英文混写;非循环位置的单字母(a、b、tmp);把 NoteStore 缩成 NS 只为少打字;同一概念在不同文件里用两种缩写;把「以后再改」当作例外。

工具查不到的边界:外部字段名这条例外只覆盖映射层。Note.scopeID 这个 Go 字段仍按 Go 的表写;只有写 SQL 和解析响应那一处用列名原文,并且用一处常量或结构体标签集中表达映射,不让下划线写法扩散到业务代码。