
简介华为软件详细设计模板是一份源自华为研发流程的标准化文档模板定位用于规范软件详细设计并直接指导编码、测试与维护适合嵌入式、通信及企业级软件研发团队和初次接触详细设计的工程师参考。模板不仅提供产品名称、密级、版本、修订记录、目录、图表清单等文档管理要素还围绕目的、范围、设计原则与约束、功能设计、数据设计、接口设计、性能设计、安全性设计、错误处理与异常设计、测试设计等研发关键环节搭建了完整章节框架且大多配有中英文对照说明能够帮助读者快速理解每个章节的编写要求与填写方式降低详细设计文档的编写门槛。资源为单个doc文件压缩包大小约89KB打开即可参考或二次修改为团队内部模板。目前已有1071人学习下载适合作为软件设计规范学习、研发流程培训或相关课程教学的辅助材料。1. 这份华为详细设计模板值得每个研发团队抄一遍很多开发团队的设计文档写着写着就变成“代码粘贴板”或者“需求复述稿”。评审时大家翻一遍发现问题全靠运气。华为这份软件详细设计模板之所以值得拆解在于它把“设计文档”这件事从自由写作变成了结构化表达什么位置写什么内容、字段怎么填、粒度到哪一层全都有明确约束。写的人知道要交代什么评审的人知道往哪儿挑毛病后来接手的人也能按图索骥。本文不讨论这份模板怎么下载、怎么打开而是把它拆成一套可以直接落地的写作规范适合正在建立设计流程的团队也适合刚转岗做设计的开发者对照自查。2. 文档骨架从文档头到缩略语清单每一页都在消解沟通成本2.1 文档头与密级先回答“这份文档能不能被带走”模板第一页有产品名称、密级、产品版本还有拟制、评审、批准三个签名位。密级这里很多人直接复制模板里的“Low”实际上华为内部对密级的定义会对应到具体的信息安全策略Low通常指内部公开Medium以上就要做访问控制。签名位对应的是一条质量管理链路拟制人对内容负责评审人对技术方案负责批准人对发布负责。最容易被跳过的是签字日期格式写的是“yyyy-mm-dd”这条在追溯文档版本演进时非常重要没有日期的签字等于没有签字。版本号建议和产品版本号体系保持一致不要单独另起一套。2.2 修订记录比 Git 提交日志更早的变更追踪手段修订记录表格里有日期、修订版本、CRID/Defect ID、修改章节、修改描述、作者六列。CRID 是 Change Request ID 的缩写Defect ID 是缺陷编号这列的作用是把文档变更和研发管理系统里的具体诉求或缺陷关联起来。没有项目管理系统支撑的小团队也建议在修改描述里写清楚“改了什么为什么改”。修订版本从 1.1 起步不要用 v1.0、v1.1、V2.0 这种混杂的写法建议统一为两位数字语义第一位是大版本升级第二位是修订累积。修改章节列直接写“2.1.2/2.2”这种带层级的编号比写章节名更利于对照阅读。2.3 目录、表目录与图目录让百页设计文档可被快速翻阅模板里同时给出了 Catalog、Table List、Figure List 三套目录看起来繁琐但对大型模块设计文档来说必不可少。图目录和表目录不是手工维护的静态文字而是利用 Word 的“插入题注”功能生成的可更新域。具体做法是先给每张图、每个表添加题注题注格式设为“图 2-1 模块结构图”“表 2-3 数据结构定义”然后在文档靠前位置插入“图表目录”域右键选择“更新域”即可自动同步。纯文字目录则在大纲视图下统一设置标题级别再插入目录域。手工手动改页码编号的做法在文档超过 30 页以后必然会出错不推荐。2.4 关键词、摘要与缩略语清单让搜索引擎和外行都能读懂关键词字段看起来只是个供检索用的标签但模板里要求 Abstract 对全文做精炼概括这恰恰是很多工程师最不愿意写的一节。实际上摘要写得好的设计文档评审效率会高很多。缩略语清单必须覆盖全篇所有缩写格式是三列表缩写、英文全称、中文解释。比如“M2UA”这一项要写全 MTP2 User Adaptation Layer中文解释为“MTP2 用户适配层”。这条规则的价值在多人协作场景中最明显团队里不同人来自不同产品线对同一缩写的理解可能完全不同。提示缩略语清单建议放在文档开头而不是文末附录。读者遇到看不懂的缩写时不会翻到最后一页去查。3. Introduction 与 Scope把设计边界写到没有歧义3.1 Purpose一句“能直接指导编码”的标准模板里对 Purpose 的要求是“详细设计必须能够直接指导编码活动”这句话是整份 LLD 文档的验收标准。写 Purpose 时可以分两层落笔第一层写清楚这份文档服务于哪个产品或模块第二层注明读者的预期能力比如“读者应具备 M3UA 协议基础并熟悉 VOS 消息框架的调用方式”。这样一来新加入项目的开发也能判断这份文档是否适合自己作为入门资料对于文档管理者来说也更加清楚受众在什么位置。3.2 Scope把“不做什么”写入定义Scope 部分要求描述文档“包括什么、不包括什么”这是详细设计和概要设计最容易重叠的地方。HLD 管的是系统怎么拆模块、模块间怎么交互LLD 管的是一个模块内部的数据结构和函数怎么实现。如果某个模块在 HLD 里定义为“调用外部计费接口”LLD 里就不需要写计费系统的内部实现只需要在 Scope 里声明“计费相关逻辑不在本文档范围内”。边界切分的价值在多人并行开发时尤其明显上下游模块同时开工谁依赖谁、谁提供接口在 Scope 里先对齐才不会出现开发到一半才发现两个模块对接口定义各写了一套的情况。3.3 设计约束与全局假设虽然模板正文里没有单独设“约束”章节但经验上建议在 Introduction 末尾补一个“Assumptions and Constraints”子节。例如目标硬件平台的处理能力、协议栈内存上限、必须兼容的历史版本接口这类信息直接影响后续的数据结构和函数设计。文档里写不下的要给出指向其他参考文档的链接规则是每一条约束都能回溯其来源。这里的思路在代码实现中的体现是不要让设计文档中出现无法验证的约束每一条都要能对应到某个具体的硬件规格或协议规范。4. 详细设计核心数据描述与函数描述的结构化写法4.1 数据描述从简单数据到复合数据的分层模板把模块数据分为简单数据和复合数据两类简单数据包括模块级全局变量、常量、宏复合数据包括结构体、联合体等。简单数据的描述格式必须包含两个字段功能描述和数据定义。功能描述说清楚这个数据“是用来干什么的”数据定义给出实际的声明语句。如果全局变量的命名没有统一前缀规范建议在数据定义里写上清晰的命名解释例如以“g_”前缀表示全局变量、以“M2UA_MAX_”前缀表示常量宏。这些细节在代码规范不完善的团队里是设计文档最直接的补充价值。复合数据的描述格式比简单数据多一层必须包含数据结构描述、数据结构定义、数据项描述三部分。数据结构描述交代用途数据结构定义用实际编程语言写出完整定义数据项描述用表格逐项列出每个字段。以下是一个参考格式#define M2UA_MAX_SSN_LEN 16 typedef struct { unsigned char ucDstSsn; /* MTP3 目的子系统号 */ unsigned char ucSrcSsn; /* MTP3 源子系统号 */ unsigned short usCic; /* 电路识别码 Circuit Identification Code */ unsigned char aucData[M2UA_MAX_SSN_LEN]; /* 用户数据缓冲区 */ } m2ua_data_t;数据项描述对应填入表格包含字段名、字段类型、字段定义。数据项定义要说明取值范围和默认值比如“ucDstSsn 范围 0x00-0xFF默认值为 0x0A”。对于枚举字段可以用表格列出枚举名和值。这里描述的目的在于让编码人员在写代码前就对数据的生命周期有完整认识而不是一边写一边设计。4.2 函数描述八个字段加一个实现段模板中函数描述的标准格式是八个字段加一个实现段覆盖了“别人怎么用我、我怎么用别人、我改了什么、我返回什么”的全部信息。这八个字段逐一对应Function 函数名、Description 函数功能与性能描述、Calls 被本函数调用的函数清单、Data Accessed 被访问的全局变量与数据库表、Data Updated 被修改的全局变量与数据库表、Input 输入参数说明、Output 输出参数说明、Return 返回值说明。写函数设计时最容易被忽略的是 Calls 和 Data Accessed / Data Updated 两个字段它们记录了函数的外部依赖和副作用也是编码与代码 review 时最需要关心的部分。函数调用关系的部分用层次图或结构图来描述比较直观。以下是一个完整的函数描述示例/* * Function: m2ua_nif_sendto_mtp2 * Description: 向 MTP2 模块发送 M2UA 消息包 * Calls: VOS_AllocMsg, Dev_FromVspCardNoGetCpuid, VOS_FreeMsg, VOS_SendMsg * Data Accessed: 设备信息表消息发送相关全局计数 * Data Updated: 消息发送计数字段 * Input: ucLinkNo 链路号取值 0x00-0x1FpMsg 消息缓冲区指针 * Output: 无 * Return: M2UA_SUCCESS 或 M2UA_FAILURE * Others: 该函数复用 MTP3 模块向 MTP2 发消息的既有通路 */ m2ua_return_t m2ua_nif_sendto_mtp2(unsigned char ucLinkNo, m2ua_msg_t *pMsg) { /* 参数合法性检查 */ if (ucLinkNo M2UA_MAX_LINK_NO) { return M2UA_FAILURE; } if (pMsg NULL) { return M2UA_FAILURE; } /* 申请消息包空间 */ void *pMsgBuf VOS_AllocMsg(sizeof(m2ua_msg_t)); if (pMsgBuf NULL) { return M2UA_FAILURE; } /* 填写目标 CPU 信息 */ if (Dev_FromVspCardNoGetCpuid(ucLinkNo, pMsg-usDstCpuid) ! OK) { VOS_FreeMsg(pMsgBuf); return M2UA_FAILURE; } pMsg-ucDstModuleId M2UA_MODULE_ID_MTP2; pMsg-usMsgLen sizeof(m2ua_msg_t); /* 发送消息 */ VOS_SendMsg(M2UA_MODULE_ID_MTP2, pMsgBuf); return M2UA_SUCCESS; }这是一段典型的模板化实现设计文档里给出的实现段用伪码或流程图展开。伪码不用写到每行代码但要能体现完整的错误处理路径。以上面这个 m2ua_nif_sendto_mtp2 为例伪码至少应该包含参数合法性检查、消息包申请、失败回滚路径、消息内容填充、最终发送。这里的重点是培养设计人员对资源管理的全局意识确保任何一条失败路径都不会造成内存泄漏或状态残留。接口错误的处理方式也在这里一并体现失败的 return 值是否定义了对应的错误码。协议栈类模块通常还要在 Others 字段里补充并发调用注意事项比如“该函数可能被多个任务同时调用调用方需保证消息包生命周期有效”。5. 错误处理系统错误、接口错误、协议错误的三层划分5.1 系统错误与接口错误的处理策略模板把错误处理拆成系统错误、接口错误、协议错误三类。系统错误指内存分配失败、任务创建失败、信号量超时这类资源性故障接口错误指模块对外输出的错误码协议错误指协议规范里没有明确规定的情况。这三个层次的划分在代码实现上有直接映射系统错误一般用返回值配合 errno 或错误日志接口错误用模块自定义的错误码枚举协议错误则需要定义专门的告警和恢复机制。比如 M2UA 模块收到未知消息类型时模板建议在“协议错误”一节描述处理策略是丢弃消息、回送错误通知还是直接断链。5.2 错误码定义规范与可追溯性新定义接口错误码时需要列出错误码与错误原因。错误码的命名要有统一规则模块缩写加场景加错误语义。例如错误码含义触发场景M2UA_E_LINK_INVALID链路号不合法ucLinkNo 超过最大链路号M2UA_E_MSG_ALLOC_FAIL消息申请失败VOS_AllocMsg 返回 NULLM2UA_E_CPUID_GET_FAILCPU 信息获取失败Dev_FromVspCardNoGetCpuid 调用失败M2UA_E_PARAM_NULL参数为空pMsg 指针为 NULL错误码需要和日志系统配合每个错误码的出现位置、记录方式都要在设计阶段定好而不是等测试发现后再补。系统错误的处理策略一般遵循“谁申请谁释放”的原则局部资源申请失败时清理已占用资源再返回任务创建失败这种进程级错误则需要考虑是否触发主控复位或降级运行。资料引用格式遵循常见的三种情况英文文章中作者、篇名、期刊、卷号、年份、页码英文书籍中作者、书名、出版社、年份中文文献中作者、篇名、期刊、卷号、年份。版本较新的资料可以补充“访问日期”涉及内部文档时引用编号和发布日期即可。对于工程团队参考资料清单的价值不止是学术规范更是在后续文档追溯时快速判断哪些设计决策来自哪些依据避免技术演进过程中因为引入新方案而丢失决策上下文。注意模板中明确标注了“文档内容仅供参考”这一点在对外输出设计方案时能起到免责作用内部使用时则要求设计者对内容真实性负责。从数据描述的结构化到错误码定义规范整套模板的核心价值在于把设计经验沉淀成团队共识。真正用得好的团队会把模板中的章节按照自身项目情况裁剪并固化到公司文档系统里让所有新项目一开张就沿用同一套表达语言。文档模板本身并不产生设计质量但它让优秀的设计实践有了可复制的载体。本文还有配套的精品资源点击获取