通用语言
从当前对话中提取并形式化领域术语为一致的术语表,保存到本地文件。
流程
- 扫描对话以查找与领域相关的名词、动词和概念
- 识别问题:
- 同一个词用于不同的概念(歧义)
- 不同的词用于同一个概念(同义词)
- 模糊或重载的术语
- 提出规范的术语表,带有明确的术语选择
- 使用以下格式写入工作目录中的
UBIQUITOUS_LANGUAGE.md - 在对话中内联输出摘要
输出格式
使用以下结构编写 UBIQUITOUS_LANGUAGE.md 文件:
# 通用语言
## 订单生命周期
| 术语 | 定义 | 避免使用的别名 |
| ----------- | ------------------------------------------------------- | --------------------- |
| **Order** | 客户购买一个或多个商品的请求 | Purchase, transaction |
| **Invoice** | 交付后发送给客户的付款请求 | Bill, payment request |
## 人员
| 术语 | 定义 | 避免使用的别名 |
| ------------ | ------------------------------------------- | ---------------------- |
| **Customer** | 下订单的个人或组织 | Client, buyer, account |
| **User** | 系统中的身份验证身份 | Login, account |
## 关系
- 一个 **Invoice** 属于且仅属于一个 **Customer**
- 一个 **Order** 产生一个或多个 **Invoices**
## 示例对话
> **Dev:** "当 **Customer** 下 **Order** 时,我们是否立即创建 **Invoice**?"
> **Domain expert:** "不——只有在确认 **Fulfillment** 后才生成 **Invoice**。如果商品分多个 **Shipments** 发货,单个 **Order** 可以产生多个 **Invoices**。"
> **Dev:** "所以如果 **Shipment** 在发货前被取消,它就没有 **Invoice**?"
> **Domain expert:** "没错。**Invoice** 的生命周期与 **Fulfillment** 绑定,而不是与 **Order** 绑定。"
## 标记的歧义
- "account" 被用来表示 **Customer** 和 **User**——这些是不同的概念:**Customer** 下订单,而 **User** 是可能代表也可能不代表 **Customer** 的身份验证身份。
规则
- 要有主见。 当同一个概念存在多个词时,选择最好的一个并将其他列为要避免的别名。
- 明确标记冲突。 如果对话中某个术语使用有歧义,在"标记的歧义"部分明确指出并提供清晰的建议。
- 仅包含与领域专家相关的术语。 跳过模块或类的名称,除非它们在领域语言中有意义。
- 保持定义紧凑。 最多一句话。定义它是什么,而不是它做什么。
- 展示关系。 使用粗体术语名称并在明显时表达基数。
- 仅包含领域术语。 跳过通用编程概念(数组、函数、端点),除非它们具有领域特定的含义。
- 当出现自然聚类时将术语分组到多个表中(例如按子域、生命周期或参与者)。每个组都有自己的标题和表格。如果所有术语都属于一个凝聚的领域,一个表格就可以——不要强制分组。
- 编写示例对话。 开发人员和领域专家之间的简短对话(3-5 个回合),展示术语如何自然交互。对话应该澄清相关概念之间的边界并展示术语的精确使用。
示例对话
Dev: "如何在没有 Docker 的情况下测试 sync service?"
Domain expert: "提供 filesystem layer 而不是 Docker layer。它实现了相同的 Sandbox service 接口,但使用本地目录作为 sandbox。"
Dev: "所以 sync-in 仍然创建 bundle 并解包它?"
Domain expert: "没错。sync service 不知道它在与哪个层通信。它调用
exec和copyIn——filesystem layer 只是将这些作为本地 shell 命令运行。"
重新运行
在同一对话中再次调用时:
- 读取现有的
UBIQUITOUS_LANGUAGE.md - 合并后续讨论中的任何新术语
- 如果理解有所发展,更新定义
- 重新标记任何新的歧义
- 重写示例对话以合并新术语