playbook/docs/tsl/naming.md

241 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TSL 命名规范Naming
本仓库命名规则与 Google C++ Style
Guide 对齐:通过名字的“形状”快速判断实体类型(类型/函数/变量/常量等),减少阅读成本。
## 1. 选名原则
- **可读一致**:名字清晰可读,并随可见范围调整具体程度。
- 可见范围越大(越对外),名字越应具体、少省略。
- 本指南中“对外可见”指:`unit interface`、`class public`、顶层 `function`
- **标识符语言**:标识符(类型/函数/property/变量/参数等)统一使用英文;禁止中文与拼音(注释可中英混合,见
`docs/tsl/code_style.md`)。
- **少用生僻缩写**:能写全称就写全称。
- 允许使用团队已约定、大家都懂的常见缩写;若缩写不够通用,优先写全称或在评审/文档中先达成约定。
- **驼峰/帕斯卡中的缩写规则**:缩写(首字母缩写/词组缩写)在
`PascalCase`/`camelCase`
中**按一个单词处理**,写成“首字母大写其余小写”,不要写一串全大写。
- 示例:`UserId`(不是 `UserID`)、`UrlTable`(不是 `URLTable`)、
`StartRpcServer`(不是 `StartRPCServer`)、`HttpClient`(不是
`HTTPClient`)。
- **避免无意义词**:如 `data`、`info`、`tmp`、`handle` 等。
- 可以作为限定词的一部分(例如 `user_data`),但不要单独用作名字(例如仅叫
`data`)。
## 2. 命名风格总览
对于以下规则,“单词”指英文中不带空格的词。
- `snake_case`:全小写,下划线分隔单词,用于普通变量/参数等;私有类成员变量使用
`snake_case_`(见 5.2)。
- `PascalCase``UpperCamelCase`):每个单词首字母大写,无下划线,用于类型、顶层函数/“动作型”方法、property以及少量公有成员字段访问器/设置器方法见 7 的例外约定)。
- 自定义标识符只使用本指南约定的 `PascalCase`/`snake_case``lowerCamelCase`
仅用于沿用内置/标准库/第三方 API 的既有命名。
**大小写与关键字约定**
- TSL 语言大小写无关,但本指南仍要求按约定使用大小写以提升可读性;不要用仅大小写不同的名字区分不同实体;同一标识符在仓库中应保持一致写法。
- 所有语法关键字统一使用全小写书写,例如
`if`、`for`、`class`、`function`、`unit`、`return` 等。
- 调用内置/标准库/第三方 API 时,推荐保持对方官方大小写形式(`aaBBCC`/lowerCamelCase例如
`getSysParams("xxx")`;自定义 wrapper 仍按本指南使用 `PascalCase`
## 3. 类型命名Type Names
TSL 的顶层声明只有三种:`class`、`unit`、`function`(仅适用于 `.tsf`)。因此
`.tsf` 文件基名必须与顶层声明同名见“4. 文件命名与顶层声明”)。
- **类class与单元unit**使用
`PascalCase`,不带下划线;名称应为名词/名词短语(通常单数),避免动词开头。
- 不推荐 `*Unit` 作为 `unit` 的后缀(`unit`
本身已表达语义);需要表达用途时,可使用 `*Shared`/`*Common`/`*Enums`
等更具体后缀(按团队约定)。
- **顶层函数function**使用 `PascalCase`;名称优先动词/动词短语(例如
`Load`/`Parse`/`Build`),详见函数命名章节。
- 示例:`UserAccount`、`OrderShared`、`LoadMarketData()`。
## 4. 文件命名与顶层声明File Names
TSL 的语法要求(仅 `.tsf`):每个 `.tsf`
文件只能有一个顶层声明,且**文件基名必须与该顶层声明名字一致**。
- 顶层声明可能是 `class`、`unit` 或 `function`(见类型命名)。
- `.tsf` 代码文件:用于库/模块等“顶层声明”的承载文件;顶层声明可为
`class`/`unit`/`function`,文件基名需与之同名。
- `.tsl` 脚本文件:用于入口/编排层;允许直接写语句(如
`a := 1; echo a;`),不要求顶层声明,也不强制文件基名与函数名一致;可复用逻辑应下沉到
`.tsf`(见 `docs/tsl/code_style.md`)。
- 注:`.tsf` 也是 TSL 源文件,命名/风格与 `.tsl` 遵循同一套规则。
- **硬规则(仅
`.tsf`**:重命名顶层声明时必须同步重命名文件基名,否则语法/加载规则无法识别;批量重命名可参考
`$bulk-refactor-workflow`
命名建议:
- 基名统一使用 `PascalCase`,与顶层声明的推荐写法一致。
- 示例:
- `LoadMarketData.tsl` 中定义 `function LoadMarketData(...)`.
- `UserAccount.tsf` 中定义 `type UserAccount = class ... end;`.
- `DocxEnumerations.tsf` 中定义 `unit DocxEnumerations; ... end.`
- `ParseConfig.tsf` 中定义 `function ParseConfig(...)`.
TSL 大小写无关,实际编译时按大小写比较不会出错,但仍应保持文件名与声明名的推荐写法一致以便检索与协作。
## 5. 变量命名Variable Names
### 5.1 普通变量与参数
- **局部变量、函数参数、非成员变量**使用 `snake_case`
- 若参数名与 TSL 关键字冲突导致编译失败,使用前导下划线的 `snake_case`
作为例外,例如 `_type``type` 是常见冲突关键字)。
- 前导下划线 `_`
**仅用于上述关键字冲突的参数场景**,不要用于其他局部变量、成员变量、函数/类型/单元名称或全局变量。
- 建议把单位写进名字(尤其时间/金额/比例):例如
`timeout_ms`、`spread_bp`、`ratio_pct`。
- 示例:`table_name`、`max_retry_count`、`user_id`(短名例外见 5.5)。
### 5.2 类成员Class Data Members
- **私有成员变量**使用 `snake_case_`(尾随下划线)。
- 尾随下划线 `_`
**仅用于私有成员变量**不要用于局部变量、参数、公有成员字段、property 名称或顶层全局变量。
- **公有成员变量**若必须存在,使用
`PascalCase`;但**不推荐外部直接访问公有字段**。
- 对外暴露的成员优先使用 **property**
- property 名称使用 `PascalCase`(视为对外 API
- property 的 `read/write` 指向真实成员(通常为私有 `snake_case_`)。
- 布尔 property 使用 `Is`/`Has`/`Can`/`Should` 等前缀的 `PascalCase`(例如
`IsReady`),对应私有成员可用 `is_ready_` 等。
- 示例:
```tsl
type User = class
public
property UserId read user_id_ write user_id_;
property IsReady read is_ready_; // bool property example
private
user_id_;
is_ready_;
end;
```
### 5.3 全局/静态变量
- 不推荐使用顶层全局/静态可变变量;优先封装到 `unit`/`class`
中,通过函数或 property 访问。
- 合理例外(仍需集中管理,避免到处读写):
- 进程级只读配置缓存(启动后不再变)。
- 有上限/可清理的缓存(明确容量/TTL/清理点)。
- 指标/计数器(只增不减,或集中在少数写入点更新)。
- 若必须声明顶层全局/静态可变变量:
- 命名仍使用 `snake_case`(不使用 `g_` 前缀)。
- 必须在声明处写注释说明:它是什么、用于什么、以及(如不明显)为什么需要是全局/静态。
- 建议补充写入点与生命周期:谁会写、何时写、何时清理/重置;如涉及并发,写明并发假设/保护方式。
- 不要在注释/日志中写入任何敏感信息(参考 `.agents/tsl/auth.md`)。
- 示例(注释模板,按需裁剪):
```tsl
// <var_name>: <what it is>
// Used for: <what it is used for>
// Global because: <why it needs to be global (if unclear)>
```
- 全局/静态常量仍按常量规则使用
`kPascalCase`(建议同样写一句用途注释,便于检索与维护)。
### 5.4 布尔变量
- 布尔变量建议区分两类语义:
- **状态/谓词predicate**:描述“是否满足某条件/是否处于某状态”,使用
`is_ / has_ / can_ / should_` 等前缀表达语义。
- 示例:`is_ready`、`has_error`、`can_retry`。
- **选项/开关flag/option**:描述“是否启用某行为/模式”,允许使用不带 `is_`
`snake_case` 短语(更贴近配置项语义)。
- 示例:`dry_run`、`include_header`、`enable_cache`、`use_cache`。
- 尽量使用正向命名,避免双重否定:`is_valid` 优于
`is_not_valid``disable_cache` 这类命名需谨慎(容易在调用点读错)。
### 5.5 短名例外
- 在极小作用域内可用习惯短名:仅限 `for/while`
的索引变量或约 510 行内的临时值。
- 允许短名清单(建议严格执行):`i/j/k`(索引)、`n`(计数);其他一律使用有含义的名字。
- 作用域一旦扩大(跨多个分支/循环、跨函数、跨文件),必须改为有含义的名字。
### 5.6 集合与复数命名Collections
- **数组/列表/可迭代集合**使用复数名词的 `snake_case``users`、`order_items`。
- 若复数形式不直观或为不可数名词,使用后缀明确类型:`news_list`、`price_items`。
- **映射/字典key→value**使用 `snake_case` 并加后缀 `_map`;必要时可用
`_by_<key>` 表达键语义(仍需保留 `_map``user_map`、`price_by_symbol_map`。
- **集合/去重集合**使用后缀 `_set``user_id_set`、`symbol_set`。
## 6. 常量命名Constant Names
- **模块级/全局级固定常量**(写死、与入参无关、加载后不变)使用
`kPascalCase`,以 `k` 开头。
- 示例:`kDaysInAWeek`、`kAndroid8_0_0`。
- 常量名建议带单位(尤其时间/金额/比例):例如
`kTimeoutMs`、`kSpreadBp`、`kRatioPct`。
- 对于**局部 const 但值来自参数/运行时**的变量:
- 可用普通变量名 `snake_case`
- 不要用 `k` 前缀误导读者认为其全局固定。
### 6.1 单元枚举模拟Unit Enumerations
TSL 没有内置 `enum`,推荐使用 `unit` + `const``interface` 区域模拟枚举集合。
- `unit` 名称使用 `PascalCase`,建议以 `Enumerations` 结尾表达用途(例如
`DocxEnumerations`)。
- 枚举值使用 `const` 定义并放在 `interface` 中:
- 项目自定义枚举值:默认使用 `kPascalCase`(属于模块级固定常量)。
- 外部/互操作枚举值:允许沿用对方既有前缀与命名(例外场景)。
示例:
```tsl
unit AlertEnumerations;
interface
const kAlertLevelAll = -1;
const kAlertLevelNone = 0;
end.
```
```tsl
unit DocxEnumerations;
interface
// WdAlertLevel
const wdAlertsAll = -1;
end.
```
## 7. 函数与方法命名Function Names
- 顶层函数与“动作型/业务型”方法使用 `PascalCase`
- 访问器/设置器方法(仅当 property 无法表达语义时才使用)允许使用 `snake_case`
的小写形式,以贴近“字段/状态”的语义(按团队约定的例外)。
- **特殊函数/运算符重载为语法固定名,必须使用全小写**
- 构造/初始化函数:`create`。
- 析构/释放函数:`destroy`。
- 运算符重载:`operator+()` 等,按语法使用小写 `operator<op>()` 形式。
- 示例:`AddTableEntry()`、`DeleteUrl()`、`OpenFileOrDie()`。
- **推荐使用 property 语法**对外暴露访问器property 名
`PascalCase``read/write` 绑定成员变量(见类成员章节)。
- 不推荐新增显式 getter/setter仅当 property 无法表达语义时,才使用 getter/setter
- getter与字段同形的 `snake_case`(如 `count()`、`is_ready()`)。
- setter使用 `set_` 前缀的 `snake_case`(如
`set_count(x)`、`set_ready(x)`)。
## 8. 宏与编译期开关Macro Names
- 能不用宏就不用。
- 若项目不支持宏/预处理,本节可忽略;若支持且必须使用,命名为全大写加下划线,并带项目/业务前缀:
- `<PROJECT>_ENABLE_FOO`、`<PROJECT>_USE_BAR`、`<PROJECT>_ROUND(x)`。
## 9. 例外Exceptions
- 当命名需要与外部既有 API/协议保持一致时,可沿用对方风格(例如对接 C/C++ 库、历史接口、跨语言互操作代码等)。
- 不要为了“命名隔离”引入不必要的 wrapper/嵌套;优先保证语义清晰、可检索,并在必要处用注释说明“该命名来自外部约束/协议”。