mcpField
U
ubiquitous-language

ubiquitous-language

github.com/codealive-ai开发16863 次安装3 天前更新
代码仓库

关于 ubiquitous-language

用于维护项目术语表的开发技能,帮助团队在代码、文档、API 和交流中保持命名一致。它先查找既有规范,再依据术语表、代码证据和用户决策处理新名称、旧名称及未决术语。

主要功能

  1. 01维护项目术语单一来源
  2. 02命名前检索现有术语
  3. 03区分规范名、禁用名与旧名
  4. 04记录术语定义和上下文
  5. 05支持术语表生成与迁移
  6. 06提供命名审计和历史挖掘

适用场景

  1. 01为代码实体和 API 选择名称
  2. 02统一团队领域词汇
  3. 03处理代码与术语表冲突
  4. 04审查或更新项目术语表

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/codealive-ai/ai-driven-development --skill ubiquitous-language

安装后在 Claude Code 中输入/ubiquitous-language确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
references/
generating-thesaurus.md
git-history-mining.md
naming-audit.md
scripts/
git_term_index.py

详细介绍

通用语言:项目术语表管理器

通过维护一份持续更新的术语表,并在每次需要命名时查阅它,确保整个代码库中的命名一致。

四种模式:

  • 命名咨询(频繁)——本文件中的全部内容
  • 术语表生成(罕见)——阅读 references/generating-thesaurus.md
  • 命名审计(定期)——阅读 references/naming-audit.md
  • 历史挖掘(可选)——当 ## Unresolved 中的条目需要证据时,阅读 references/git-history-mining.md:哪个名称先出现、哪个替代了哪个、哪个正在被弃用。生成术语表后会提供此模式,也可随时针对现有术语表按需使用。

基础

此技能结合了两套知识体系:

  • Eric Evans 的领域驱动设计(DDD)——通用语言、有界上下文、聚合命名
  • 第一性原理框架(FPF)——一个跨学科的“思维操作系统”,提供语义精确性的形式化工具:将有界上下文作为声明式语义框架、多义词拆解、词汇防火墙、带有损失说明的跨上下文桥接、术语连续性关系,以及防止命名膨胀的控制机制。诸如“FPF F.5”或“FPF A.1.1”的引用,指向 FPF 规范中的特定章节。

核心原则

“项目应使用一套统一、共享的词汇。代码、文档、API 和交流中的每个名称, 都必须对应术语表中的一个术语。如果某个概念不在术语表中——先将它加入术语表, 再进行命名。”

——领域驱动设计,Eric Evans

**代码库是首要证据,但并非自动具有权威性。**通过代码了解当前流通的术语。使用术语表和用户输入来决定哪些术语应当成为规范术语。

  • 对于当前存在的内容——从代码中提取(类、数据库架构、API 路由、事件)
  • 对于应当成为标准的内容——询问用户或领域专家
  • 如果代码与已批准的术语表冲突——新增代码应以术语表为准
  • 如果用户说“修正遗留命名”——用户指示优先于代码库;将现有代码名称映射到 ## Legacy 条目,并以用户提供的术语作为规范术语

隐性知识:对于尚未实现的领域,最重要的领域知识只存在于专家的头脑中,而非任何资料中。

术语表文件

查找术语表:

  1. 如果用户指定了路径——使用该路径
  2. 如果仓库中的某处已存在 THESAURUS.md——使用该位置
  3. 默认路径:docs/THESAURUS.md

领域词汇的唯一事实来源。

版本管理

词库会在 YAML frontmatter 中声明其格式版本和维护它的技能——机器可读,位于正文之外,用 grep 搜索也只需一步:

---
thesaurus-format: "2.0"
skill: ubiquitous-language
---

# Project Thesaurus

