安装此技能
npx skills@latest add mattpocock/skills --skill=domain-modeling 然后在你的编码 agent 里输入 /domain-modeling 。
本页目录
它做什么
domain-modeling 在你做设计的时候,构建并打磨一个项目的统一语言(ubiquitous language)。它会挑战一个与词汇表(glossary)冲突的术语,在你用了模糊说法的地方要一个精确的词,并拿一个具体场景检验一种关系,直到边界精确为止。
它是主动的那门纪律,不是被动的那门。任何技能都可以读 GLOSSARY.md 来借用它的词汇。这个技能是给当你正在改变模型(model)的时候用的,这就是它会打断你的原因。它在你把一个术语定下来的那一刻,就在对话中间把它写进 GLOSSARY.md,而不是在最后产出一份整洁的词汇表。最后才写的词汇表是一场会话(session)的摘要;内联的版本才是会话的产出。
什么时候用它
输入 /domain-modeling,或者当一个任务匹配时由 agent 自动去拿它。在实践中,自动调用是这个技能最弱的部分。当 grill-with-docs 或 wayfinder 说去加载它时,模型常常加载 grilling 而跳过这一个。如果一场质询(grilling)会话跑完了,而 GLOSSARY.md 到最后没有变化,那就是发生了这件事。把它和其他技能一起点名调用。
当词就是问题时,用它:
| 情况 | 做法 |
|---|---|
| 两个人对「cancellation」的理解不同 | domain-modeling:选定规范术语(canonical term),把另一个列进 _Avoid_ |
| 「Account」在三个文件里干三份活 | domain-modeling:把它拆成 Customer 和 User |
| 你刚做了一个难以逆转的架构选择 | domain-modeling:如果这个选择够格,它会主动提出一份 ADR |
| 模块的形状是问题:接缝放在哪里,接口有多深 | codebase-design |
| 你想在构建之前把整个计划拷问一遍 | grill-with-docs,它在底下驱动这个技能 |
| 你想查一个术语,而不是改它 | 什么都不用。读 GLOSSARY.md。它是一个文件。 |
前提条件
开始之前什么都不需要。这个技能往两处写入,并且按需创建两者:
- 仓库根部的
GLOSSARY.md。当你定下第一个术语时,技能创建它。在一个根部有GLOSSARY-MAP.md的仓库里,术语改为进入地图所指向的、按上下文划分的GLOSSARY.md。 docs/adr/。技能在第一份够格的 ADR 出现时创建它。
开始之前不需要任何东西存在,技能也不会预先创建任何东西。
两件产物,两道门槛
词汇表和 ADR 有各自不同的门槛。这个技能的大部分麻烦都来自把两者混为一谈。
GLOSSARY.md | docs/adr/NNNN-slug.md | |
|---|---|---|
| 存放 | 术语。一件东西是什么,用一两句话,把被拒绝的同义词列在 _Avoid_ 下 | 一个决定,用一到三句话:背景、选择、理由 |
| 写入门槛 | 一个模糊的术语变成了规范说法 | 三者全部:难以逆转、没有上下文会令人意外、是真实权衡的结果 |
| 何时写 | 内联,术语定下来的那一刻 | 主动提出,不擅自假定 |
| 绝不存放 | 实现细节、一份规范文档(spec)、草稿纸、通用编程概念 | 本次会话每一个选择的日记 |
ADR 的三项测试只要漏掉任何一项,就不写 ADR。一个容易被逆转的决定反正会被逆转;一个不令人意外的决定不是任何人的问题;一个没有真实替代方案的决定,只是记录了你做了显而易见的事。
GLOSSARY.md 的规则最重要,因为它是在实践中会坏掉的那一条。它是一份词汇表,别的什么都不是。 不加约束的话,模型会把「写进 GLOSSARY.md」当成许可,把你给出的每个答案都持久化,文件就变成一份不断生长的规范文档。这是关于这个技能报告得最多的问题,跨越好几个模型。
交叉对照,以及它止步的地方
当你说某件事是如何工作的,技能会检查代码,并指出任何矛盾。「你的代码取消整个 Order,但你刚说部分取消是可能的,哪个才对?」 技能会让语言和代码在改变任何一方之前,先公开地达成一致。
它交叉对照代码、以及已提交的 GLOSSARY.md 和 ADR,别的什么都不查。它不搜索你的 issue 追踪器(issue tracker)。如果你的团队几个月前在一个已经关闭的 issue 里争论出一种命名冲突并解决了它,技能会把它当作新问题重新提出来。有一个开放的请求要修这个。在那之前,变通办法是把这条指令放进你自己的 docs/agents/domain.md,那些技能已经会读它。
常见问题
我的 GLOSSARY.md 有 500 行。1,000 行。3,000 行。我该怎么办?
大小是症状。原因是这个文件吸收进了实现细节和那些从来不属于词汇表的决定。修法是一条直接的指令:/grill-with-docs make my GLOSSARY.md more concise and remove any implementation details from it。拿它去跑一个臃肿的文件,大部分内容都会消失。只有在这个文件已经精瘦、却仍然覆盖两个读者不愿同时装进脑子里的领域时,才用 GLOSSARY-MAP.md 拆分它。拆分一个臃肿的文件,得到的是好几个臃肿的文件。技能在这方面的指引还不够强,无法从一开始就阻止它膨胀,追踪这件事的 issue 仍然打开。
为什么是 GLOSSARY.md 而不是 CONTEXT.md?
在 1.3.0 之前它是 CONTEXT.md(以及 CONTEXT-MAP.md)。这个文件是一份词汇表,别的什么都不是,所以 GLOSSARY.md 就把这一点说出来了,而且,正如一位读者所说,「有了 AI agent,一切都是上下文(context)」。如果你的仓库里还有 CONTEXT.md,重新运行 /setup-matt-pocock-skills:它会主动提出 git mv 这个文件,并更新 docs/agents/domain.md。这套技能里的每一个都找 GLOSSARY.md,所以保留旧名字意味着要给它们全部打补丁。
/ubiquitous-language 去哪了?
它被移除了,而且不是弃用。它的职责搬进了 domain-modeling,后者持续维护整个模型,而不是从某一场对话里倒出一份词汇表。词汇管控现在更重要,而不是更不重要。它运行在质询、分诊和绘制地图的底下,而不是作为一遍你需要记住的单独流程。
我怎么给一个原本没有词汇表的代码库弄一份?
明确地去要,而不是等它慢慢积累。/grill-with-docs help me scaffold my existing repo with a GLOSSARY.md 是文档给出的路线。预期一场很长的拷问。一位用户报告说,在文件成型之前问了 50 多个问题。在一个棕地(brownfield)仓库上,顺带使用会让词汇表积累得慢得多。
我能保留领域模型(domain model),同时用自己的 ADR 格式吗? 目前不能干净地做到。词汇表那一半和 ADR 那一半发布在同一个技能里,所以一个有既定 ADR 约定的团队(不同的模板、不同的位置、不同的命名)会拿到与自己的团队风格冲突的指令。当前的选择是在本地复制这个技能并修改它,或者在你仓库自己的 agent 文档里覆盖 ADR 约定。把两者拆开是一个开放的请求。
词汇表真的值它占的位置吗?它只是又一件要审查的产物,而且可能会过时。 有时候它不值。DDD 越接近实现,就越没用。回报在上游,在命名和概念对齐上,而不在聚合(aggregate)与分层仪式上。同义词管控在命名边界上很重要:模块名、表名、状态枚举、issue 标题、CLI 命令。它在普通散文里远远没那么重要。还有一种反对意见说,领域术语压缩的是已经共享这些术语的人之间的沟通,而 agent 对平实的日常语言描述会做出同样的反应。按这种解读,词汇表的价值是让你和你的审查者与 agent 正在做的事保持对齐,而不是让 agent 变得更好。在一天的构建里,跳过它。而一份未经审查、由 agent 编写的词汇表比没有更糟:它会填满自信的断言,而后续的会话会把它们当作真的。
它能替我把模糊的提示词变成领域语言(domain language)吗? 不能,也没有计划做一个这样的技能。你自己都不理解的领域语言,一旦写下来就没有意义。这个技能在你已经具备理解之后强制执行精确性;它不会发明你不拥有的词汇。相关的陷阱是只使用领域词汇而不做建模。正确的名词架在错误的概念上,产出的东西读起来正确,实际上不正确。
它生效的标志
- 它在你说话说到一半时打断你,问你指的是两件事里的哪一件,而不是挑一个继续往下走。
GLOSSARY.md在对话进行中就发生变化,而不是在最后爆发式地写一遍。- 它拒绝为一件你明天就可能撤销的事写 ADR,并说明三项测试里哪一项没过。
- 新条目用一两句话定义一件东西是什么,并在
_Avoid_下点名你正在放弃的那些词。 - 当你的代码和你的句子不一致时,它把你的代码引回来给你看。
GLOSSARY.md变短的次数和变长的次数一样多。
它在体系中的位置
domain-modeling 是一份模型调用(model-invoked)的参考(reference),它运行在其他技能的底下,比它单独运行的时候更多。grill-with-docs 通过一场质询会话驱动它,wayfinder 在绘制地图时加载它,triage 用它把工单(ticket)保持在项目自己的词汇里,而 improve-codebase-architecture 在决定落定时调用它。它最亲近的同胞是 codebase-design。两者一起构成其他一切底下的词汇层,这一个管领域,那一个管模块的形状。它也可以被直接触及,当你想要这门纪律、却不想承诺去走那个本来会加载它的技能的步骤时。当你不确定哪个技能合适时,ask-matt 会为你路由。