بنقرة واحدة
devflow-design
在规格确认后、写代码前做软件设计时使用;也在设计评审被打回、或实现中发现模块边界/接口契约/错误处理需要重新设计时使用。涵盖模块划分、接口契约、错误模型、数据所有权、方案取舍与测试设计。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
在规格确认后、写代码前做软件设计时使用;也在设计评审被打回、或实现中发现模块边界/接口契约/错误处理需要重新设计时使用。涵盖模块划分、接口契约、错误模型、数据所有权、方案取舍与测试设计。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
在规格、设计、测试或代码需要独立评审时使用:阶段产物完成后的把关、人要求 review、或对既有产物做专项检查时。评审必须由作者之外的独立上下文执行,产出 findings 与 verdict。
在实现任何功能或修复任何缺陷、即将编写实现代码时使用;设计确认后的整个实现期都适用。强制测试先行的 RED→GREEN→REFACTOR 循环。不用于规格编写、设计决策或纯文档修改。
在车载软件工作项(ECU、域控、车载服务、整车平台)的规格、设计、实现或评审中使用,涉及功能安全/ASIL、车载 SOA 服务、DTC/诊断、整车启动/休眠/唤醒、SELinux 或跨 ECU 协同时。只承载车载专属约束;内存/实时性、通用服务接口或其他相邻领域规则由命中 description 的领域技能叠加,语言级规则见适用 `<language>-coding-standards`。
在后端/服务端工作项(HTTP/REST/GraphQL API、服务与仓库层、数据库访问、缓存、鉴权、限流、后台任务、可观测性、配置与机密、弹性容错、生产就绪)的规格、设计、实现或评审中使用,涉及接口契约、分层与依赖方向、配置与机密、错误模型、数据一致性、幂等、认证授权、依赖超时重试熔断、过载保护、优雅停机时。只承载服务端/API 领域约束;客户端/UI、行业专属服务或其他相邻领域规则由命中 description 的领域技能叠加,语言级规则见适用 `<language>-coding-standards`。
在编写、修改或评审 C 代码(.c 源文件、.h 头文件、C 单元测试、C ABI 边界)时使用。提供指针所有权、手动内存与资源释放、缓冲区容量、整数转换、宏、头文件、错误返回的具体规则与正反例。只适用于 C 语言;其他语言或 C++ 代码使用对应语言自己的 coding-standards 技能。
在需要为某种编程语言新建或修订 coding-standards 技能时使用:把团队内部编码规范文档转化为符合 DevFlow 形态的 <language>-coding-standards 技能,或把新的团队规则并入既有语言技能。不用于编写业务代码或直接做代码评审。
| name | devflow-design |
| description | 在规格确认后、写代码前做软件设计时使用;也在设计评审被打回、或实现中发现模块边界/接口契约/错误处理需要重新设计时使用。涵盖模块划分、接口契约、错误模型、数据所有权、方案取舍与测试设计。 |
设计回答的问题:用什么结构来满足规格,让代码做对的同时也值得长期持有。 一份好设计的检验标准:
设计分两级(团队开发流程要求):
| 级别 | 工件 | 何时需要 | 模板 |
|---|---|---|---|
| 组件级设计 | 组件根下 features/<id>/component-design-draft.md → ship 时 promote 到组件根下 docs/component-design.md(或团队覆盖路径) | 工作项影响组件边界:对外接口 / 组件依赖 / 状态机 / 组件职责变化,或组件设计基线缺失、过期 | references/devflow-component-design-template.md |
| 工作项级设计 | 组件根下 features/<id>/design.md(或团队覆盖路径) | 每个工作项(微小修改可按 using-devflow 裁剪) | references/devflow-ar-design-template.md |
硬性顺序:影响组件边界时,必须先修订组件设计草稿并经评审与模块架构师确认,再写工作项设计;工作项设计只能引用组件基线(功能编号、接口契约、软件单元),不得重新定义组件级架构。组件根下 docs/component-design.md(或团队覆盖的组件设计基线)不存在而工作项触及组件边界 → 先补建组件设计,不要在工作项设计里"顺便"定义组件架构。
设计的第一律:简单性。 满足当前规格的最少结构就是好结构。每多一层间接、一个抽象、一个配置项,都要付出理解、测试和演进的复利成本。本文所有原则最终都服务于这一条。
using-devflow 重新解析;读该组件根下已确认的 spec.md 和 docs/component-design.md(存在时,或团队覆盖路径),列出本变更触碰的既有模块与新增职责。component-design-draft.md,确认后再继续。features/<id>/traceability.md(或团队覆盖路径)填入每条需求对应的组件设计章节 / 工作项设计章节 / 测试设计用例列。devflow-review 按 design rubric 做独立评审并落盘记录(必经节点);评审 verdict 通过后,attended 模式再把评审记录与 verdict 呈人确认,并更新 plan.md 门禁表。R2 门禁未通过(含 attended 下未确认)前不进入实现。实现中发现设计有误:停下、回来改 design.md(必要时回到组件设计)、重新评审确认,不在代码里悄悄偏离。
每个模块(文件/类/组件)的职责必须能用一句不含「和」「以及」的话说清。说不清,或者句子里有两个动词短语,就是两个职责。
❌ ConfigManager:负责加载配置、校验配置、监听配置变化,以及把变化通知给订阅者
✅ ConfigStore:持有当前生效配置,提供原子读取
✅ ConfigLoader:从存储读取并校验配置块
✅ ConfigNotifier:把配置变化分发给订阅者
是否真的要拆成三个文件取决于规模——小就先放一个文件里,但内部结构按职责组织,这样将来拆分是搬运而不是手术。
判断两段代码该不该放一起:它们是否因同一个理由而变化。协议格式变化时要改的代码放一起;业务规则变化时要改的代码放一起。反例是「所有回调放 callbacks.c、所有结构体放 types.h」这类按形态分类——一次行为变更要横跨所有文件(霰弹式修改)。
「低耦合」不是感觉,按下面检查:
| 检查 | 坏信号 | 动作 |
|---|---|---|
| 依赖方向 | 底层模块 include 上层头文件;两模块互相 include | 依赖必须单向:上层依赖下层、具体依赖抽象。互相依赖 → 提取第三方共同依赖或用回调/事件反转 |
| 知识泄漏 | 调用方需要知道被调方的内部状态/调用顺序才能正确使用("先调 init 再调 open,但 reset 之后要重新 init") | 把时序约束收进模块内部,或用状态机显式拒绝非法顺序 |
| 数据泥团 | 三四个参数总是结伴出现在多个签名里 | 提取成结构体,给这组数据一个名字 |
| 特性依恋 | 一个函数大量读写另一个模块的数据,却几乎不碰自己模块的 | 函数搬到数据所在的模块 |
| 扇出过大 | 一个模块 include / 调用 7-8 个以上其他模块 | 它在做协调器还是上帝模块?拆出子职责 |
| 实现泄漏 | 公共头文件暴露内部结构体字段、私有函数、实现用的宏 | 头文件只放契约;内部细节进 .c / detail 命名空间 |
模块内聚的检验:随机删掉模块里的一个函数,其余函数是否大概率也要跟着改?是 → 内聚好。模块里有一半函数和另一半函数互不引用、不共享数据 → 那是两个模块住在一个文件里。
抽象必须由真实的重复或真实的变化轴支撑,不由想象支撑。
/* ❌ 当前只需要写日志到文件,却设计了插件框架 */
typedef struct {
int (*open)(void *ctx);
int (*write)(void *ctx, const log_entry_t *e);
int (*flush)(void *ctx);
int (*close)(void *ctx);
} log_backend_ops_t;
int log_register_backend(const log_backend_ops_t *ops, void *ctx);
/* ✅ 满足当前规格的最少结构;将来真有第二个后端再提取接口,
届时已知道两个实现的真实差异,抽象才会切在正确的位置 */
int log_file_open(const char *path);
int log_file_write(const log_entry_t *e);
什么时候间接层值得引入:跨越所有权边界(隔离第三方库、硬件、协议栈,让它们可替换可仿真);隔离真实的不稳定源(spec 明确说协议版本会变);切断循环依赖。
SOLID 不是新增流程,也不是为了制造抽象。它是设计与重构时识别变化理由、依赖方向和契约稳定性的速查语言;每条都必须落回 DevFlow 的可检查问题。
| 原则 | DevFlow 判据 | 常见坏信号 | 默认动作 |
|---|---|---|---|
| SRP | 一个模块只有一个变化理由 | 职责句里出现“和/以及”;一次需求变更横跨无关职责 | 拆职责;规模还小时至少按职责组织内部结构 |
| OCP | 真实变化轴有稳定扩展点 | 每加一种类型要改多处 switch / if 链和调用方 | 先确认变化轴真实,再提取表驱动、策略或多态 |
| LSP | 替换实现不削弱接口契约 | 子实现改变错误语义、前置条件或失败后状态保证 | 收紧契约,拆接口;不成立时取消继承/抽象 |
| ISP | 调用方只依赖自己使用的契约 | 公共头文件暴露大而全接口、内部字段、私有宏 | 拆小接口;隐藏内部字段与实现细节 |
| DIP | 高层策略不依赖底层细节 | 上层知道硬件、协议、存储或第三方库调用细节 | 在真实边界引入端口/适配层;拒绝无第二用例的单实现接口 |
接口契约描述可观察行为,不是函数名列表。每个对外接口(公共头文件函数、服务操作、协议消息)写全六项:
/* ❌ 这不是契约,只是签名 */
int mode_set(int mode);
/* ✅ 可冷读的契约(最终落在头文件注释 + design.md)*/
/**
* 请求切换运行模式。线程安全;不可在中断上下文调用。
*
* @param mode 目标模式,必须是 MODE_NORMAL 或 MODE_SAFE。
* @return OK 已接受请求;下一控制周期内完成切换并发出
* ModeChanged 事件(见 design.md §事件语义)。
* ERR_INVALID_ARG mode 非法;内部状态不变,不发事件。
* ERR_BUSY 上一次切换尚未完成;调用方应退避重试。
* 副作用:成功路径更新 mode 状态并向事件队列投递一条 ModeChanged。
*/
int mode_set(mode_t mode);
接口设计的取向:让误用难以编译通过、让正确用法成为唯一明显写法。用枚举不用魔法 int;语义不同的量用不同类型(duration_ms_t 而不是裸 uint32_t);需要配对调用的资源返回句柄并提供成对 API。
错误处理是设计决策,不是实现时的临场发挥。设计阶段定三件事:
1. 错误分类——不同类别的处理策略不同:
| 类别 | 例子 | 策略 |
|---|---|---|
| 调用方编程错误 | 传 NULL、非法枚举、违反调用顺序 | 校验并返回明确错误码(或按项目约定 assert);不进入降级逻辑 |
| 可预期的运行时失败 | 资源暂不可用、队列满、超时、外部输入非法 | 返回错误码,调用方有明确的恢复/退避路径 |
| 环境/硬件故障 | 存储损坏、外设无响应 | 进入设计好的降级模式,上报诊断事件 |
| 不可恢复的内部矛盾 | 状态机进入"不可能"状态 | 按项目故障策略(安全状态/复位/记录后受控终止) |
2. 传播策略:错误在哪一层被翻译、哪一层被处理。底层错误码原样穿透到顶层是泄漏(调用方被迫了解三层之下的细节);每层都包一遍是噪音。默认:在模块边界翻译一次("flash 写失败" → "配置保存失败"),中间层只透传。
3. 失败路径的状态保证:每个可失败操作明确——失败后已发生的副作用是回滚、保留还是半完成?接口契约里写清。「出错后状态未定义」在评审中按 critical 处理。
每块跨边界的数据(缓冲区、句柄、回调上下文)在设计里明确三个问题:谁分配、谁释放、指针在调用返回后是否仍可用。
只在真实存在多个合理方案时写选项对比,每个方案至少回答:改动范围、复杂度、对既有调用方的兼容性、失败时回滚成本、长期维护影响。然后给出推荐和理由——列完选项不推荐等于把设计工作推给评审者。
只有一个合理方案时,写一段「为什么不是 X」:X 是评审者最可能问的替代方案(通常是"更简单的做法"或"更通用的做法")。这不是形式——它强迫你检验自己是否真的考虑过更简单的路径。
伪选项是常见造假:三个方案其实是同一方案的不同措辞,或者两个陪跑方案明显荒谬。评审会按风险信号处理。
设计文档必须含测试设计章节——这是第一层规格通向第二层 TDD 的桥。把 spec 的每条验收标准映射成用例。canonical 测试设计表只有一张:工作项设计模板第 6.1 的 Case ID 汇总表(或等价表),它是 devflow-tdd 细化 plan 的唯一入口;第 6.2+ 子表只能展开步骤、mock、风险覆盖,不得引入无法回指到第 6.1 的新用例。
| Case ID | 覆盖需求 | 场景(Given/When/Then 摘要) | 层级 | 预期结果 |
|---|---|---|---|---|
| TC-001 | FR-001 | SAFE 下 SetMode(NORMAL) → 切换+事件 | unit | 返回 OK;周期内 ModeChanged=NORMAL |
| TC-002 | FR-001 | SetMode(非法值) → 拒绝 | unit | ERR_INVALID_ARG;状态与事件无变化 |
| TC-003 | NFR-001 | 1000 次切换延迟测量 | integration | p95 ≤ 5ms(QAS 阈值) |
规则:
modify 需求必须有回归用例(旧行为中要保留的部分);remove 必须有删除后语义用例TC-xxx),并能双向追溯:spec Acceptance → Case ID → plan 任务;组件级测试项如需引用,先映射到工作项级 TC-xxxdevflow-specify这张表就是 devflow-tdd 的任务来源:实现时逐用例 RED→GREEN→REFACTOR。
<language>-coding-standards)与领域开发技能已读取并体现在契约里;领域技能按各自 description 触发,不依赖固定枚举| 文件 | 用途 |
|---|---|
references/devflow-ar-design-template.md | 工作项级设计(design.md)模板,含「高质量设计增补」章节 |
references/devflow-component-design-template.md | 组件级设计模板,含「高质量设计增补」章节 |