【嵌入式架构】项目越来越难维护?从全局变量到分层架构的避坑指南
做过几个嵌入式项目后你大概率会遇到这种情况——项目刚开始开发得飞快后面越来越难维护。新增一个功能要改十几个文件。修一个Bug冒出来三个新Bug。新人看代码看得头皮发麻。老员工走了以后没人敢动代码。问题到底出在哪今天我想把这件事掰开了聊。一、项目是怎么一步步失控的每个项目刚开始的时候代码不到100行逻辑简单结构清晰开发效率极高。然后需求像潮水一样涌来——按键处理、OLED显示、蓝牙通信、温湿度采集、电池管理、OTA升级、手机APP对接、云平台数据同步、日志系统……工程规模从几百行膨胀到几万行。然后各种诡异的问题开始冒头改了蓝牙代码显示功能莫名其妙挂了。修了显示逻辑功耗突然飙了。加了一个传感器OTA升级开始失败。这不是个别现象而是几乎所有嵌入式项目都会经历的失控曲线代码量在涨开发周期在涨Bug数量也在涨而且涨得越来越快。二、问题真的出在代码质量吗很多人第一反应是代码写得差。但代码质量差只是表象。真正的问题是系统复杂度失控了。随着需求增加模块越来越多、数据越来越多、依赖关系越来越复杂。如果没有架构设计来约束系统会像滚雪球一样不断膨胀最后变成一团拆不开的毛线球。打个比方你在一个房间里堆东西刚开始随便放找什么都容易。但东西越来越多之后没有分类、没有标签、没有固定位置最后你自己都不知道什么东西在哪。嵌入式软件也一样。模块之间的依赖关系如果不受控复杂度就会指数级增长。我见过一个项目光梳理模块间的调用关系就花了两个人一周。一周什么正事都没干就画了张依赖图。三、全局变量——最危险的代码说到依赖失控全局变量是头号元凶。刚开始用extern全局变量的时候你会觉得非常方便——想用数据直接访问想修改状态直接赋值开发速度飞快。但随着项目变大全局变量越来越多每个模块都可以访问和修改最后没人知道一个变量在哪里被修改、哪些模块依赖它。看似只修改了一个变量实际上影响了整个系统。看看这张图。5个全局变量6个模块15条依赖线。这还只是一个简化后的例子。真实项目中几十个全局变量、上百条依赖线是常态。全局变量最大的危害不是不安全是不可追踪。你改了一个变量的值根本不知道这个改动会影响到哪些模块影响有多深。我之前review过一个项目一个sys_mode变量被7个文件读写改了一个赋值语句三个不相关的功能同时出了问题。查了两天才定位到原因。四、模块之间为什么越来越耦合来看一个典型的场景显示模块里直接判断ble_connected这个变量。// display.cvoiddisplay_update(void){if(ble_connected){lcd_show_icon(ICON_BT_ON);}else{lcd_show_icon(ICON_BT_OFF);}}看起来没什么问题对吧但这里已经埋下了隐患——显示模块依赖了蓝牙模块的内部状态。未来蓝牙逻辑变化比如从直连变成网关转发显示模块也必须跟着修改。这就是耦合。耦合最大的特点是修改一个模块影响多个模块。项目越大问题越明显。左边是典型的耦合设计——每个模块互相直接访问牵一发而动全身。右边是解耦设计——模块之间通过事件总线通信改一个模块不影响其他模块。说实话左边那种全连接的拓扑我见过太多团队这么干了。刚开始就两三个模块互相调用很自然。等模块多了才发现依赖关系已经是一团乱麻想拆都拆不开。五、为什么后期开发越来越慢很多团队都有这样的经历第一版开发用了3个月。第二版用了6个月。第三版用了1年。为什么因为后期开发的时间大部分不是在写代码而是在理解代码。阅读旧代码、查找依赖关系、回归测试——这些时间占了开发周期的大头。说明系统复杂度已经超过了团队的掌控能力。没有架构设计的项目开发效率会随着版本迭代急剧下降。有架构设计的项目效率曲线平稳得多。两条线之间的差距就是架构设计的价值。我带过一个项目V3.0的时候新人入职光熟悉代码就花了三周。后来花了两个月重构V4.0的时候新人一周就能上手。这两个月的重构投入后面省下来的时间远不止两个月。六、那好的项目是怎么做的我参与过一个20万行代码、5年开发周期的智能穿戴产品。期间经历多次功能升级系统依然稳定。回头看做对的事情其实就几件每模块职责单一不越界。比如传感器模块只管采集不管显示也不管上报。想获取数据调接口。// sensor_module.h — 只暴露接口不暴露内部intsensor_init(void);intsensor_read(float*temp,float*humi);voidsensor_deinit(void);// sensor_module.c — 内部状态用static保护staticfloats_last_temp0;staticfloats_last_humi0;staticbool s_initializedfalse;模块之间不直接访问对方内部通过事件通信。typedefenum{EVT_TEMP_CHANGED,EVT_BT_CONNECTED,EVT_BT_DISCONNECTED,EVT_BATTERY_LOW,}event_type_t;typedefstruct{event_type_ttype;int32_tvalue;}event_t;voidevent_subscribe(event_type_ttype,void(*handler)(event_t*));voidevent_publish(event_t*evt);数据有唯一拥有者。温度数据归传感器模块管蓝牙状态归蓝牙模块管。其他模块想用这些数据订阅事件不要直接去读全局变量。这三件事说起来简单做起来需要坚持。尤其是项目赶进度的时候最容易妥协的就是这些原则。但每次妥协都是在给未来埋债。七、分层架构把原则落地上面说的这些原则落地最实用的框架就是分层架构。四层结构从下往上HAL层封装寄存器操作向上提供GPIO/SPI/UART/I2C等抽象接口。换芯片只改这一层。模块层是各类硬件驱动传感器驱动、通信驱动、存储驱动。每个模块独立编译、独立测试。服务层放协议栈、数据管理、OTA等跨模块功能。封装模块层能力向上提供业务级接口。应用层是业务逻辑、状态机、GUI页面。只调服务层接口不直接碰底层。有一条纪律必须遵守上层只能调下层的接口不能跨层访问更不能反向依赖。违反这条分层就白做了。我见过不少号称分层的项目应用层直接调HAL层函数操作寄存器服务层反过来调应用层的回调。这种分层比不分还糟因为给人造成了有架构的错觉实际上依赖关系比扁平结构还乱。八、架构设计到底在干什么说了这么多架构设计就一个目的控制复杂度。项目长大以后决定系统寿命的不是编码能力而是你能不能把复杂度控制在团队能驾驭的范围内。模块边界控制模块内部的复杂度让每个模块能被单独理解。统一接口控制模块之间的复杂度让依赖关系可追踪。数据管理控制数据流动的复杂度让数据变更可追溯。三者配合才能把系统复杂度控制在团队能驾驭的范围内。好的架构是什么样的新功能容易扩展Bug容易定位新人能在一周内上手模块可以跨项目复用。差的架构是什么样的改一处崩三处Bug越修越多新人三周还看不懂代码换个项目全部推倒重来。写在最后做了这么多年嵌入式我越来越觉得限制工程师成长的已经不是语法也不是驱动开发能力而是系统设计能力。从写功能到设计系统这是嵌入式工程师最重要的一次跨越。很多人写了十年代码还是停留在实现需求的层面从来没想过怎么让代码在三年后还能被维护。项目越来越难维护通常不是因为代码写得差而是模块边界不清晰、全局变量泛滥、模块耦合严重、缺少统一接口、系统复杂度失控。软件架构的本质就是控制复杂度。听起来朴素做到需要坚持。

