关于 dido-code-style
dido-code-style 是帮助 Dido Marchet 构建 Web 应用的编码规范技能,覆盖跨技术栈的实现与审查原则,并指向后端和 Nuxt 前端的专用技能。
主要功能
- 01跨语言编码原则
- 02项目上下文与连续性实践
- 03模块化和依赖规范
- 04可扩展性与副作用规则
- 05后端和 Nuxt 技能衔接
适用场景
- 01按项目规范实现代码变更
- 02审查代码变更并排查缺陷
- 03依据关联指南分析仓库或模块
- 04保持文档与代码变更一致
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ didomarchet/ dido-skills --skill dido-code-style安装后在 Claude Code 中输入/dido-code-style确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
analisi.mdrepo-audit.jsriferimento/skill-di-terzi.md详细介绍
Dido 的代码风格与约定
你正在帮助 Dido Marchet 构建 Web 应用。请严格遵守这些约定:它们已在 Dido 的生产项目中验证,适用于所有技术栈。**处理相应代码时必须使用的技术栈技能:**后端使用 dido-backend,Nuxt 前端使用 dido-frontend-nuxt。
| 任务 | 阅读内容 |
|---|---|
| 编写或修改代码 | 第 1 部分,以及相应的技术栈技能 |
| 审查修改、“查找 bug” | 第 1 部分 + 第 2 部分“审查与 bug 排查” |
| 分析仓库、模块或文件夹 | 本文件旁边的 analisi.md |
如果项目的 CLAUDE.md 有更具体的规定,则以它为准。
1. 适用于所有项目和语言的原则
上下文与延续性
编写代码绝不是凭空进行的:每项修改都以现有内容为基础,并让下一位参与者(无论是人还是 AI)了解发生了什么以及原因。
编写代码之前
- 阅读项目的
CLAUDE.md、其中引用的文档和记忆:这里记录着决策、约束和已知限制。不要重新提出已记录为弃用或超出范围的内容(例如docs/LIMITI-NOTI.md),也不要重新讨论已经做出的决定。 - 了解你要修改的区域之前做过什么:
git log --oneline -- <path>、近期提交、说明原因的注释,以及相关测试。先弄清代码为何如此编写,再进行修改。 - 阅读涉及的完整流程,而不只是要修改的那一行:调用方、测试以及描述该流程的文档。编写新辅助函数前,先查找是否有现成的可复用函数。
- 如果项目有基于同一 starter 衍生的姊妹项目,查看它们如何解决同一问题,并遵循相同约定。
- 如果有不清楚之处或与文档矛盾的地方,请先询问:不要猜测,也不要悄悄推翻已有决定。
修改期间及之后
- 对于不明显的决定,应在代码中添加说明原因的注释;如果它改变了项目的工作方式,还要在同一次修改中更新
CLAUDE.md/ 文档,而不是事后补上。 - 一项事实,只记录一处。 文档应记录代码本身无法表达的内容:决策及其原因、操作流程(包括所需命令和 URL)、各服务和模块的职责。其余内容应指向信息源:变量列在
.env.example中,名称本身不足以说明含义的变量应在上方添加注释;端点则列在 OpenAPI 规范中。重复记录文件已有定义的表格、列表或图表,都是副本;而每个副本都会成为文档落后的地方。 - 修改后,在仓库中搜索你改动涉及的关键词。如果文档重复记录了已修改的内容,应删除整份重复内容,而不只是改动的那一行,并改为指向信息源,而不是更新副本。修正文档中已不再适用的操作流程和决策。
- 提交信息应使用项目所用语言说明改动内容及原因。
- 代码和 git 未记录的事实(某项决策及其原因、约束、截止日期、外部参考资料)应写入记忆。
- 最终报告应说明改动内容、已验证的事项以及尚待处理的问题,让下一步工作能够基于事实展开。
简单易读
- 编写能解决今天需求的最简单代码。不是下一个需求,也不是假设中的需求。
- 三行相似代码胜过过早抽象。只有在确实有重复调用点时才提取 helper,不要提前提取。
- 一件事,一个组件。 如果某个部分几乎和已有的另一个部分做同样的事(滚动列表、下拉菜单、淡出效果、helper),就复用它:同一个组件、composable 或库。如有需要,只做最小扩展(一个 prop、一个 slot、一个 CSS 变量)。两个部分做同一件事,就已经是实际的重复调用点:绝不再复制一份,哪怕只有几条 CSS 规则。动手前,先在仓库里搜索已有的实现。
- 不要使用只有一个实现或一个使用者的 factory、adapter、registry、基类、插件系统或配置选项。例外:已经具体规划了第二种实现,并且写在项目的
CLAUDE.md中(例如,文件存储从local切换到s3)。 - 不要添加没人传入的参数、选项或标志。不要把特定函数泛化。
- 一眼就能读懂:名称能说明事物是什么;用提前返回代替嵌套条件;每个函数只做一件事;不要写需要注释才能看懂的“巧妙”代码。
模块化,每个部分都可以移除
各部分协同工作,但每个部分都可以移除或关闭,其他部分仍能继续运行,只有真正依赖它的部分除外。写下隐藏依赖的那天看不出来,因为所有东西都还在。等有人移除某项功能或某个服务停止响应时,问题才会显现。
- 与某项功能有关的所有内容都带上它的名称:它自己的文件夹,以及在技术栈按类型拆分的地方(组件、查询、语言、数据库 schema、API 规范、env 文件),也要有带此名称的文件、文件夹或区块。这样,移除功能的人就能找到所有相关部分,只需额外删除少数几行连接代码,例如路由挂载或布局中的 import。
- 一个部分通过另一个部分的入口点(模块的 index、service、composable、prop)使用它,绝不直接访问其内部文件或状态。这样,查看 import 的 grep 就能看出谁在使用它,而其内部实现变更时无需改动任何使用者。
- 可选部分依赖核心,而不是反过来。核心不 import 统计、错误跟踪或第三方 widget:这些部分通过框架机制(hook、事件、middleware、plugin、slot)接入。不是 API 客户端调用错误跟踪,而是错误跟踪监听错误。
- 某个部分缺失、未配置或无响应时,只关闭依赖它的部分。无法缺少该部分的操作应自行失败,并给出清晰的错误。如果该部分只是辅助用途(日志、审计、统计、通知),操作仍应成功,问题则写入日志。这适用于确实可能缺失的内容,例如外部服务、配置和 CMS 数据。对于内部代码,仍遵循“一种问题,一种保护”。
- 启动时只阻止缺少全局必需的配置,例如数据库和密钥。如果可选部分缺少配置,就让该部分保持关闭,并在日志中说明。
- 模块化不意味着要增加抽象。按功能划分的名称和文件夹、入口点、单向依赖,以及框架已有的机制就足够了。不要自建插件系统、registry、事件总线或功能标志:遵循“简单易读”。
- 在宣布完成之前,想想移除刚写的部分会导致什么损坏,并查找哪些地方 import 了它:结果应该只有它自己的接入点。对于可选部分或外部服务,也要尽可能尝试在没有它的情况下运行(不设置它的变量,或关闭服务)。其余部分必须能启动并正常运行。
为扩展而设计,而非过早扩展
数据量和流量增长时,代码依然能正常运行:这是设计,不是优化。
- 可能增长的列表都要分页;查询只获取需要的字段;循环中不能逐项查询(N+1)。
- 用于筛选、联接或排序的列都要有索引。
- 不要使用在多于一个 worker 或容器时会出问题的进程内存状态——或者在项目文档中注明这一限制。
- 大文件和大型数据集要使用流式处理;请求路径中不能有阻塞调用(
*Sync、同步加密)。
“为流量增长后做准备”的基础设施属于过早设计:缓存、队列、worker、微服务、额外层级。只有在测量结果或实际事故表明有需要时才添加。添加缓存或优化时,要在上方写明原因的注释(测量了什么、可以接受多旧的数据):修改前先阅读。
不要有隐藏的副作用
- 函数只做其名称所述的事,不做其他事:
get、find、resolve、check、validate不写入数据。 - 不要修改参数或模块共享状态;返回新值。
- 必须一起成功的写入要放在同一事务中。
- 外部副作用(电子邮件、webhook、第三方调用、文件写入)要在数据保存后执行,绝不能放在可能回滚的事务中。
不要留死代码
- 不要保留注释掉的代码、未使用的函数 / export / import / 变量 / 依赖项 / 配置键 / 文件。历史由 git 保存。env 文件及其变量不在此列:参见“env 文件”。
- 不要为已不存在的情况保留回退路径。不要为无人计划处理的工作添加 TODO。
更改内容时,删除旧内容
- 用 Y 替换 X → 在同一次修改中删除 X:代码、测试、文档、API 规范、配置。env 文件除外:参见“env 文件”。
- 除非 Dido 要求,否则不要添加向后兼容垫片:不要保留已弃用的别名、旧名称的 re-export、改名为
_unused的变量、// removed X标记,也不要同时读取新旧字段。 - 在说“已从所有位置删除”之前:使用带单词边界的 grep(
grep -rn '\bnome\b' src/ tests/ docs/),不要使用过于狭窄的模式。残留内容常藏在测试和查询 / 筛选中。
env 文件
- 每个 repo 的根目录都有三个 env 文件,全部纳入 repo:
.env.example、.env.local(开发环境)和.env.production。不要在 git 之外保留其他 env 文件。 - 文件中包含真实值,包括机密,因为这些 repo 是私有的。仅当值需要生成或从其他位置获取时,才使用
CHANGE_ME。 - 不要删除或合并这些文件,即使其中两个内容相同也不行。除非 Dido 要求,否则不要删除任何变量或值、将其清空或改成占位符,即使代码已不再读取它们也不行。
- 新变量必须添加到这三个文件中,名称相同。
一个问题只用一种防护机制
- 如果某个 bug 或风险已由现有机制覆盖,就不要再添加第二种机制“以防万一”。针对不同故障情况保存多份数据(设备丢失、服务器从备份恢复、用户操作错误)不算重复:每份数据各自应对一种问题。
- 不要处理不可能发生的错误情况:已有会抛出异常的守卫后,不要再做 null 检查;不会抛出异常的代码不要用 try/catch 包起来;已在上游验证的数据不要重复验证。“不可能”意味着代码已将其排除,例如前面不久就有守卫,而不是“从未遇到过”。
- 在边界处验证,然后信任内部代码。边界是代码无法控制的一切:用户输入、外部 API、启动时的环境变量,以及浏览器中的本地存储(配额已满、数据被浏览器删除、连接已关闭)、网络、其他标签页、页面关闭或被系统挂起。在这些地方,错误绝不可能算作“不可能”。
最小改动
- 修复只改出问题的行,不改模块。“顺便重构”应单独提交,且只有 Dido 要求时才做。
- 不要重新格式化、重命名或调整未要求修改的代码顺序。
- 与周边代码保持一致:命名、惯用写法、文件结构、语言和注释密度。
- 现有代码不是规则。若它与这些技能相悖(重复代码、重复组件,或使用了与此处所述不同的方法),应以这些技能和 Dido 的指示为准,即使那段代码是别人写的。按它们的要求处理,并在报告中写明差异。
注释
- 说明为什么,而不是说明做了什么。
- 对于已有的不明显选择,应添加注释说明原因(例如:
// 不缓存:...)。 - 对于有人可能会“修正”的刻意缺失,应简短注释说明原因(例如:不缓存 SMTP 客户端,因为服务端会运行于多个进程)。这不是
// removed X这样的标记,而是解释设计决策,不是记录历史。
文案
所有供人阅读的文本(界面、邮件、错误消息、注释、文档、报告),都应在读者需要采取行动时提供。句子要简短,用读者熟悉的词语。编写新文案前,先查看已有文案(模板、语言文件、邮件),并沿用相同的语体和称呼方式。
在界面中,页面、区块或卡片应包含标题、内容和操作。只有在以下三种情况下才添加副标题、说明和帮助文本:
- 字段要求特定格式或有不明显的限制(“最大 10 MB”);
- 操作无法撤销,此时应在确认对话框中说明,而不是放在页面上(“删除账户?订单和地址无法恢复。”);
- 出现问题时,消息应说明问题和补救方法(“文件超过 10 MB。请选择更小的文件。”)。
按钮应写明操作(“保存”“发布”),标签应写明对象名称。
使用常规标点:句号、逗号、冒号、括号和直引号("…"),不要使用书名号(« »)。在界面中,句子里提到的按钮、状态或字段名称应使用粗体;在没有格式的文本中(提示条、提示、错误消息),则应使用直引号。每段最多使用一个长破折号(—)和一个间隔号(·);术语与其解释之间使用冒号。
测试
- 每个新行为和每个错误修复都要有测试,且没有该改动时测试应失败。修复错误时,先编写测试并确认其失败。
- 从公共接口测试行为(HTTP 路由、渲染后的组件、CLI 输出),不要测试内部实现。
- 不要为了让测试通过而修改测试。如果行为变更是有意的,应在改动中说明。
- 如果项目没有测试配置,应在报告中说明;未经要求,不要添加测试框架。
安全贯穿每次修改
每次修改在被视为完成之前,都必须经过与影响范围相称的安全检查:CSS 微调不需要全面检查,新增端点则需要全面检查。
- 输入。 每个外部输入(请求体、查询参数、路径参数、标头、Cookie、上传文件、Webhook、第三方 API 响应)都必须在边界处验证:类型、格式、长度、允许的值。
- 身份验证与授权。 谁可以调用它?检查必须在服务器端进行,绝不能只是在 UI 中隐藏。用户能否通过更改 ID 访问他人的数据?已停用或降级的账户是否会立即失去访问权限?
- 数据暴露。 响应只返回必需字段:生产环境绝不返回密码哈希、令牌、OTP、机密、堆栈跟踪或驱动程序错误。日志中绝不包含密码、令牌或 OTP。
- 注入。 不得通过拼接字符串来构造 SQL、Shell 命令或 HTML:使用参数化查询 / ORM、自动转义的模板,且不得对用户可控的内容使用
v-html/innerHTML。 - 机密。 放在仓库的 env 文件中(见“Env 文件”),或以静态加密方式存储;绝不能放在代码、日志或客户端 bundle 中(客户端 bundle 中只能放置本质上公开的值,例如只读 CMS 令牌)。
- 滥用。 对所有可能被恶意触发或用于发送垃圾信息的功能实施速率限制(登录、OTP、密码重置、注册、上传、联系表单)。还要检查每项保护措施(计数器、封锁、限制)是否可能被他人触发:如果陌生人能让其他人的账户触发保护措施,就会导致账户锁定。令牌必须随机生成、有有效期且只能使用一次。登录和密码重置响应不得透露账户是否存在。
- 文件。 检查类型和大小,使用生成的名称保存,不得使用用户可控的路径,私有内容只能在身份验证后下载。
- 传输与浏览器。 明确设置 CORS 允许列表,Cookie 使用
HttpOnly+Secure+ 正确的SameSite,生产环境使用 HTTPS。 - 依赖项。 新增依赖项必须确实有用(不能用几行代码替代)、有人维护,且不存在已知的严重漏洞(
npm audit/pnpm audit)。
然后:
- 添加保护措施之前,先检查现有措施是否已覆盖相关风险(项目的
CLAUDE.md、代码注释):“一个问题对应一项保护措施”这一原则同样适用于安全。 - 由你的修改引入的漏洞必须在同一次修改中修复。超出此次修改范围的既有漏洞,应说明具体场景和严重程度:不能默不作声,也不能通过未经要求的重构来“修复”。
- 最终报告中必须有一行说明安全检查的情况:检查了什么,以及发现了什么(或“未发现问题”)。
只有验证过才算完成
- 未实际运行之前,绝不要说“完成”或“有效”:需运行测试、仅做检查的 lint 和格式化、构建、实际命令、实际端点。“编译通过”不代表“有效”。
- 修改架构或生成的代码后,先重新生成,再运行任何操作(例如
npx prisma generate)。 - 明确说明已验证和未验证的内容,以及原因(例如:“数据库未启动,未运行测试:以下是运行方法”)。
警示信号:停下来,先修正再继续
| 想法 | 现实 |
|---|---|
| “为了兼容,我保留旧函数 / 字段 / 变量” | 没人要求这样做。在这次修改中将其删除,并更新测试和文档。 |
| “这个 env 文件是重复的 / 没人读取这个环境变量,我把它删了” | env 文件应保持 Dido 创建时的样子,保留所有值。只有 Dido 要求时才修改。 |
| “我把它做成可配置 / 通用的,或许以后会用到” | 只有一个使用者 = 不需要抽象。编写专用版本。 |
| “我需要的功能和 X 差不多,就在这里重写一份” | 使用 X,并通过 prop 或 slot 扩展它。第二份副本就是一个潜伏的 bug。 |
| “旁边的代码就是这么做的,它已经有自己的副本了” | 现有代码不是规则:应遵循 skill,并指出差异。 |
| “我直接导入内部文件,省点事” | 通过它的入口导入,否则下次修改那部分时就会破坏你的代码。 |
| “我在这里调用统计 / 错误跟踪” | 这是挂接到核心的可选部分,应使用 hook 或事件。 |
| “没有这个变量,应用就无法启动,这样他们就会注意到” | 如果只有某个部分需要它,就只关闭那部分,并在日志中说明。 |
| “我加个缓存 / 队列,以防万一” | 没有衡量就不加缓存。 |
| “我再加一道检查,有备无患” | 找出已有的覆盖方式:一个问题只保留一个防护措施。 |
| “既然我已经在这里了,顺便把这个也修一下” | 单独修改,而且只有 Dido 要求时才做。 |
| “这个看起来不对,我改了” | 先阅读注释、git log 和文档:这可能是有意为之的决定。 |
| “能编译,所以就算完成了” | 实际运行,并报告运行了什么。 |
| “文档以后再更新” | 在同一次修改中更新,否则永远不会更新。 |
| “我也更新 README 中的表格” | 如果表格重复了代码,就删除并改为链接到权威来源。 |
2. 审查与分析
审查与查找 bug
审查修改,或处理“查找 bug”之类的请求时:
- 假定代码可以正常工作:举证责任在于指出问题的一方。
- 只报告严重程度为高或中等的问题(见下文“严重程度”)。未发现问题 → 用一行回复“正常”。
- 不要报告美观、命名、微小简化、理论上的竞态或面向未来的改进,除非 Dido 要求。结尾绝不要加上“另外还注意到一两个小问题”。
严重程度
| 严重程度 | 问题 |
|---|---|
| 高 | 数据丢失或损坏、安全漏洞、用户可见的错误、会话或凭据丢失、账号锁定 |
| 中等 | 文档所述场景下状态不一致、重试或幂等性失效、实际瓶颈、测试失败、误导客户端的 API 文档、某个可选部分或外部服务缺失或无响应时,导致不依赖它的部分也一起崩溃 |
| 低 | 过度设计、死代码和残留项、能带来具体收益的简化、其他不一致的文档、文档中的重复内容、关键流程缺少测试、文本、其他模块化问题(导入内部文件、核心导入可选部分、某项功能的代码分散在多处) |
完整分析(“分析代码仓库”)
分析代码仓库、模块或文件夹时,请阅读本文件旁边的 analisi.md:其中说明了运行 repo-audit.js 工作流的成本和方式、它会检查什么、什么情况下问题会被证伪,以及报告的格式。