请给版本加引号——不加引号的 2.10 会被 YAML 解析为浮点数 2.1。

  • rg -n '^thesaurus-format:' THESAURUS.md → 一次命中即可找到版本。没有键 = 1.0 (即技能 2.0 发布前采用的前置索引文本布局)——除非文件中已有 - **Term** `Id` kind: 索引行:这表示它是插件 9.2.0 中未标记版本的 2.0 文件; 只需添加版本标记。
  • 格式主版本号 = 技能主版本号(本文件 frontmatter 中的 metadata.version)。技能 的次版本和补丁版本发布不会更改格式。
  • 读取任何不高于自身版本的格式;写入时仅使用当前格式。主版本不匹配意味着必须先迁移(参见 generating-thesaurus.md);次版本不匹配意味着存在新的可选标记——旧版读取器仍可正常工作,编辑相关行时可以添加这些标记。
  • 格式版本高于自身版本的词库:可以读取,但不要改写——告知用户更新技能。
  • 文件中只记录格式版本,不记录技能本身的版本——每次编辑都会导致其过时,而 git log 已能回答“是谁写的”。skill: 是一个指针,让没有该技能的 Agent 知道要安装什么。
格式布局技能
1.0### Term 条目,包含 Synonyms to AVOID;## Legacy Terms 条目;## Forbidden Lexicon 表格≤ 1.x(插件 ≤ 9.1.1)
2.0优先 grep:## Index 行,包含 kind:/ctx:/avoid:、use: Forbidden 行、→ Legacy 行、SKOS 桥接2.x
布局:优先 grep

该文件的设计目标是:对任意名称执行一次 rg/grep,即可回答“这个名称应该怎么处理?”,无需阅读周围文本。固定顺序的五个区段:

区段形式单行即可回答
## Index每个概念一行“有这个术语吗?哪个名称是规范名称?哪些名称被禁止?”
## Terms### Term 条目“它的确切含义是什么/不是什么/与什么有关?”
## Forbidden每个词一行“这个词能用于域名吗?”
## Legacy每个旧名称一行“代码中有这个旧名称——它被什么替代了?”
## Unresolved### Term — 问题 条目“这个名称仍是一个待解决的问题吗?”

注册表不变量:项目已知的每个名称都恰好出现在一条注册表行中——Index 行(作为 Term、Identifier 或 avoid)、Forbidden 行、Legacy 行或 Unresolved 标题。每种注册表行都有自己的形式,因此,命中行的形式会告诉你它的状态,行本身会告诉你规范名称。无需 -B/-A 上下文。

注册表行是带标签标记的项目符号行,而不是 Markdown 表格:表格需要使用 |(这是 rg 中的交替匹配符),按列位置匹配,并会被格式化工具重新填充。标记(kind:、ctx:、avoid:、use:、in:、→)不受位置限制、不受格式化工具影响,也无需转义。

# Project Thesaurus

## Index

- **Order** `Order` kind:aggregate avoid: `Purchase`, `Transaction`, `Buy`
- **Order Line Item** `OrderLineItem` kind:entity avoid: `LineItem`, `OrderItem`, `Item`
- **Order Placed** `OrderPlaced` kind:event avoid: `OrderCreated`, `NewOrder`

## Terms

### Order
- **Definition**: A customer's confirmed request to buy one or more products at agreed prices.
- **NOT**: A payment (that's `Payment`), a shipment, or a draft cart (that's `Cart`).
- **Related**: Order Line Item, Order Placed, Cart

## Forbidden

- `Manager` use: `OrderFulfillment` — hides responsibility; name the activity

## Legacy

- `UserManager` → `Customer` + `CustomerRegistration` in: `src/legacy/` — split in v3

## Unresolved