相关新闻

保姆级教程:手把手教你用SurroundOcc跑通NuScenes数据集(从数据加载到可视化全流程)

保姆级教程:手把手教你用SurroundOcc跑通NuScenes数据集(从数据加载到可视化全流程)

从零开始掌握SurroundOcc:NuScenes数据集全流程实战指南1. 环境准备与项目初始化在Ubuntu 20.04 LTS系统上,我们需要先配置好基础开发环境。建议使用Anaconda创建独立的Python环境以避免依赖冲突:conda create -n surroundocc python3.8 -y c…

2026/7/1 0:36:49阅读更多 →
免费开源图片元数据批量编辑终极指南:ExifToolGUI完全教程

免费开源图片元数据批量编辑终极指南:ExifToolGUI完全教程

免费开源图片元数据批量编辑终极指南:ExifToolGUI完全教程 【免费下载链接】ExifToolGui A GUI for ExifTool 项目地址: https://gitcode.com/gh_mirrors/ex/ExifToolGui 你是否曾面对数百张照片的拍摄时间混乱而束手无策?是否需要在大量图片中批…

2026/7/1 0:36:49阅读更多 →
MoeKoeMusic:如何用这款二次元音乐播放器打造个性化听歌体验

MoeKoeMusic:如何用这款二次元音乐播放器打造个性化听歌体验

