ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

domain-modeling 领域建模技能实战指南:打磨通用语言、维护 CONTEXT.md 与记录 ADR

domain-modeling 领域建模技能实战指南:打磨通用语言、维护 CONTEXT.md 与记录 ADR domain-modeling 领域建模技能实战指南打磨通用语言、维护 CONTEXT.md 与记录 ADR【免费下载链接】skillsSkills for Real Engineers. Straight from my .agents directory.项目地址: https://gitcode.com/GitHub_Trending/skills13/skills本指南完整讲解 Matt Pocock Skills 技能集中domain-modeling的设计原理与实战用法它如何在设计过程中持续构建与打磨项目的通用语言ubiquitous language如何在术语解决的当下把结果内联写入CONTEXT.md以及何时才值得以 ADR 形式记录一项决策。读完本文你将掌握该技能的文件结构、会话内六项核心动作、两套产物的书写规范与判定标准并能在自己的仓库中复现这套词汇层工程实践。核心定位主动的建模学科而非被动的词汇消费domain-modeling的目标是在你设计的同时构建并打磨项目的通用语言当某个术语与词汇表冲突时质疑它当你用了模糊的措辞时逼迫你给出精确的词并用具体场景对概念之间的关系做压力测试直到边界完全精确。它与被动用法之间存在一条清晰的界线阅读CONTEXT.md借用其词汇是一行式习惯任何技能都能做到而本技能服务的是你正在改变模型的那一刻。这也是它会在会话中途打断你的原因——它在一个术语解决的那一刻就把结果内联写进CONTEXT.md而不是在会话结束时批量产出整洁的词汇表。因为批量版本只是一次[会话session]的摘要而内联版本才是会话真正的输出物。什么时候该调用它你可以显式输入/domain-modeling也可以让 Agent 在任务契合时自动调用。在实际使用中自动调用恰恰是这套技能最薄弱的一环当grill-with-docs或wayfinder指示加载它时[模型]常常只加载了grilling而跳过它。如果一次 [grilling] 会话结束后CONTEXT.md仍未被改动那就是发生了这种情况——请显式地按名称调用它。当问题出在词上时就该使用它场景应对两个人对cancellation有不同理解domain-modeling选定规范术语把其他词列入_Avoid_Account 在三个文件里干着三份工作domain-modeling把它拆成 Customer 和 User你刚做了一个难以逆转的架构选择domain-modeling如果它过了门槛就提供一份 ADR问题出在模块的形状上接缝在哪里、接口有多深交给 codebase-design你想在动手构建前对整个方案进行拷问grill-with-docs它在底层驱动本技能你只是想查一个术语、不想改动它什么都不用做。读CONTEXT.md。它就是个文件前置条件一切惰性创建无任何预设启动前不需要任何前置条件。技能只写两处地方且都是惰性创建的CONTEXT.md仓库根目录由第一个被解决的术语创建。如果仓库根目录存在CONTEXT-MAP.md术语则写入 map 指向的各个上下文对应的CONTEXT.md。docs/adr/由第一份通过门槛的 ADR 创建。也就是说开始前什么都不必存在也不会被投机性地提前创建任何文件。这一点与仓库中 domain.md 的消费侧约定互为印证If any of these files dont exist, proceed silently. Dont flag their absence; dont suggest creating them upfront——缺文件时安静继续绝不主动建议提前创建。两种产物、两把尺子词汇表与 ADR 的分野词汇表glossary和 ADR 被要求遵循不同的标准混淆这两者正是本技能实践中大部分麻烦的来源CONTEXT.mddocs/adr/NNNN-slug.md承载内容术语。用一两句话说明某个事物是什么被拒的同义词列在_Avoid_下一项决策一到三句话背景、选择、理由写入门槛一个模糊的术语变成了规范术语三者全部满足难以逆转、脱离上下文令人意外、是真实权衡的结果写入时机内联在术语被敲定的瞬间被提供而非被默认写入永不承载实现细节、spec、草稿纸、通用编程概念本次会话每个选择的流水账ADR 的三项测试缺一不可容易逆转的决定迟早会被逆转不令人意外的决定没人会问为什么没有真实备选方案的决定只是在记录我们做了显而易见的事。而CONTEXT.md那条规则才是真正要牢牢记住的因为它是实践中最先失守的一条它只是词汇表仅此而已。一旦失守模型会把写入CONTEXT.md当作持久化你每一个回答的许可文件就会变成一份持续运转的 spec。据技能文档记载这是该技能在多种模型上被反馈最多的问题。文件结构单上下文与多上下文大多数仓库只有一个上下文见 SKILL.md 中的结构示意/ ├── CONTEXT.md ├── docs/ │ └── adr/ │ ├── 0001-event-sourced-orders.md │ └── 0002-postgres-for-write-model.md └── src/如果根目录存在CONTEXT-MAP.md则仓库有多个上下文map 会指明每个上下文的位置以及哪些 ADR 属于全局、哪些属于具体上下文/ ├── CONTEXT-MAP.md ├── docs/ │ └── adr/ ← system-wide decisions └── src/ ├── ordering/ │ ├── CONTEXT.md │ └── docs/adr/ ← context-specific decisions └── billing/ ├── CONTEXT.md └── docs/adr/创建文件一律惰性只有当你确有内容要写时才创建。若没有CONTEXT.md在第一个术语被解决时创建若没有docs/adr/在需要第一份 ADR 时创建。多上下文场景下技能会推断当前话题属于哪个上下文不确定时直接询问。会话中的六项核心动作来自 SKILL.md 的 During the session 一节定义了会话中的六项动作对照词汇表质疑Challenge against the glossary当用户使用的术语与CONTEXT.md中的既有语言冲突时立即指出你的词汇表把 cancellation 定义为 X但你似乎指的是 Y。到底是哪个打磨模糊语言Sharpen fuzzy language用户使用模糊或过载的术语时提议一个精确的规范术语你说 account你指的是 Customer 还是 User这是两个不同的东西。讨论具体场景Discuss concrete scenarios当领域关系被讨论时用具体场景做压力测试。编造能探测边界情况的场景迫使用户对概念之间的边界保持精确。与代码交叉验证Cross-reference with code当用户陈述某事物如何工作时检查代码是否同意。若发现矛盾把它摆到台面上你的代码整单取消 Orders但你刚说可以部分取消。哪个是对的内联更新 CONTEXT.mdUpdate CONTEXT.md inline术语一经解决就地更新CONTEXT.md不要批量攒起来——让记录随时发生。格式见 CONTEXT-FORMAT.md。CONTEXT.md必须完全不含实现细节绝不当作 spec、草稿纸或实现决策的仓库它是词汇表仅此而已。克制地提供 ADROffer ADRs sparingly只有三项条件全部为真时才主动提议创建 ADR详见下文ADR 三条件。任一条缺失就跳过。格式见 ADR-FORMAT.md。CONTEXT.md 书写规范结构模板CONTEXT-FORMAT.md 给出了标准结构# {Context Name} {One or two sentence description of what this context is and why it exists.} ## Language **Order**: {One or two sentence description of the term} _Avoid_: Purchase, transaction **Invoice**: A request for payment sent to a customer after delivery. _Avoid_: Bill, payment request **Customer**: A person or organization that places orders. _Avoid_: Client, buyer, account四条规则要有主见Be opinionated同一概念存在多个词时选定最佳的那个把其余列入_Avoid_。定义保持紧凑Keep definitions tight最多一两句话。定义它是什么而不是它做什么。只收录本项目上下文特有的术语通用编程概念timeout、错误类型、工具类模式即使项目大量使用也不该收录。添加前自问这是该上下文独有的概念还是通用编程概念只有前者才属于。自然聚簇时用子标题分组若所有术语都属于单一内聚领域平铺列表即可。单上下文 vs 多上下文单上下文大多数仓库根目录一个CONTEXT.md。多上下文根目录的CONTEXT-MAP.md列出上下文、它们的位置及相互关系# Context Map ## Contexts - [Ordering](https://link.gitcode.com/i/f64a4b92676819dba7d5c237adf9cd38): receives and tracks customer orders - [Billing](https://link.gitcode.com/i/f64a4b92676819dba7d5c237adf9cd38): generates invoices and processes payments - [Fulfillment](https://link.gitcode.com/i/f64a4b92676819dba7d5c237adf9cd38): manages warehouse picking and shipping ## Relationships - **Ordering → Fulfillment**: Ordering emits OrderPlaced events; Fulfillment consumes them to start picking - **Fulfillment → Billing**: Fulfillment emits ShipmentDispatched events; Billing consumes them to generate invoices - **Ordering ↔ Billing**: Shared types for CustomerId and Money技能按如下规则推断结构存在CONTEXT-MAP.md就读它找上下文只有根CONTEXT.md就是单上下文两者都不存在则在第一个术语解决时惰性创建根CONTEXT.md。仓库中的真实样例本仓库根目录的 CONTEXT.md 正是这一规范的活样板它定义了Issue tracker、Issue、Decision ticket、Triage role等术语每条都有一两句话的是什么定义与_Avoid_列表例如_Avoid_: backlog manager, backlog backend, issue host并包含## Relationships描述概念间关系以及## Flagged ambiguities记录已被解决的歧义backlog 曾经同时指代承载 issue 的工具和其中的工作体现已裁定只保留Issue tracker一词。ADR 书写规范位置与编号ADR 位于docs/adr/使用顺序编号0001-slug.md、0002-slug.md等。docs/adr/目录惰性创建仅在需要第一份 ADR 时。新增时扫描目录中最大编号并加一。模板可以短到一段话# {Short title of the decision} {1-3 sentences: whats the context, what did we decide, and why.}就这些。一份 ADR 可以只有一段话。它的价值在于记录做过这个决定以及为什么而不在于填满各个章节。可选章节Status 前置元数据proposed | accepted | deprecated | superseded by ADR-NNNN、Considered Options、Consequences仅在确实带来价值时才加入大多数 ADR 用不上。何时提供 ADR三条硬性条件难以逆转Hard to reverse日后改变主意的成本是实打实的。脱离上下文令人意外Surprising without context未来读者看到代码会想他们到底为什么这么做真实权衡的结果The result of a real trade-off存在真实备选方案你基于特定理由选了一个。容易逆转就跳过反正你会再改不令人意外就没人会问为什么没有真实备选就没有可记录的内容除了我们做了显而易见的事。什么才配写入 ADRADR-FORMAT.md 列举了七类合格内容架构形状我们用 monorepo。写模型是事件溯源的读模型投影到 Postgres。上下文之间的集成模式Ordering 与 Billing 通过领域事件通信而非同步 HTTP。带有锁定成本的技术选型数据库、消息总线、认证提供方、部署目标。不是每个库都要记只记换掉要花一个季度的那些。边界与范围决策Customer 数据归 Customer 上下文所有其他上下文只按 ID 引用。明确的不允许和允许同样有价值。对显而易见路径的刻意偏离我们因 X 而手写 SQL 而非用 ORM。任何合理读者会假设相反做法的地方都算。这类记录能阻止下一位工程师修好一个刻意的选择。代码中不可见的约束因合规要求不能用 AWS。因合作伙伴 API 契约响应时间必须低于 200ms。被拒备选方案当拒绝理由并不显然时你权衡过 GraphQL 却出于微妙原因选了 REST就记下来否则六个月后又有人来建议 GraphQL。交叉验证让语言与代码当面对质让这套技能活起来的关键动作是当你陈述某事物如何工作时它会去检查代码并暴露矛盾——你的代码整单取消 Orders但你刚说部分取消是可能的。到底哪个是对的语言与代码被要求在改动任何一方之前当众达成一致。这个边界值得明确它只交叉验证代码与已提交的CONTEXT.md/ADR除此之外不查任何东西。它不搜索你的 issue tracker因此几个月前在一次已关闭的 issue 里被反复争论并刻意定案的命名冲突会被当作新问题重新抛出来。技能文档记载修复该问题的改进请求仍然开放在此之前的变通方案是把相关指示写进你自己的docs/agents/domain.md——这正是 domain.md 所扮演的角色skills 本来就会读取该文件。该文件还规定若输出与既有 ADR 冲突必须显式指出如 Contradicts ADR-0007 (event-sourced orders), but worth reopening because…而不是静默覆盖。常见问题解答我的CONTEXT.md有 500 行、1000 行、甚至 3000 行怎么办体积是症状而非病因文件吸收了一堆本不该是词汇表材料的实现细节与决策。修法是直接下达指令/grill-with-docs make my CONTEXT.md more concise and remove any implementation details from it。对臃肿文件跑一次大部分内容都会消失。只有当文件真正精瘦、却仍覆盖两个读者不想同时捧在手里的领域时才考虑CONTEXT-MAP.md拆分——拆分臃肿文件只会得到几份臃肿文件。技能文档坦承这一块的引导尚不足以从源头阻止膨胀相关的改进问题仍然开放。为什么叫CONTEXT.md而不是GLOSSARY.md这是整个技能集中被争论最多的命名问题至今没有定论。反对现有名字的理由很充分如果它只是词汇表GLOSSARY.md这个名字才名副其实有读者评论说有了 AI Agent一切都是 context。支持它的理由在于 mapCONTEXT-MAP.md指向多个CONTEXT.md的读法远比GLOSSARY-MAP.md自然且 context 本就是 DDD 中表示模型边界区域的常规用词。据记载至少有一个人维护本地 fork 只为重命名该文件——你也可以这么做但技能集里每个技能都去找CONTEXT.md改名意味着要全部打补丁。/ubiquitous-language去哪了被移除了而且是直接移除而非弃用。它的职责并入了domain-modeling后者持续维护整个模型而不是在某次会话结束时倒出一份词汇表。词汇强制并没有变轻反而更承重了——它现在跑在 grilling、triage 与 mapping 的底层而不是作为一项你记得才做的独立流程。如何为一个没有任何词汇表的代码库生成词汇表显式请求而不是等它慢慢积累。文档给出的路径是/grill-with-docs help me scaffold my existing repo with a CONTEXT.md准备好接受一场漫长的质询——有用户反馈文件成型前被问了 50 个问题。在存量brownfield仓库上靠偶发使用累积词汇表速度远远不够。我能保留自己的领域模型、同时用自己团队的 ADR 格式吗目前做不到干净利落。词汇表与 ADR 两半打包在同一个技能里因此一个已有成熟 ADR 惯例不同模板、不同位置、不同命名的团队会收到与自家风格冲突的指示。当前选项是本地复制技能后自行编辑或在仓库自己的 agent 文档中覆盖 ADR 约定。把两者拆开是一项仍开放的改进请求。词汇表真的值回票价吗不过是又多了一份要评审、还会过期的产物。有时确实不值值得坦白说清界限DDD 越接近实现就越没用其价值在上游——命名与概念对齐而非聚合与分层仪式。同义词控制在命名边界上才重要模块名、表名、状态枚举、issue 标题、CLI 命令在普通行文里则没那么重要。还有一个在争议中的反驳领域术语压缩的是本就共享这些词的人类之间的沟通而 Agent 对同样的平实英文描述会有同样反应。按这种读法词汇表的价值在于让你和评审者始终与 Agent 正在做的事对齐而非让 Agent 变得更强。一天就能建完的小项目跳过它。而一份未经评审、由 Agent 自产自销的词汇表比没有更糟它会变成自信的传说后续会话把它当作真理。它能把我的模糊 prompt 变成领域语言吗不能也没有计划做一个做这件事的技能。一个连你自己都不理解的领域语言一旦写下来就成了毫无意义的话。本技能是在你拥有理解之后强制精确它不为你制造你尚未拥有的词汇。相关的陷阱是不做建模就用领域词汇——在错误的概念结构上盖正确的名词产出读起来像是对的、实际却是错的。生效的标志它会打断你追问你指的是两个东西中的哪一个而不是替你挑一个然后继续。CONTEXT.md在会话过程中持续变化而不是在结尾爆发式更新。它会拒绝为你明天就能反悔的东西写 ADR并指出三条测试里哪一条没通过。新条目用一两句话定义某事物是什么并在_Avoid_下列出你放弃的词。当你的代码与你的话互相矛盾时它会把代码原样引用回给你。CONTEXT.md变短的次数和变长的次数一样多。生态中的位置被其他技能驱动、也直接可达的底层学科domain-modeling是一份由模型调用的参考更多时候是作为其他技能的底层跑而不是单独运行grill-with-docs 通过一场 grilling 会话驱动它其 SKILL.md 原文就是一行Call the Skill tool twice, for grilling and domain-modelingwayfinder 在绘制 map 时加载它其Chart the map第一步就是调用 grilling 与 domain-modeling 两把工具来钉死目的地triage 用它让 issue 保持项目自己的措辞improve-codebase-architecture 在决策成型时调用它。它最近的同胞是 codebase-design两者是垫在所有技能之下的词汇层——这一个管领域那一个管模块的形状。它也可被直接调用当你想只要这套纪律、而不想被通常拉它进来的技能步骤绑住时。拿不准该用哪个技能时ask-matt 会为你路由。【免费下载链接】skillsSkills for Real Engineers. Straight from my .agents directory.项目地址: https://gitcode.com/GitHub_Trending/skills13/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表