### Account — one word, two concepts (billing vs auth)
- **Found in**: `billing/Account.ts` (balance), `auth/Account.ts` (login)
- **Question**: Two bounded contexts, or one of them a naming mistake?
- **Impact**: 18 files
- **Options**: `BillingAccount` + `UserAccount`; or contexts Billing / Identity
索引行
- **<Term>** `<Identifier>` kind:<kind> [ctx:<Context>] [avoid: `<name>`, `<name>`]
字段内容规则
术语领域专家使用的名称,以 **粗体** 显示可以由多个词组成,也可以是非英语名称。同时也是条目的 ### 标题文本
标识符PascalCase 代码形式,以反引号括起在代码中搜索的内容。其他所有大小写形式都由它按规则生成(参见大小写)
kind:以下选项之一:aggregate entity value event command query service role process state policy concept决定下面的命名规则。没有合适选项时使用 concept
ctx:有界上下文名称只有在确认上下文后才出现(参见 generating-thesaurus.md);标题随即变为 ### 术语(上下文)
avoid:禁用的同义词和缩写,每项以反引号括起,并以逗号分隔放在行末,因为它是唯一长度可变的字段。为空时省略
  • 每个概念占一行。 该概念的所有名称都放在这一行上——这样反向查找(rg Purchase →“使用 Order”)只需一次命中。
  • 每个类似标识符的名称都用反引号括起。 rg '`Order`' 是精确匹配; rg Order 还会匹配 OrderLineItem 和 Reorder。rg -F '**Order**' 可精确匹配术语。
  • 按术语的字母顺序排序。 ## Terms 下的条目也遵循相同顺序。
  • 禁用名称列表只放在这里。 条目中不重复列出——集中一处,避免不一致。
禁用名称和旧名称行
- `<Word>` use: `<Identifier>`[, `<Identifier>`] — <why>
- `<OldName>` → `<Identifier>`[ + `<Identifier>`] in: <files/modules> — <note>
- `<OldName>` → — (see `<X>`, `<Y>`) in: <files> — retired

use: 始终指向索引中的标识符。→ 是旧名称标记:A + B 表示旧名称已拆分;→ — 表示已弃用且没有单一继任名称。

条目
### [Term]
- **Definition**: What this concept means in the business domain — one sentence
- **NOT**: What this term does NOT mean; name the neighbouring term it is confused with
- **Related**: Other Index Terms this connects to, written exactly as in the Term field

仅在能提供实际信息时添加可选行:**更广义**、**更狭义**、 **组成部分**、**包含部分**、**示例**。只在一侧填写——rg 会自动提供反向查找结果;镜像副本只会逐渐不一致。最简可用条目只有一行: - **定义**:…——其余信息已包含在索引行中。

锚点语法(确保查找只需一个正则表达式):标题必须恰好是 ### <术语> 或 ### <术语>(<上下文>),不得有其他内容。标签、状态和上下文前缀应放在索引行中,而非标题里。使用 rg -n '^### Order( \(|$)' 查找条目——单独使用 \b 不够,因为它也会匹配 ### Order Line Item。

术语表记录的是概念,而非行为。 它擅长记录名词(实体名称、角色、流程名称),但不能替代业务规则的行为规范。不要试图把术语表变成规范文档——条目应保持简短。如果某个概念有关键不变量,请在定义中简要注明,而不要另设章节。

非英语领域:如果业务领域使用非英语语言,术语应使用原语言——术语表应反映领域专家实际使用的说法。标识符则采用代码形式: - **Счёт-фактура** `Invoice` kind:entity。这正是两个字段都存在的原因。

查找协议

先查找,再创造。这是最重要的一步。 大多数命名任务都不需要新术语——合适的名称已经存在。

  1. 定位 术语表(见上文)。如果不存在,告知用户并提供生成选项。 检查 rg -n '^thesaurus-format:'——没有键或值为 1.x 表示使用旧版布局:以下协议仍可通过纯文本搜索使用,但请在开始时提供一次迁移选项。

  2. 如果索引不超过约 60 行,阅读索引——它以每个概念一行的形式列出全部词汇,比任何搜索都更省力。对于较大的文件,则改为搜索。

  3. 搜索你正在考虑的每个候选名称,以及周边代码中对该对象的现有称呼。使用 rg(Grep 工具)或 grep -E——模式相同:

    rg -n -i 'invoice' docs/THESAURUS.md             # any role, any section
    rg -n '`OrderLineItem`' docs/THESAURUS.md        # exact identifier as seen in code
    rg -n -F '**Order**' docs/THESAURUS.md           # exact Term (not "Order Line Item")
    rg -n 'avoid:.*`Purchase`' docs/THESAURUS.md     # is this word a banned synonym?
    rg -n 'kind:event' docs/THESAURUS.md             # all terms of one kind
    rg -n 'ctx:Billing' docs/THESAURUS.md            # everything one context owns
    rg -n '`Basket` →' docs/THESAURUS.md             # legacy name and its replacement
    rg -n -A4 '^### Invoice( \(|$)' docs/THESAURUS.md  # the entry itself
    

    唯一的注意点:* 和 | 是正则表达式元字符——搜索 **Term** 时使用 -F,并且不要搜索表格竖线(表格中没有竖线)。

  4. 根据命中行的形式采取行动:

    命中行的形式含义操作
    - **X** `X` kind:… ——你的词是术语或标识符概念已存在完全照用该标识符。停止
    - **X** … avoid: … `你的词` 你正准备使用一个被禁用的同义词改用该行中的标识符
    - `word` use: …该词不能用于领域名称选择 use: 后面的标识符
    - `word` → …代码中仍在使用旧名称新代码使用 → 后面的替代名称;不要传播旧名称
    ## Unresolved 下的 ### word — …尚未解决的命名问题不要擅自决定——明确提出问题、询问用户,或提供历史记录挖掘选项(见下文)
    仅有 ### 标题/条目文本相关概念阅读条目;它可能有助于构词
    没有命中新概念转到“如果概念是新的”
  5. 如果索引行带有 ctx:,检查限定上下文——同一个词在一种上下文中可能是规范用语,在另一种上下文中则可能被禁用。