MoeKoeMusic:如何用这款二次元音乐播放器打造个性化听歌体验 【免费下载链接】MoeKoeMusic 一款开源简洁高颜值的酷狗第三方客户端 An open-source, concise, and aesthetically pleasing third-party client for KuGou that supports Windows / macOS / Linux / We…

2026/7/1 0:36:49阅读更多 →
Spring 事务实现方式有哪些?

Spring 事务实现方式有哪些?

编程式事务:通过编程的方式管理事务,这种方式带来了很大的灵活性,但很难维护。声明式事务:将事务管理代码从业务方法中分离出来,通过aop进行封装。Spring声明式事务使得我们无需要去处理获得连接、关闭连接、事务提交和…

2026/7/1 1:46:56阅读更多 →
大模型核心技术与企业级应用实战指南-附录

大模型核心技术与企业级应用实战指南-附录

附录 这部分是整本书的"工具箱"——遇到不熟悉的概念回来查,看到感兴趣的工具体验一下,想深入研究的照着参考文献去找原文读。 附录A:常用术语表 按字母顺序排列,方便快速查阅。 A Adam — 一种自适应学习率的优化算法…

2026/7/1 1:46:56阅读更多 →
go ethereum之p2p

go ethereum之p2p

简介 p2p是以太坊节点网络层的骨架,夹在底层 TCP/UDP 和应用协议(eth、snap、les)之间,管三件事:节点发现(谁在线)、连接管理(怎么连上、怎么断)、消息多路复用&#xff…

2026/7/1 1:46:56阅读更多 →
中餐厅摆台 点击UI图片拖拽预制体到桌面并 实现预制体拖拽

中餐厅摆台 点击UI图片拖拽预制体到桌面并 实现预制体拖拽

1、准备桌面 和 酒杯先在Scene窗口中调好相对位置,然后将酒杯拖拽到project目录中生成预制体。需要给预制体增加一个脚本就是 using UnityEngine; public class ItemHeight : MonoBehaviour {// 在预制体Inspector手动填好:这个物品放在桌面需要的世界Yp…

2026/7/1 1:46:56阅读更多 →
— 一款针对 IT 团队开发的文档管理系统,基于 Golang 开发,内置项目管理,用户管理,权限管理等功能,可以用来储存日常接口文档,数据库字典,手册说明等文档。功能特色:

— 一款针对 IT 团队开发的文档管理系统,基于 Golang 开发,内置项目管理,用户管理,权限管理等功能,可以用来储存日常接口文档,数据库字典,手册说明等文档。功能特色:

色:项目空间划分:支持创建多个项目空间,每个空间可独立管理文档,适合多团队或多产品线并行管理性化项目设置:支持配置项目名称、描述、评论权限、自动发布、下载权限等,适配不同项目需求多编辑器支持&#…

2026/7/1 1:46:56阅读更多 →
TensorRT 推理加速:从 ONNX 到优化引擎的编译与部署全链路

TensorRT 推理加速:从 ONNX 到优化引擎的编译与部署全链路

TensorRT 推理加速:从 ONNX 到优化引擎的编译与部署全链路 一、GPU 推理的延迟鸿沟:为什么 PyTorch 模型跑不到理论算力 在模型部署阶段,一个常见的困惑是:GPU 的理论算力(如 A100 的 312 TFLOPS FP16)与实…

2026/7/1 1:41:55阅读更多 →
AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

6个月前的2025年12月,Boris Cherny 公开宣布自己卸载了 IDE。一时间,Vibe Coding 成了全行业最热的话题。6个月后,当我们回过头来拉一份真实账本,发现事情远没有"一句话生成一个App"那么浪漫。本文从产品经理和研发两个…

2026/6/30 4:03:30阅读更多 →
审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

引言:审计结束三个月了,审计员的权限还没关某城商行每年按照监管要求开展至少一次数据安全审计。审计期间,内审部门需要抽样检查各类业务数据——交易流水、客户信息、员工操作日志、权限配置记录。这些数据分布在不同系统中,审计…

2026/6/30 4:36:27阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/1 0:01:44阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/1 0:01:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/1 0:01:44阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/1 0:01:44阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/1 0:01:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/1 0:01:44阅读更多 →