十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

软件架构设计说明书:单一数据源生成与一致性体检

软件架构设计说明书:单一数据源生成与一致性体检 简介《软件架构设计说明书》以图书杂志采购和借阅系统为实例面向项目经理、程序设计员、测试人员及软件工程专业学生系统呈现从需求到部署的架构设计全过程适合作为课程设计、毕业设计与架构入门的学习范本。资源包共1个文件为一份367KB的docx文档体量轻巧却内容完整可离线阅读与打印批注。文档依次展开简介、架构表示方式、设计目标与约束、用例视图、逻辑视图、进程视图、实施视图、部署视图、接口与通信、非功能性需求以及架构决策与评估等章节其中用例视图列出用户注册、图书搜索、采购订单创建、借阅归还等关键用例逻辑视图给出业务逻辑层、数据访问层与用户界面层的层次划分部署视图说明组件在物理节点上的分布并附性能、可扩展性、安全性与容错性等质量需求。目前已有1439人学习可为撰写架构文档、制定开发计划与搭建测试框架提供直接参照。1. 一份软件架构设计说明书.docx 为什么总在评审会上失效需求评审到一半有人问设备接入层为什么压在业务层上面你说文档里写了打开那份软件架构设计说明书.docx发现最后修改日期是三个月前架构图还是一张被压花的截图接口表里的字段和代码里的结构体早对不上。问题通常不是写得不够全而是写完之后没人能验证它对不对图是死的表是手抄的换个作者章节顺序就变一遍。这份文档真正要解决的是让架构决策、组件边界、接口契约和质量约束变成可评审、可追溯、可回归检查的产物。它面向三类人要动手搭骨架的架构师、要照着写模块的开发以及专门挑刺的评审人。下面把一份能落地的软件架构设计说明书拆开讲章节骨架怎么定接口和架构图怎么从单一数据源生成Qt 上位机软件架构与智驾软件架构这类具体场景该补哪些章节最后用脚本给它做一次一致性体检。2. 软件架构设计说明书.docx 的章节骨架怎么定2.1 先定视图清单再定章名常见的失败写法是章名写成系统概述总体设计详细设计这种。评审人翻完第一章还在看背景找不到能质疑的点。可靠的做法是先把视角viewpoint列出来再让章名和视角一一对应。我一般会按这套骨架排1 范围与约束 / 2 逻辑视图组件与职责/ 3 运行视图进程、线程、时序/ 4 开发视图模块、依赖、构建/ 5 部署视图 / 6 接口契约 / 7 数据模型与存储 / 8 质量属性与场景 / 9 关键决策记录 / 附录 术语表。这么排的好处是把谁跟谁说话和什么时候说话彻底分开。逻辑视图解决静态依赖运行视图解决线程和周期评审时可以分块推进一块过完再进下一块。全篇通读一遍的结果往往是评审人只记得第一页那张图。第 9 章的关键决策记录ADR最容易被省掉但它恰恰是半年后新人问为什么不用现成框架时唯一能翻出来的东西。2.2 每个章节写什么才算写够了只列章名不够得给每章定必填字段和验收标准否则每个人写出来的密度差三倍。下面这张表建议直接抄进模板的编写说明页。章节必填字段判定写够了的标准逻辑视图组件名、一句话职责、依赖方向、对应代码目录每个组件都能指到仓库里一个真实目录运行视图进程/线程、通信方式、周期、队列长度每个周期性任务都有明确周期数值接口契约名称、方向、传输方式、字段、超时、错误码字段与代码里的结构体逐项对齐质量属性场景六要素、目标值、验证方式目标值是数字验证方式可执行关键决策决策、备选方案、理由、影响范围、日期至少记录一条被否掉的备选方案提示把职责限定在一句话内。写不下就说明这个组件该拆这个约束比任何架构原则都管用。2.3 用脚本生成章节骨架别手抄目录手工维护目录的代价在插入新章节那天集中爆发编号全乱、样式不一致、导航窗格认不出标题。常见做法是把章节目录写成一个 Python 列表用 python-docx 生成骨架文件后续所有人从这份骨架往下填。from docx import Document from docx.shared import Pt # 章节结构的唯一来源改这里就等于改全篇目录 SECTIONS [ (1 范围与约束, [1.1 业务目标, 1.2 外部约束, 1.3 术语与缩写]), (2 逻辑视图, [2.1 组件清单, 2.2 依赖关系, 2.3 代码目录映射]), (3 运行视图, [3.1 进程与线程, 3.2 周期与队列, 3.3 关键时序]), (6 接口契约, [6.1 外部接口, 6.2 内部接口, 6.3 错误码与超时]), (9 关键决策记录, [9.1 决策清单, 9.2 备选方案对比]), ] def build(out软件架构设计说明书.docx): doc Document() normal doc.styles[Normal] # 统一改样式不要逐段设字体 normal.font.name 微软雅黑 normal.font.size Pt(10.5) for title, subs in SECTIONS: doc.add_heading(title, level1) # 用内置标题样式 doc.add_paragraph(待填写结论 / 依据 / 影响范围) for s in subs: doc.add_heading(s, level2) doc.add_paragraph(待填写) doc.save(out) build()逻辑说明SECTIONS是目录的唯一来源增删章节只改这一处正文编号交给 Word 的多级列表不手打数字。add_heading(level1)用的是内置标题 1样式导航窗格、自动目录域、后面的脚本检查都依赖它手写加粗大字号的标题在脚本眼里等于不存在。占位段落故意写成结论/依据/影响范围三段式逼作者写出可判断的内容而不是本模块负责处理业务逻辑这类谁都能写的话。参数说明level取值 1 到 9架构说明书最多用到 3正文字号定在 Normal 样式上而不是逐段设置换模板时只改一行。如果团队有既定的封面和页眉用Document(template.docx)打开再写样式继承才生效。2.4 什么时候该拆成两份文档单份 docx 超过六七十页或者接口契约需要单独给外部合作方签字时就该拆。我的分法是把架构总览和接口契约ICD分开总览讲为什么这么分ICD 讲字段和时序。原因是两者的变更频率差一个数量级ICD 可能一周改两次总览半年才动一回合在一起的结果是总览的版本号被接口变更拖着走评审时没人说得清这一版到底改了架构还是只改了字段名。3. 让架构图和接口表可追溯从单一数据源生成 docx3.1 把接口契约写成 YAML手抄的接口表一定会过期因为它和代码是两个真相。可行解法是让接口先落成机器可读的定义文档只是它的一种渲染结果。# interfaces.yaml —— 接口契约的唯一来源 - name: DeviceCommand direction: upstream-device # 调用方向用于自动生成通信视图 transport: tcp # tcp / 串口 / 共享内存 / dds period_ms: 20 # 发送周期必须与代码定时器一致 timeout_ms: 100 fields: - {name: cmd_id, type: uint16, unit: -, desc: 指令码} - {name: seq, type: uint32, unit: -, desc: 递增序号用于丢包检测} - {name: payload, type: bytes, unit: -, desc: 变长负载长度由头部给出}逻辑说明direction和transport这两个字段是给图用的渲染成表格的同时能喂给 PlantUML 或 D2 之类的图生成器画通信视图图和表就不会互相打脸。period_ms和timeout_ms是评审追问最多的两个数必须和代码里的定时器、超时配置逐一对齐对不上就说明有一边该改了。3.2 用 python-docx 把 YAML 渲染成表格import yaml from docx import Document def render_interfaces(doc, pathinterfaces.yaml): items yaml.safe_load(open(path, encodingutf-8)) for it in items: doc.add_heading(f接口{it[name]}, level3) doc.add_paragraph( f方向 {it[direction]}传输 {it[transport]} f周期 {it[period_ms]}ms超时 {it[timeout_ms]}ms ) table doc.add_table(rows1, cols4) table.style Light Grid Accent 1 # 内置样式WPS 下不会错位 for i, h in enumerate([字段, 类型, 单位, 说明]): table.rows[0].cells[i].text h for f in it[fields]: cells table.add_row().cells cells[0].text, cells[1].text f[name], f[type] cells[2].text, cells[3].text f[unit], f[desc] doc Document(软件架构设计说明书.docx) render_interfaces(doc) doc.save(软件架构设计说明书.docx)逻辑说明函数写完直接存回原文件所以生成流程可以并入任何一次文档更新。字段顺序沿用 YAML 里的顺序评审人比对代码中的结构体定义时是按同样顺序看的顺序一乱比对成本立刻上升。参数说明table.style要选目标环境里确实存在的内置样式自绘边框在别的办公软件里经常掉字号不要单独设交给 Normal 样式统一控制。注意这个脚本会覆盖原文件先提交一版再跑别拿唯一的文档做实验。3.3 架构图的生成与编号图源建议放在仓库里比如docs/figures/*.puml用一条构建命令生成 PNG 或 SVG再用add_picture(..., widthCm(15))插进文档。图题统一成图 X-YX 是章号Y 是章内序号。手写交叉引用迟早会断Word 的引用域在文件被转存几次之后经常失效稳妥做法是在附录放一张图索引表脚本生成时顺带刷新编号。图从源码渲染还有一个附带好处评审提意见时改的是源码下一次生成自动同步不会出现图改了但文档里还是旧截图。3.4 把文档生成挂到流水线上接口 YAML 一改文档是否同步就该由流水线回答而不是靠人的自觉。做法很直接在持续集成里加一个任务检测到interfaces.yaml有变更就重新生成 docx 并作为产物上传同时在合并请求的说明里贴出接口表的差异。评审人打开请求就能看到这次改了哪个字段、周期从多少变成了多少。把这件事做成流水线的结果之后文档过时从一个道德问题变成了一个构建状态。4. Qt 上位机与智驾场景下说明书要补的章节4.1 Qt 上位机软件架构把线程模型写死上位机文档最容易糊弄的就是并发部分只画三层框图不写谁在哪个线程。真正要落到纸面的是这几项对象属于哪个线程、跨线程用什么连接方式、队列长度上限、以及哪些调用是异步的。对象/模块所属线程跨线程方式队列上限备注主窗口 UIGUI 线程直接调用-禁止任何阻塞 IO串口收发通信线程信号槽 QueuedConnection64 帧超限丢最旧帧数据落盘存储线程信号槽 环形缓冲4096 条按时间切片写盘协议解析工作线程信号槽128 帧解析失败入错误队列写清这张表的价值在于评审时能一眼看出哪些调用是跨线程的。Qt 里常见的坑基本都出在这里耗时 IO 放在 GUI 线程导致界面卡住moveToThread只搬了父对象没搬子对象串口在子线程读写UI 却直接调它的方法。另外版本约束也得进文档Qt 大版本、用到的模块串口、图表、以及第三方库版本都要在第 1 章的约束小节里明写不然换台机器编译出来的行为可能不一样。4.2 智驾软件架构实时性与降级策略单独成节智驾方向的说明书除了常规模块划分感知、融合、规划、控制还得补三类内容。第一类是实时性指标各环节周期、抖动上限、端到端延迟预算这些要写成数字而不是形容词。第二类是通信中间件配置话题名、服务质量等级、以及接口描述文件的版本配置不一致往往表现为偶发丢帧最难排查。第三类是降级策略建议单独做一张表写清故障、降级动作和恢复条件。故障降级动作触发条件恢复条件单路传感器失效降低融合权重继续运行连续 3 帧无数据连续 20 帧数据正常定位精度下降限速并提示接管协方差超阈值持续 500ms精度回到阈值内 2s通信链路超时切换至保守控制策略心跳超时 200ms心跳恢复且稳定 1s功能安全分析危害分析、失效模式分析不建议整篇塞进架构说明书写清引用关系即可架构章节负责说明安全机制落在哪个组件上分析结论放在独立文档两边用一张映射表对上。4.3 质量属性场景表把高性能换成可测数字高实时低延迟稳定可靠这类词在评审里等于没写。换成场景六要素之后讨论才有落点。质量属性场景目标值验证方式实时性每 10ms 收到一帧点云正常负载端到端 ≤ 30msP99台架打点统计吞吐8 路设备同时上报不丢帧CPU ≤ 60%压测 30 分钟可恢复通信进程异常退出3s 内自动重启并续传注入故障脚本可维护新增一路设备协议改动不超过 3 个文件代码评审记录4.4 延迟预算的算例预算表要进说明书不是进汇报材料。下面这段脚本用来核一遍各项占比。# 端到端延迟预算采集 - 传输 - 处理 - 显示 budget_ms {采集: 2, 传输: 5, 处理: 18, 显示: 5} total sum(budget_ms.values()) margin total * 0.2 # 余量比例按平台抖动实测值定别照抄 print(f预算合计 {total}ms含余量上限 {total margin:.1f}ms) for name, v in budget_ms.items(): print(f{name}: {v}ms 占比 {v / total:.0%})逻辑说明占比超过一半的那一项就是评审必须追问的地方处理 18ms里如果再拆不出子项说明这块还没设计完。margin是给调度抖动留的空间比例要按目标平台实测的抖动值倒推直接抄 20% 容易在高负载场景翻车。参数说明里的每一项都要能指到对应的实现位置指标和代码对不上的预算表只是装饰。5. 给说明书做一致性体检解析与回归检查5.1 用脚本读回文档生成完不算结束还得能读回来查。文字解析这步能拦住大部分低级问题标题层级跳级、占位符没删、表格空着、章节被误删。from docx import Document import re def norm(style_name): # 不同语言版本下样式名可能是 Heading 1 或 标题 1 m re.search(r(\d), style_name) return int(m.group(1)) if (Heading in style_name or 标题 in style_name) and m else 0 doc Document(软件架构设计说明书.docx) headings [p.text for p in doc.paragraphs if norm(p.style.name)] todo [p.text for p in doc.paragraphs if 待填写 in p.text] print(章节数:, len(headings), 未完成占位:, len(todo)) last 0 for p in doc.paragraphs: lvl norm(p.style.name) if lvl 0: continue if lvl last 1: # 出现跳级比如从标题1直接到标题3 print(层级跳级:, p.text) last lvl逻辑说明norm先把样式名归一化成数字避免换个语言版本的办公软件就误判。检查项不追求格式漂亮追求的是没写完这件事在流水线上就会变红。表格为空的检查可以遍历doc.tables看是否存在只有表头没有数据行的表。5.2 反向生成类型定义让文档和代码共用一份契约比检查更彻底的做法是把接口定义反过来喂给代码。同一份 YAML 既可以渲染成文档里的表格也能生成 C 结构体或 Python 数据类的骨架团队提交时直接用生成结果手写结构体这一步就没了。这样接口变更只可能发生在一个地方文档和代码之间的偏差从审核发现变成不可能发生。生成时注意保留两个容易被优化掉的字段递增序号和原始字节长度。回放历史数据排查丢包时正是靠这两个字段定位问题出在哪一段链路、丢在第几帧。字段一旦为了省空间被删掉事后只能靠猜。本文还有配套的精品资源点击获取
返回列表