命名以下内容之前,始终先执行此流程:类、接口、类型、枚举、聚合、实体、值对象、函数、方法、命令、查询、领域事件、变量、常量、字段、参数、数据库表/列/集合、API 端点和响应字段、文件、目录、模块、包、功能标志、配置键、环境变量,以及引用领域概念的提交消息或 PR 标题。

如果概念是新的

创建新术语之前,先尝试四种方法(摘自 FPF F.14“少命名,多表达”):

  1. 复用——是否已有术语涵盖了这个概念?它可能只是某种变体,而不是新事物。
  2. 组合——能否组合现有术语?OrderLineItem 复用了 Order + LineItem。
  3. 限定——这是否是在不同状态/时间窗口下的同一概念?不要创建 NightOperator——使用 Operator 并添加时间限定词。
  4. 询问——如果仍不清楚:“我需要为[概念]命名。术语表中没有对应术语。这个领域怎么称呼它?” 如果用户也没有答案——这不是死胡同,而是一个空白点。 构建通用语言是一种共同创造,而不是提取过程。将其加入 ## Unresolved,并在标题中添加 [WHITE-SPOT] 标签。不要强行给未定义的概念命名。

只有在这四种方法都行不通后,才创建新术语:

  1. 命名不变量所确立的事实(FPF F.5)——不要命名愿景。如果代码没有强制“Premium”条件,就不要称其为 PremiumCustomer。
  2. 采用最小范围的泛化——选择规则确实得到强制执行的最狭义名称。不要为了显得普适,就把 Task 升级为 Activity。
  3. 控制在 1 到 3 个词——不要使用带有修辞意味的形容词(如“稳健”“最优”“高级”)。
  4. 将其加入术语表:添加一行索引(术语、标识符、kind:、avoid:;如果为空则省略 avoid:),并且添加一个至少包含定义的 ### Term 条目。两者都要按顺序排列。
  5. 然后在代码中使用该术语。

如果发现不一致

如果现有代码使用的术语与术语表相矛盾:

  • 标记出来:“发现了 fetchPurchases(),但索引行写的是 Order,并在 avoid: 下列出 Purchase”
  • 如果影响范围较小,建议重命名
  • 如果涉及大规模重命名,将其记为技术债务,并询问用户如何处理

如果歧义无法自行消解

当名称被列入 ## Unresolved 时——一个概念有两种拼写、一种拼写对应两个概念,且没有明显的首选项——当前代码树无法解决这个问题,但仓库历史往往可以:哪个标识符最先出现、哪个提交在添加一个标识符的同时移除了另一个、哪个正在消亡。

提出建议,不要悄悄执行。 每当你展示 ## Unresolved 项目时——生成后、审查后,或遇到命名问题时——都只需提出一次:

“我可以挖掘这些内容的 git 历史——查看每个名称何时出现、哪个替代了哪个,以及哪个在增长、哪个在消亡。会在仓库外创建临时索引,之后删除。要我在你手动回答这些问题前先试试吗?”

