学习如何撰写 Claude Code 风格指南提示,强制命名、分层、错误处理和日志规则,通过简单检查尽早发现违规。

风格违规很少以一次严重错误出现。它们通常从微小的“差不多”选择开始,在一次拉取请求中看起来无害,然后逐渐堆积,直到代码库显得不一致、难以阅读。
风格漂移常常表现为:一个文件使用 userID,另一个使用 userId,第三个使用 uid。一个 handler 返回 { error: "..." },另一个抛出错误,另一个记录日志后返回 null。每次改动都很小,但合在一起就会让仓库中的模式变得不可预测。
快速迭代和多人协作会让问题更严重。人在时间压力下会复制他们看到的东西。如果仓库中最新的代码使用了一个快捷写法,下一个改动很可能以该写法为模板。几周后,“默认风格”不再是你写下的指南,而是最后发生的事情。
因此目标必须是保持一致的约定,而不是个人偏好。问题不该是“我喜不喜欢这个名字?”,而是“这是否符合我们约定的规则,以便下一个人可以无需思考就能遵循?”
及早发现违规意味着在坏模式成为复制粘贴的源头前就阻止它。把注意力放在新增和修改的代码上,修复新不一致的首次出现,并阻止合并引入新的漂移。当你标记一个问题时,附上一个简短的首选示例,供下次模仿。
举个现实的例子:某个开发者新增了一个 API 端点并为了调试而记录了原始请求体。如果这段代码合并了,下一个端点会复制它,很快敏感数据就会出现在日志中。第一次在 PR 中捕获它代价很低;等它扩散后再处理既痛苦又危险。
风格指南只有在审查中能像检查表一样被读取时才有效,而不是一堆偏好。把每条准则重写为可在 diff 上检查的规则。
把规则按四类组织,便于抓住:命名、分层、错误处理和日志。对每一类写两件事:必须满足的条件和禁止项。
事先决定每条规则的强度:
设置作用范围以避免审查变成无尽的重构。一个简单的规则很好用:“新增和修改的代码必须符合规范;未触及的现有代码不必重写,除非它阻碍了修复。”如果你想要清理工作,把它作为单独的有时间限制的任务。
还要定义你期望审查产出的格式,便于落地:通过/失败的结论、带文件与行号的违规清单、以具体改动形式给出的建议修复,以及在可能导致漏洞或泄露时的一句话风险说明。
举例:如果一个 PR 在日志中记录了原始用户令牌,审查在“日志:禁止记录秘密”这一项下应判为不通过,并建议改为记录请求 ID。
风格提示失败的原因通常是听起来像偏好。好的审查提示应像一份合同:明确列出不可协商的项、清晰命名的例外,以及可预测的输出。
以两个短块开头:必须为真(必须满足的项)和可放宽之处(可例外的项)。然后加上一条决策规则:“如果不明确,标记为需要澄清。不要猜测。”
强制要求证据。当工具标记违规时,要求引用确切的标识符和文件路径,而不是模糊描述。这个单一限制可以减少大量来回沟通。
把作用范围限定得很紧:只对变更的行和直接受影响的代码路径发表评论。如果允许无关的重构,风格执行就会变成“重写整个文件”,人们会停止信任这些反馈。
这里有一个可以复用的结构:
Role: strict style guide reviewer.
Input: diff (or files changed) + style guide rules.
Non-negotiables: [list].
Allowed exceptions: [list].
Scope: ONLY comment on changed lines and directly impacted code paths. No unrelated refactors.
Evidence: Every finding MUST include (a) file path, (b) exact identifier(s), (c) short quote.
Output: structured compliance report with pass/fail per category + minimal fixes.
要求报告每次都保留相同的章节,即便某些章节写上“No issues found”:命名、分层、错误处理、日志。
如果报告写着“service 层泄露了 DB 细节”,它必须引用类似 internal/orders/service/order_service.go 的文件路径和确切调用(例如 db.QueryContext),这样你就能在不争论意图的情况下修复泄露。
风格指南之所以能坚持,是因为流程可重复。目标是让模型检查规则,而不是争论喜好,并且每次都用同样的方式执行。
使用一个简单的两遍工作流:
举例:一个 PR 添加了新端点。第一遍会标出 handler 直接访问 PostgreSQL(分层违规)、请求结构体命名混用(命名违规)、以及日志记录了完整邮箱(日志违规)。第二遍给出最小修复:把 DB 调用移到 service/repository,重命名结构体,并在日志中对邮箱做脱敏。其他内容不变。
命名问题看起来微不足道,但它们会带来真实成本:人们误读意图、搜索变困难、以及“几乎相同”的名字会成倍增长。
明确说明审查者必须在整个变更中执行的命名规则:文件名、导出类型、函数、变量、常量和测试的命名。明确大小写(camelCase、PascalCase、snake_case),并选定一个缩写规则(例如 APIClient vs ApiClient)。然后在所有地方强制执行。
还要统一共享词汇:错误类型、日志字段和配置键。如果日志用 request_id,就不要允许某处使用 reqId,另一处使用 requestId。
一个实用的审查指令:
Check every new or renamed identifier. Enforce casing + acronym rules.
Flag vague names (data, info, handler), near-duplicates (userId vs userID), and names that contradict behavior.
Prefer domain language: business terms over generic tech words.
要求一份简短报告:三处最令人困惑的名称、任何近似重复项以及应保留的那个名称,还有任何不符合标准的日志/配置/错误名称。
分层规则用简单语言表达效果最好:handlers 处理 HTTP,services 保存业务规则,repositories 访问数据库。
锁定依赖方向。Handlers 可以调用 services;services 可以调用 repositories。Repositories 不应调用 services 或 handlers。Handlers 不应引入数据库代码、SQL 助手或 ORM 模型。如果使用共享包(config、time、IDs),保证它们不含应用逻辑。
把横切关注点固定到一个“家”:校验通常属于边界(请求形状),而业务规则的校验属于 service。授权通常从 handler 开始(身份、权限),但 service 应当强制执行最终决定。映射应发生在层的边界:handler 将 HTTP 映射到领域输入,repository 将 DB 行映射到领域类型。
把下面这段放入提示以保持审查具体:
Check layering: handler -> service -> repository only.
Report any leaks:
- DB types/queries in handlers or services
- HTTP request/response types inside services or repositories
- repository returning DB models instead of domain objects
- auth/validation mixed into repository
For each leak, propose the smallest fix: move function, add interface, or rename package.
让报告具体:列出文件、它属于哪个层、哪个 import 或调用破坏了规则,以及防止该模式扩散的最小改动建议。
大多数风格争论在生产出现问题时最激烈。明确的错误处理策略能让修复保持冷静,因为大家都知道“好的做法”是什么。
写下哲学并执行它。例如:“包装错误以添加上下文;只有在改变语义或映射到用户消息时才创建新错误。在系统边界外返回原始错误。” 这一句话能防止随机模式蔓延。
把面向用户的文本和内部细节分开。用户消息应简短且安全。内部错误可以包含操作名和关键标识,但不能包含秘密。
在审查中检查几个常见失误:吞掉错误(记录但不返回)、含糊的返回(在失败后返回 nil 值且 error 也是 nil)、以及向用户暴露堆栈跟踪、查询文本、令牌或 PII 的信息。如果支持重试或超时,要求显式声明它们。
举例:结账调用超时。用户看到“Payment service is taking too long.”。内部则应包装超时并包含 op=checkout.charge 和订单 ID,以便可搜索和可操作。
只有大家以相同方式写日志时,日志才有用。如果每个开发者选择自己的用语、级别和字段,搜索会变成猜测。
把日志级别设为不可协商:debug 用于开发细节,info 用于正常里程碑,warn 用于意外但已处理的情况,error 用于用户可见的失败或需要关注的情况。把“fatal”或“panic”保持稀少并与明确的崩溃策略绑定。
结构化日志比完美句子更重要。要求稳定的键名以免仪表盘和告警破裂。决定一小套核心字段(例如 event、component、action、status、duration_ms)并保持一致。
把敏感数据视为硬性终止条件。明确列出绝对禁止记录的内容:密码、认证令牌、完整的信用卡号、秘密和原始个人数据。点出那些看起来无害但其实不安全的项,比如密码重置链接、会话 ID 和完整请求体。
关联 ID 使跨层调试成为可能。要求每条与请求相关的日志都包含 request_id。如果要记录 user_id,定义允许的场景以及如何表示缺失或匿名用户。
下面是一段可复用的提示块:
Review the changes for logging conventions:
- Check level usage (debug/info/warn/error). Flag any level that does not match impact.
- Verify structured fields: require stable keys and avoid free-form context in the message.
- Confirm correlation identifiers: request_id on all request-bound logs; user_id only when allowed.
- Flag any sensitive data risk (tokens, secrets, personal data, request/response bodies).
- Identify noisy logs (in loops, per-item logs, repeated success messages) and missing context.
Return: (1) violations with file/line, (2) suggested rewrite examples, (3) what to add or remove.
在合并前做一次快速“安全检查”:任何新日志缺少 request_id(针对请求工作)、任何改变现有键名的新键(userId vs user_id)、任何错误日志缺少失败的描述(操作、资源、状态)、任何会在每个请求触发的高频日志,以及任何可能在字段或消息中出现秘密或个人数据的情况,都应被标记。
把风格漂移当作构建失败,而不是建议。加一个严格的门禁,在合并前运行并返回明确的通过或不通过。如果违反了必须的规则(命名、层边界、日志安全、错误处理)则判为不通过并指出确切的文件和行。
把门禁保持简短。一个实用技巧是要求每条规则给出 YES/NO 检查表,只要有任何一项为 NO 就拒绝批准。
一个能捕捉大多数问题的 PR 大小检查表:
当工具建议修复时,要求为它触及的每条规则提供一小段合规代码片段。这能避免模糊的反馈,如“重命名以提高清晰度”。
风格指南失败最快的方式是留下解释空间。如果两个审查者读同一条规则会得出不同结论,工具就会在执行品味而不是标准。
命名就是一个常见例子。“使用清晰名称”不可测试。把它收紧为可验证的语言:“函数用动词(例如 createInvoice),布尔值以 is/has/can 开头,导出类型用 PascalCase。”
另一个陷阱是一次性要求所有内容。当一个提示尝试涵盖命名、分层、错误、日志、测试和性能时,反馈往往泛泛。需要深度时把审查拆成有重点的几遍,或者把门禁提示限制在必须的规则上。
最常导致执行漂移的问题:
如果你把提示当作测试,就能获得可预测的执行;如果把它当成建议,违规就会潜入并扩散。
对 diff(而不是整个仓库)做一次快速检查并确认:
保留一个简短的提示模板,并在每次变更时粘贴:
Review ONLY the changed code against our rules for naming, layering, errors, and logging.
List mandatory violations first (with file + line if available). Then list optional suggestions.
End with either: “no mandatory violations found” or “mandatory violations found”.
举例:在 handler 中新增一个 procUsr() 函数并直接写入 PostgreSQL,即使功能可用也应因命名和分层违规而失败。在这里捕获它能防止复制粘贴把错误扩散开来。
一位同事新增了端点:POST /v1/invoices/{id}/send。它触及了 handler、service 和 storage。
第一遍你想要的是报告而不是重写:
Pass 1 (report only)
You are a strict style checker. Read the patch.
Rules: naming must match our guide, handlers call services only, services call storage only, no SQL in handlers,
errors must be wrapped with context, logs must be structured and not leak PII.
Output: a numbered list of violations with file:line, rule name, and one-sentence impact. Do not propose fixes.
If a rule might be intentionally broken, ask one clarification question.
典型发现包括:SendInvoiceNow() 与 SendInvoice 的命名不一致、handler 直接调用 db.QueryRow、返回原始 err 且未加上下文、以及像 log.Printf("sending invoice %v", invoice) 这类会转储完整对象的噪声日志。
第二遍要求最小且安全的改动建议:
Pass 2 (minimal fix suggestions)
Using the violations list, propose the smallest code edits to comply.
Constraints: keep behavior the same, no refactors beyond what is needed, show suggested function names and where code should move.
For each fix, include 1-2 lines of example code.
如果允许破坏规则,需要先说明:“仅在添加一条短注释解释原因并添加后续任务以移除例外时才允许例外。”
修复后,handler 变得瘦小,仅作适配;service 负责工作流;storage 负责查询;错误变为 fmt.Errorf("send invoice: %w", err);日志变为一行干净的、只记录安全字段(如发票 ID,而不是完整发票)。
选一个团队认可的提示并把它当作共享工具开始使用。从审查中最常惹你麻烦的点开始(命名漂移、层泄露、不一致的错误、不安全的日志)。仅当你在真实代码中看到实际违规时才更新提示。
在提示顶部保留一小段规则块,并在每次审查时不变地粘贴它。如果每次人人都编辑规则,你得到的就不是标准,而是辩论。
一个简单的节奏有帮助:每周由一人收集最常见的风格错误,并恰好添加一条更明确的规则或一个更好的示例。
如果你在像 Koder.ai (koder.ai) 这样的聊天驱动构建流程中工作,值得在变更过程中而不是仅在结束时运行相同的门禁检查。规划、快照和回滚等功能可以帮助你在导出源代码前把风格修复保持小且可撤回。