尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

嵌入式项目决策记忆缺失的代价与ADR架构决策记录实践指南

嵌入式项目决策记忆缺失的代价与ADR架构决策记录实践指南 1. 为什么嵌入式项目里最值钱的东西往往没被记下来干了十几年嵌入式开发我有个越来越强烈的感受一个项目最核心的资产不是代码不是电路图而是当初那些为什么要这么做的决策过程。代码没了可以重写电路图丢了可以反推但决策上下文丢了后面接手的人只能靠猜猜错了就得交学费。我见过太多嵌入式项目的真实状态是这样芯片选型的时候硬件工程师和软件负责人吵了三天最后定了一颗 Cortex-M4 内核的 MCU理由是主频够、外设丰富、供货稳定。这个结论可能就写在某封邮件里或者干脆只存在几个人的脑子里。半年后新人入职看到代码里大量使用 DMA 和中断嵌套忍不住问为什么不用 RTOS没人能完整回答只能含糊地说当初评估过好像不太合适。至于怎么评估的、基于什么条件评估的、否掉 RTOS 的关键指标是什么全部丢失。这玩意儿在软件开发领域有个名字叫 ADR全称 Architecture Decision Record架构决策记录。说白了就是一张卡片、一个文档或者一个 commit把我们决定做什么、为什么做、当时有哪些选项、最后怎么选出来的固定下来。这个理念最早是从敏捷和软件架构圈子里流行起来的Michael Nygard 那篇经典的《Documenting Architecture Decisions》算是启蒙读物。但说实话这个工具在互联网后端团队里已经挺常见了在嵌入式领域却依然稀罕。为什么?因为嵌入式项目有它的特殊性。嵌入式开发通常是软硬件协同决策链条长而且很多决定一旦落到 PCB 上、焊到板子里就物理不可逆了——你软件写错了还能改Flash 烧错了还能重烧但引脚分配错了、电源方案选小了、Flash 容量买小了这些是改不动的。越是不可逆的决策越需要记录决策依据可恰恰是这种项目大家越不爱写文档。这背后的原因很现实嵌入式项目周期紧、调试占时间、硬件迭代慢开发者习惯性把精力花在让板子跑起来上觉得写文档是浪费时间。这个观念得改。不光是文档有价值这种空话而是嵌入式项目的技术债里最大的一笔往往是决策记忆缺失债。今天这篇我把自己在几个嵌入式项目里推行 ADR 的完整思路、模板、踩过的坑全部摊开讲希望能帮在固件开发、板卡设计、软硬件协同项目里挣扎的朋友们找到一条让记忆不丢失的路。2. 嵌入式项目到底缺什么记忆2.1 代码注释和 Commit Message 远远不够很多人会说我们项目有代码注释啊有 git 提交记录啊怎么会缺记忆?但嵌入式项目里真正关键的决策往往散落在代码之外的层面。举个例子一个典型的电机控制项目主控芯片选型时对比过 A、B、C 三颗芯片最后选了 A。代码里你只看到#include stm32f4xx.h看不到为什么不用 B。B 的主频更高但封装是 BGA 不好手工焊接C 的功耗更低但 ADC 采样率和 DMA 支持的通道数不够。这种决策写不进代码commit message 里顶多写一句更换主控芯片为 STM32F4背后的三颗芯片对比矩阵、焊接工艺约束、外设需求清单全丢了。更隐蔽的是软硬件接口层的决策。比如串口 DMA 收发缓冲区的设计为什么用环形缓冲区缓冲区为什么定 256 字节而不是 128 或 512。这背后可能有中断延迟的实测数据、有无 DMA 半传输中断的硬件差异、内存占用和通信吞吐量的折中。这种决策直接决定代码结构如果后来者不知道当初的约束条件很可能优化一下把缓冲区改成 64 字节结果在高波特率下丢包查了三天才发现是自己把缓冲区改小了。2.2 嵌入式项目的决策生命周期更长web 后端项目一个架构决策可能影响的是服务集群怎么扩展改起来相对灵活。但嵌入式项目不一样一个决策的生命周期可以从需求分析一直延续到产品退市。硬件方案定了后面十年的维护都受这个约束。固件架构定了即使换芯片核心的设计约束还会延续。我做车载电子那几年有个项目里用了外置 EEPROM 存储标定参数因为当初选 MCU 时内部 Flash 容量刚好够用但余量不大就设计了一套将参数区放到外部 EEPROM 的方案。这个决策当时没有记录。三年后产品迭代新 MCU 内部 Flash 大了四倍完全可以取消外部 EEPROM 降低成本但没人知道当初为什么要用外部存储——是因为容量不够还是因为擦写寿命还是因为抗震动可靠性?结果项目组不敢动这个设计每台设备继续多花几毛钱的 BOM 成本。几毛钱看着不多一年出货百万台就是几十万。这不是技术问题这是记忆缺失造成的真金白银损失。2.3 团队协作中的口头知识陷阱嵌入式项目往往是软硬件协同硬件工程师、固件工程师、测试工程师各管一段。大量的决策发生在会议室、实验室、生产线的沟通中。这些场景里说出来的结论如果没有同步记录下来就成了团队里的隐性知识。隐性知识的问题是它在的时候大家觉得理所当然一旦相关人员离职、转岗或者记忆模糊整个团队就面临失忆。我带过的一个团队有位资深硬件工程师特别擅长电源设计他决定板子上所有 3.3V 和 1.8V 电源轨都用 LDO 而不是 DC-DC理由是纹波控制对 ADC 采样精度影响大。这个决策在团队里人尽皆知但他离职之后新来的硬件工程师觉得 LDO 效率低、发热大改成了 DC-DC结果 ADC 采样的噪声底噪从正负 2mV 变成正负 15mV整个传感器的精度指标直接不合格。后来翻遍文档才在旧版原理图评审记录里找到一句为保障 ADC 精度电源方案选用低纹波 LDO。如果当时有一条结构化的 ADR记录了纹波实测曲线和精度测试数据新硬件工程师第一时间就能知道这个约束根本不会踩这个坑。3. ADR 的写法与模板不整虚的直接给方案3.1 一个可落地的 ADR 模板标准的 ADR 模板有很多变体但核心要素万变不离其宗背景、决策、理由、后果。我在嵌入式项目里用的模板是在 Nygard 基础上定制过的增加了验证方式和风险与缓解两栏因为嵌入式决策必须绑定验证手段否则后任者无法判断这个决策现在还有效没有。我的模板长这样# [编号] 标题一句话描述决策内容 ## 状态 - 提议中 / 已接受 / 已替代 / 已废弃 ## 背景 - 要解决什么问题 - 当前的技术约束、业务约束、时间约束 - 相关的需求和依赖 ## 决策 - 最终选定的方案一句话说清楚 - 关键参数和关键设计点 ## 备选方案 - 方案A描述 优点 否决原因 - 方案B描述 优点 否决原因 ## 理由 - 为什么选这个方案列出决定性的 2-5 个理由 - 有数据就贴数据有测试结果就贴测试结果 ## 后果 - 正面带来什么好处 - 负面接受什么代价埋下什么隐患 ## 验证方式 - 怎么证明这个决策是有效的测试项、指标、实验 - 什么条件下需要重新审视这个决策 ## 关联 - 关联的其他 ADR、需求、代码模块、硬件版本这个模板看着比网上很多版本复杂但在嵌入式项目里很值得。因为嵌入式决策多数是环环相扣的没有关联栏你很难追溯这套决策网络的上下文。硬件选了某个 MCU会影响软件用不用 RTOS会影响驱动怎么分层会影响测试方案怎么设计。这些关联不写下来光靠人脑根本记不住。3.2 选题原则不是所有决定都配写 ADR写 ADR 最大的误区是事无巨细都记最后变成了流水账没人看。真正值得写 ADR 的决策至少要满足一条影响面大、代价高、难逆转。我整理过一套嵌入式项目的 ADR 选题过滤清单芯片/模组选型替代成本高直接影响 BOM、开发周期、后续维护必须写操作系统方案裸机还是 RTOS选哪个 RTOS做不做二次开发必须写通信协议设计私有协议还是标准协议定长还是变长重传机制怎么定必须写存储布局与分区Flash 分区、升级方案、掉电保护策略必须写电源与低功耗架构电源域划分、休眠机制、唤醒源选择必须写关键算法方案传感器融合算法选型、控制算法结构建议写工具链与构建系统IDE、编译器、构建框架的选择建议写测试策略自动化测试框架、HIL 测试方案、产测方案的架构性选择建议写至于某个函数的实现用循环还是递归某个 GPIO 是开漏还是推挽某处代码要不要加断言这些细节没必要写 ADR。写多了反而稀释注意力。判断标准很简单如果明天这个决策被推翻需要改动的代码/硬件面积有多大连带风险有多高。大就写小就别折腾。3.3 时机与流程嵌入式项目里什么时候写最舒服有人习惯决策做完了再补写 ADR我不太建议。最佳时机是决策刚定下来、还没动手实施的时候写。那时候讨论的细节、对比过的数据、否决的选项都在脑子里写起来最快最完整。等代码写完、板子调完再补基本等于考古能回忆出七成就算不错了。我在项目里的实际操作方式也很简单每次架构评审会结束时当场认领一个 ADR 编写人要求两天内提交初稿。如果评审结论触发了 ADR 的状态变化比如原来的方案被否了、换新方案了那就在下次评审里安排更新对应 ADR。这个流程不复杂但一定要有人负责跟踪否则很容易不了了之。ADR 的存放位置也很关键。嵌入式项目和 Web 项目不太一样Web 项目可以直接放在仓库的docs/adr/目录因为整个团队都在一个代码仓库里协作。但嵌入式项目的软硬件团队往往不是一套仓库硬件工程师不一定看 Git。我的选择是软件团队的 ADR 放在固件仓库的docs/adr/硬件团队的 ADR 放在硬件版本管理的文档目录里同时在项目共享文档区建一个总索引。这个总索引是给所有人看的谁要查某个决策先从索引里找到对应 ADR 编号再去对应仓库看细节。4. 嵌入式 ADR 实战三个典型决策拆解4.1 芯片选型类 ADR从拍脑袋到有据可查芯片选型是嵌入式项目里最典型的高代价不可逆决策也是最应该有 ADR 的场景。我分享一个实际做过的例子项目是一款便携式数据采集设备需要 4 路模拟量采集、1 路 CAN 通信、低功耗、批量成本控制在某个范围内。候选芯片有三颗A 是 Cortex-M0 内核主频 48MHz价格低但片上 ADC 只有 12 位需要外挂 ADC 芯片B 是 Cortex-M4 内核主频 80MHz内置 16 位 ADC价格是 A 的两倍C 是 Cortex-M7 内核主频 200MHz性能过剩价格最高。这个选型过程如果只写一个结论选用 B后面的人永远不知道为什么。ADR 里我记录了完整的对比矩阵维度方案AM0外挂ADC方案BM4内置16位ADC方案CM7内置16位ADCBOM成本低但需要外挂ADC和配套电路中高PCB面积大外挂ADC占面积小小开发周期长需要调试SPI/ADC驱动短内置ADC短功耗低低偏高ADC精度12位需校准16位满足需求16位供货风险中低多家渠道高单一来源最后选 B 的决策理由是BOM 成本虽比 A 高约 15%但节省了外挂 ADC 的 PCB 面积和调试周期且 16 位 ADC 满足精度需求不需要额外的校准和补偿算法。C 性能过剩功耗和成本都是负担。这个 ADR 的价值在三个月后立刻体现出来了。B 芯片出现了供货紧张采购部门提出换用 C 芯片的备选方案。但因为 ADR 里记录了当初选 B 的决策依据团队很快就能判断C 芯片功耗偏高如果换用需要重新评估电池续航同时 C 供货单一来源的风险更大不比 B 好。于是果断放弃换型改为采购备货。没有 ADR 的话可能又要开三轮会才能达成共识。4.2 RTOS 与裸机路线之争必须白纸黑字定下来嵌入式项目里每次选 RTOS 都能引发一番争论而且争论的核心往往不是技术本身而是当初到底为什么不用 RTOS这种失忆梗。我参与过的一个电力仪表项目就经历过裸机转 RTOS 的过程。当时团队里有一部分人主张裸机到底理由是简单可控、内存占用少、没有调度开销另一部分人坚持上 RTOS理由是功能模块越来越多裸机的超级循环已经难以维护。最后拍板用 RTOS这个决策对应了一条 ADR。我记录了关键的决策理由功能模块从 8 个膨胀到 20 多个裸机的超级循环里while(1)已经膨胀到三千多行新增功能极易引入优先级和时序问题同时目标 MCU 的资源足够跑 RTOSRAM 占用约多 4KB完全能接受。更加关键的是ADR 里把这个项目的任务划分基本原则也固定了。比如高实时性任务电流采样、保护逻辑用高优先级任务界面刷新用低优先级任务不允许在中断服务函数里做耗时操作。这些原则写下来之后新人开发时就有了行为准则不会出现在定时器中断里刷 LCD 导致采样抖动这种低级错误。4.3 Flash 分区与升级策略最容易变成烂账的决策嵌入式产品基本都逃不过 OTA 升级或者本地升级。Flash 怎么分区、Bootloader 和 App 怎么划分、升级失败怎么回滚这个设计一旦定下来整个生命周期都要跟着走而且和芯片型号强绑定——换了 Flash 容量、换了芯片整个方案可能都要推翻。我见过一个活生生的烂账案例。某项目在量产一年后产品需要增加一个新功能固件体积预计要扩大 40%。但当初 Flash 分区时App 区的大小是拍脑袋定的没留余量。结果新功能加不进去被迫做一次重新分区 全量升级的特殊版本还要考虑升级过程中断电导致变砖的风险。整个过程折腾了半个多月其实当初只需要多留一点空间或者做一个可扩展的动态分区设计。这个教训催生了我现在坚持的一条 ADRFlash 分区方案必须写。我在 ADR 里记录的内容包括分区表的起始地址、大小、各分区用途、升级流程、回滚方案、预留空间比例、以及为什么预留这么多——通常是根据历史固件增长速度估算的。这样后续者想调整分区时先读 ADR明白当前分区的边界条件和历史原因再评估能不能动。还有一个容易被忽略的点掉电保护策略。如果升级过程中突然断电系统怎么恢复?是双备份还是单备份加引导恢复?这个决策如果不说清楚后面的人写升级逻辑时很容易默认升级失败就出厂恢复把用户数据全清了。ADR 里把这个决策和理由写清楚就能避免这种灾难。5. 推行 ADR 路上的拦路虎与破解办法5.1 没时间写综合征推行 ADR 遇到最多的阻力就是一个字忙。嵌入式项目节奏紧大家觉得写文档不是干活。我承认写 ADR 确实要花时间一条完整 ADR 写下来半小时到一小时是正常的。但我不想用磨刀不误砍柴工这种大道理来压人只想算一笔账一次没有 ADR 支撑的架构决策讨论通常要开几次会每次一小时好几个人参加。如果这个决策三个月后被重新质疑又要开会。已经写过 ADR 的决策新成员可以直接读文档省掉至少一次会议的时间。一条 ADR 抵消一场会这个投资回报率是正的。更实际的做法是降低写入门槛。不要求一开始就写得特别全先建个 ADR 文件把决策结论写上再慢慢补背景和理由。只要文件存在后面的人就有线索可循。最怕的是直接不建让所有信息只停留在讨论里。我个人的习惯是每次架构讨论结束后顺手在共享文档里开一条 ADR标题先写上结论先写上理由用关键词记一下后续有时间再完善。这个种子机制很管用很多 ADR 就是在种子的基础上慢慢长大的。5.2 ADR 没人看怎么办写下没人读是所有文档的通病。ADR 要避免这个问题唯一的办法是把它嵌入到工作流里而不是作为独立文档存在。我在团队里做过几个动作每次新功能设计评审前要求评审材料里必须列出受影响的 ADR 编号。如果没有相关 ADR就说明这是一个新决策需要在新功能开发前补一条 ADR。代码评审时如果代码逻辑和设计目标有关联要求 PR 描述里引用 ADR 编号。新人入职培训时安排一次项目架构决策阅读环节把项目里已有的 ADR 从头读一遍同时讲解每条 ADR 对应的硬件设计和代码模块。这些动作的核心目的是让 ADR 成为工作流程的一部分而不是摆在文档库里的摆设。5.3 ADR 过期了怎么办嵌入式项目生命周期长一个 ADR 写完之后可能在一年后因为器件停产、需求变更、技术迭代而失效。如果失效的 ADR 不处理最后就会变成一堆僵尸文档反而误导后人。我在流程里设置了 ADR 的定期体检机制。项目里程碑节点包括方案评审、样机评审、量产评审都检查一遍已有的 ADR看有没有状态需要更新。如果一个 ADR 对应的决策已经被实际执行所推翻比如换了主控芯片那么旧 ADR 状态标为已替代新 ADR 记录新决策。这样一条条串起来整个决策的历史脉络就清晰了。对比那些文档只写一次之后再也不管的项目有状态管理的 ADR 库才是真正有价值的决策记忆库。5.4 团队协作中的边界问题嵌入式项目的软硬件团队写 ADR 的边界容易模糊。比如引脚分配是硬件牵头定的但直接影响固件开发。谁负责写这条 ADR?我的经验是决策主责人写相关方审阅。引脚分配这件事硬件工程师主责但必须经过固件工程师的确认ADR 里要有固件工程师的签名或者评审记录。同样一个决策如果软硬件理解不一致ADR 就充当了共识固化的工具。比如某个 GPIO 的默认电平硬件工程师认为是上拉、固件工程师认为是下拉这种不一致如果不通过 ADR 定下来等板子贴出来才发现就是一轮飞线或者返工。我见过最夸张的一次硬件原理图里把 boot 引脚默认设计为高电平固件工程师却一直按默认低电平启动来调试整整两周找不到原因。最后翻原理图才发现硬件设计认为默认高电平更合理但根本没告诉软件。如果当初在硬件设计评审时记录一条 ADR哪怕只有一句话也不会浪费两周时间。6. 从一条 ADR 到一套决策记忆库6.1 ADR 之外的配套档案ADR 是决策记忆的核心但光有 ADR 还不够。我逐渐建立了一套决策记忆库的配套档案体系需求追溯表把需求、ADR、代码模块、测试用例关联起来硬件版本变更记录每次硬件改版记录对应的 ADR 变化实验、测试数据存档ADR 里引用的验证数据原始数据文件要归档故障复盘记录线上问题、生产问题复盘时如果发现是决策层面的问题关联到对应 ADR这套档案不要求做得特别复杂只要关系和数据是连贯的就能在关键时刻提供完整上下文。6.2 小团队怎么低成本起步很多读者可能觉得这套做法适合大团队自己就三五个人的小项目值得搞吗?我的回答是越小的团队越值得因为小团队的记忆往往完全依赖核心一两个人。核心成员一旦变动整个项目的决策上下文就断层了。小团队的起步方式可以非常轻在 Git 仓库里建一个docs/adr/目录用 Markdown 文件存 ADR每条一个文件编号 0001 开始遇到关键决策时花 20 分钟写一条 ADR不用追求完美每次代码提交时如果和某条 ADR 相关在 commit message 里加ADR-0001的引用项目例会时如果有 ADR 状态变化花 5 分钟同步一下这套流程不需要工具链不需要额外平台坚持下来项目历史就会被一点点记录下来。等团队规模扩大、人员更替的时候会发现这些 ADR 是整个项目最宝贵的入职教材和决策底稿。6.3 工具选择与自动化如果团队想更进一步可以引入一些轻量工具Git Markdown最零成本的方案ADR 跟着代码仓库走天然有版本管理文档平台如 Confluence、语雀、飞书适合跨团队共享查阅但要注意和代码仓库的同步带模板的 ADR 生成工具命令行工具可以快速生成 ADR 模板文件省去重复输入格式的时间我个人最喜欢的是ADR 文件跟随代码仓库这种模式。它的好处是ADR 和代码的变更历史天然关联你可以通过 git log 看到某条 ADR 是哪次提交引入的当时的代码是什么状态。这种时间线上的关联性是独立文档平台很难模拟的。7. 写在最后的实操体会项目做个五六个之后我越来越清楚一件事架构决策记录这件事难的不是方法和格式而是把它当成项目基础设施的一部分来对待。就像你画原理图不会省略电源滤波电容写代码不会省略错误处理做项目管理也不应该省略决策记录。我在实际项目里最深的体会是ADR 的力量不是立刻显现的。前几个星期你可能感觉不到什么变化甚至觉得是在浪费时间。但半年后、一年后当新人快速上手、当架构争论能快速收敛、当人员变动没有造成知识断层你就会意识到这些看起来不起眼的文档已经把团队从靠人脑记忆升级成了靠制度记忆。最后分享一个我在每个项目启动时都会做的小动作在项目仓库初始化的时候就把docs/adr/目录建好放一个 README 简要说明 ADR 的格式和流程再放一个0000-template.md模板文件。这个动作只需要十分钟但它像一个提醒器让团队从一开始就知道这个项目不是先做起来再说而是从第一天就重视决策的记忆。等到项目结束、产品落地、团队解散或重组那天你会特别庆幸当初做了这个决定。因为那些 ADR 还在那里记录着这个项目从无到有的每一个关键选择等待着下一个接手的人来翻阅。
返回列表