如果没有 .git、历史少于约 50 个提交,或历史是从导入时压缩而来,请跳过这项建议;如果这些项目带有 [WHITE-SPOT] 标签(未命名的概念不会留下痕迹),也请跳过。

如果用户接受,请阅读 references/git-history-mining.md 并遵循其中的说明。简要来说:

S=<skill-dir>/scripts/git_term_index.py
python3 $S build --repo-dir . --content   # throwaway SQLite index in $TMPDIR, never in the repo
python3 $S query Account Customer         # birth, dormancy, trajectory, renames, messages
python3 $S pair User Customer             # competing names: birth order + swap commits
python3 $S contexts Account               # where the name lives — the polysemy check
python3 $S search 'rename account'        # BM25 search over commit messages
python3 $S clean                          # delete the index when done

该索引涵盖整个差异历史,因此“出现”指的是首次出现。在大型仓库中使用 --pathspec src/——它既能缩短构建时间,也能同时增强信号。

pair 会以带标签的判定结尾——RENAME(强 / 较可能 / 可能)、DRIFT、 NOT A RENAME、COEXISTENCE——并根据证据推断方向,而非依据参数顺序。按原样报告标签,不要将其升级。“RENAME — strong”意味着提交交换了名称,且提交主题说明了这一点;证据较弱的情况都需要先运行 git show。

对于一词多义(一个词、两种含义、两个模块),使用路径拆分:pair 会打印 files: A in N, B in M, both in K,而 contexts <name> 会给出单个词的目录分布。both in 0——没有任何文件曾同时包含这两者——是存在两个界定清晰的上下文的真实证据;共享文件则意味着同义词漂移,这无法仅凭历史解决。**只有工具确实打印出路径拆分时,才能声称存在路径拆分。**仅文件重命名(文件移动了,标识符未变)会出现在 query 的文件重命名部分,而不是 pair 中——两者都要运行。

**历史是证据,不是权威。**它会对候选项排序并引用提交;由用户决定。将建议连同置信度一次性批量报告,只应用获批的内容,并记录每项已应用决定所依据的提交(在 Legacy 行添加 — renamed in a41f2c9,或在条目中添加 - **History**: 行)。

按 DDD 构造分类的命名规则

索引的 Kind 列用于选择规则。

聚合与聚合根(aggregate)

使用业务领域术语。使用单数形式。不添加技术后缀。

GOOD: Order, Invoice, UserAccount, ShoppingCart
BAD:  OrderAggregate, OrderRoot, OrderAggregateImpl, OrderEntity
实体(entity)

使用领域中的单数名词。具有身份标识的事物。

GOOD: OrderLineItem, PaymentTransaction, Customer
BAD:  OrderLineItemEntity, OrderLineItemImpl, OrderLineItemObj
值对象(value)

使用描述不可变概念的单数名词。描述它是什么,而不是它做什么。

GOOD: Money, Email, PhoneNumber, Address, DateRange
BAD:  MoneyValue, EmailValidator, PriceInfo, AmountData
领域事件(event)

过去式动词 + 名词。 表示已发生的事情。

GOOD: OrderPlaced, PaymentCaptured, InvoiceSent, InventoryReserved
BAD:  OrderEvent, OnOrderPlaced, CreateOrder (that's a command)
命令(command)

祈使动词 + 名词。 表示请求执行的操作。

GOOD: CreateOrder, CancelInvoice, ProcessRefund, ReserveInventory
BAD:  OrderCreated (that's an event), NewOrder, OrderCommand
查询(query)

表示提问或检索。使用动词 + 对象,或描述性名称。

GOOD: GetOrderById, FindInvoicesByCustomer, ListPendingOrders
BAD:  RetrieveOrderData, OrderQuery, GetterForOrder
领域服务(service)

根据领域专家熟悉的业务活动命名。

GOOD: InvoiceCalculator, OrderFulfillment, NotificationSender
BAD:  OrderManager, GenericService, HelperService
仓储

可以使用 Repository 后缀——这是基础设施模式。仓储不是术语表中的术语;应以其存储的聚合命名。

GOOD: OrderRepository, InvoiceRepository, CustomerRepository
BAD:  OrderStorage, OrderPersistence, OrderFinder, OrderDao
聚合上的方法

命令(改变状态): 使用祈使动词,不加 “Get” 前缀。

GOOD: order.Cancel(), order.AddLineItem(product, quantity), order.Recalculate()
BAD:  order.CancelOrderMethod(), order.GetCancelled(), order.DoCancelOrder()

查询(只读): 以 Get、Is、Has、Can 或领域动词开头。

GOOD: order.GetTotal(), order.IsExpired(), order.CanBeShipped()
BAD:  order.FetchInfo(), order.CheckData()

需要检测并标记的命名反模式

词汇防火墙:## Forbidden 部分

领域层必须避免使用临时术语、含糊词语和实现细节。词汇表的 ## Forbidden 部分列出了绝不能出现在领域名称中的词语,必须始终将它们替换为具体的领域术语。

含糊词语(领域层中绝不使用)
含糊词语问题修正方式
Info毫无意义的后缀删除:UserInfo -> User
Data无法说明概念使用领域术语:OrderData -> Order
Manager含义模糊,掩盖职责按实际职责拆分
Handler过于通用,意图不明确根据处理的内容命名
Service被过度使用的兜底词使用具体的领域活动名称
Base带来技术干扰删除,改用组合
Item过于通用使用领域术语:Item -> OrderLineItem、Product
Util / Helper暗示设计不佳将逻辑移入领域对象
Object / Obj从不适用删除后缀
Record / Model数据库概念泄漏到领域层使用领域术语
Config / Settings隐藏具体概念的通用容器Config -> LoanProduct,Settings -> NotificationPreferences
领域层中的技术术语

领域代码必须不包含实现细节:

BAD:  MongoOrder, SqlUserRepository, HttpOrderService, OrderDto, OrderEntity
GOOD: Order, OrderRepository (interface), PaymentGateway, Order (just Order)

技术前缀/后缀只能用于基础设施层,即使在该层,领域职责也应放在名称前面:

INFRASTRUCTURE LAYER (OK): MongoOrderRepository, RedisSessionCache, HttpPaymentClient
DOMAIN LAYER (NEVER):      MongoOrder, RedisSession, HttpPayment
NAME THE ROLE, NOT THE TECH: SessionStore not RedisCache, EventPublisher not KafkaProducer

框架注意事项:在有意将领域与持久化结合的框架中(Active Record 模式、以 ORM 为中心的框架),模型本身就是领域实体。保持领域名词简洁,让框架耦合体现在继承、注解或元数据中,而不是类名中。只有当技术术语成为面向业务的名称的一部分,或泄漏到其边界之外时,才应标记为问题。

同义词漂移

同一概念在代码的不同部分被称作不同名称:

PROBLEM: "Customer" in auth, "User" in API, "Account" in billing — all mean the same thing
FIX:     Pick ONE canonical term per bounded context. Put the others in that line's `avoid:` list.
缩写边界

禁止在持久且承载领域含义的名称中使用缩写:类型、导出函数、模块、API 字段、数据库列、事件、配置键。

当含义在作用域内明确时,允许使用惯用的短期局部标识符:i、j、ctx、req、res、err、tx、db,以及表示事件的 e。

当行业标准缩写是主流术语时,允许使用:SKU、VAT、URL、ID、OAuth。如果专家使用缩写,不要强行将其展开成不自然的形式。

PROBLEM: usr, user, account, acct — competing abbreviations for the same durable concept
FIX:     Pick ONE canonical form for domain-bearing names. Short-lived locals are exempt.
翻译链(“传话游戏”)

当知识链中的不同产物使用不同术语指代同一概念时,每次转换都会造成信息丢失:

SMELL: Domain expert says "Campaign" → PM writes "Promotion" in spec →
       Dev codes `marketing_push` → QA tests "advertising effort"
FIX:   Same term everywhere: expert, PM, dev, QA all say and write "Campaign"

这比同义词漂移更糟,因为每次转换还会丢失细微差别和业务规则。**检测方法:**将需求/规范/工单中的术语与代码名称进行比较。如果两者不一致,说明通用语言存在翻译断层——应在各处统一采用领域专家使用的术语。

命名大小写约定

索引中的 Identifier 使用 PascalCase。其他所有形式都依据项目约定从它机械派生,绝不重新措辞:

上下文约定示例(Identifier:OrderLineItem)
类/类型PascalCaseOrderLineItem
函数/方法项目约定addOrderLineItem / add_order_line_item
变量项目约定orderLineItem / order_line_item
常量UPPER_SNAKEMAX_ORDER_LINE_ITEMS
数据库表项目约定order_line_items
API 端点kebab-case 或按约定/orders/{id}/line-items
事件/消息PascalCase,搭配过去时动词OrderLineItemAdded
文件/目录项目约定order_line_item.py、OrderLineItem.cs

关键规则:

  • 使用完全一致的 Identifier——不要缩写(ord)、扩展(orderObject)或使用同义词(purchase)
  • 复合名称由 Identifier 组合而成:使用 OrderLineItem,不要使用 PurchaseLineItem
  • 基础设施角色可以使用技术后缀:OrderRepository、OrderDTO(仅限基础设施层)
  • 多词 Identifier 在各种大小写形式中都保留所有单词:ProcessingStage → processing_stage,绝不使用 proc_stage
  • 变量和参数使用完整且具有描述性的名称:使用 totalAmount,不要使用 amt;使用 customerEmail,不要使用 cEmail

更新同义词表

更改术语时,使用能如实表达含义的最弱关系(参见 FPF F.13):

操作适用情况对同义词表的影响
添加新概念索引行 + 条目。最低要求:Identifier、kind:、定义
重命名措辞改进,含义不变更改索引行和标题中的 Term/Identifier;旧 Identifier → ## Legacy 行 `Old` → `New`;搜索代码库并建议重命名
拆分一个术语涵盖了两种含义移除旧行;添加两条新行及其条目;旧 Identifier → ## Legacy 行 `Old` → `A` + `B`;在各自的 NOT 中进行消歧
合并两个术语实际上表示同一种含义保留其中一行;将另一个 Identifier 移入其 avoid: 列表;合并条目
退役术语会误导,且没有单一的替代术语## Legacy 行 `Old` → — (see `X`, `Y`)
弃用概念正逐步淘汰## Legacy 行,包含 → 替代项和 in: 位置

关键判断:更改前后能否指向同一个概念?

  • 能,概念相同,只是措辞更好 → 重命名(保留为旧代码的遗留别名,供阅读时使用)
  • 不能,概念实际发生了变化 → 拆分或合并(不是重命名)

别名从简:每个术语最多保留 1 个遗留别名,即读者最可能在旧代码中遇到的那个。每次编辑后仍须满足注册表不变量:一个名称只能位于 avoid: 或 Legacy 中,不能同时出现在两者中。

旧版布局? 没有 thesaurus-format 前置元数据键(或其值为 1.x),表示使用索引前的散文布局——参见 references/generating-thesaurus.md 中的“迁移现有同义词表”。

命名之前的快速检查清单

  1. 我是否在同义词词典中搜索了这个名称及其同义词?搜索结果在哪里?
  2. 领域专家能否识别这个名称?
  3. 它是否包含含糊词(Manager、Service、Handler、Info、Data、Item、Base、Util)?
  4. 它是否过于笼统(在不同上下文中可能有多种含义)?
  5. 它是否暴露了基础设施细节(Mongo、Sql、Http、Dto、Entity、Model)?
  6. 它是否与代码库中这个术语的其他用法一致?
  7. 我使用的是索引中的确切标识符,还是 avoid: 列表中的同义词?
  8. 我是否处于该术语所属的正确限界上下文中?
  9. 名称是否符合其类型——event 使用过去时,command 使用祈使语气?
  10. 我能否用领域语言用一句话说明这个名称代表什么?
  11. 如果这是一个新概念——我是否在使用之前添加了索引行和条目?

如果任何答案引发疑虑——请停下来并先修正。

评论

支持 Markdown