今天跟大家聊聊过度设计这个话题,前段时间隔壁团队来了一位新人,然后给了他一个案子来做,项目不算难,不过在做方案评审的时候,给我的感觉就是为了一个小的项目他想把毕生所学的软件知识都得用上,所以在脑海里自然而然的想到了一个词"过度设计"。

完美主义陷阱

大家应该都有听过“工程师的完美主义陷阱”,是指在工作中过度追求完美而带来诸多问题的状态。表现为过度设计、过度优化、反复测试及不愿妥协等。

主要原因是对技术的追求、强烈的质量意识和个人完美主义性格。这一陷阱会导致项目进度延迟、成本超支、创新受限、团队协作出现问题,使工程师忽视实际需求,陷入细节而忽略整体。

之前听一个同事说有一个单片机”点灯大师”,为了控制一颗LED从应用层到驱动可以设计个七八层,看似夸张的段子,恰恰折射出当前嵌入式开发领域普遍存在的过度设计现象。

过度设计症状

RTOS依赖症

如下是一个简单的STM32呼吸灯项目,裸机定时器中断+状态机即可解决的问题,然而硬生生的上了一个RTOS,还分了好几个任务:

// 使用FreeRTOS创建3个任务
xTaskCreate(led_breath_task, "LED", 256, NULL, 3, NULL);
xTaskCreate(button_scan_task, "BTN", 128, NULL, 2, NULL);
xTaskCreate(log_upload_task, "LOG", 512, NULL, 1, NULL);

 每个任务占用至少1KB栈空间,一些资源小单片机也就20K左右的RAM,真的耗不起,并且任务切换耗时也相当耗时。

抽象强迫症

一个简单读取ADC数据采集,程序调用穿越了5层:

// 五层调用链
application → driver_service → hal_wrapper → stm32_hal → register

这样的代码在单片机上非常的膨胀,代码量至少得增加个30%,重点是还没干啥事,抽象出来也没有复用上,甚至还加重了编译和修改的负担。

设计模式崇拜症

如下是为了实现一个LED的控制,开发工程师用了一个工厂模式:

typedef struct {
    void (*init)(GPIO_TypeDef*, uint16_t);
    void (*on)(void);
    void (*off)(void);
} LED_Interface;

LED_Interface led = {
    .init = led_init,
    .on = led_on,
    .off = led_off
};

在单片上直接寄存器操作只需3条语句,而这样的接口去封装会占用较多的RAM,函数调用开销也大。

所以在资源受限的平台,过度设计真的非常有害,资源消耗的翻倍,函数嵌套较深导致维护困难,本来主频就不高,运行效率大大下降。

约束过度设计

1、资源提前预算

每个模块大概占用多少内存,进行一个明确限制,超过了就需要调整设计,比如下面这些宏定义指标就是某个项目中在当前开发阶段所限制的各种资源大小。

// 设置硬约束
#pragma SET_FLASH_LIMIT 64KB  // 最大允许使用64KB中的80%
#pragma SET_RAM_LIMIT 20KB    // 保留至少4KB余量
#pragma SET_ISR_TIME 10us     // 中断服务最长时间

这样做的好处是一方面能够直接清晰的确认当前新增功能占用的资源是否合理,另一方面也是为了产品后续更好的迭代升级预留资源。

2、自动化度量化检测表

// 在CI/CD流程中集成检查
if (McCabe复杂度 > 15) → 触发代码审查
if (函数调用深度 > 5) → 发出警告
if (条件分支数 > 10) → 要求重构

在代码的CI/CD流程中,集成检查是保障代码质量等的关键环节。主要包括:代码风格检查、语法检查、代码质量分析、依赖检查、单元测试;那么我们可以针对不同的项目设置相应的条件来拦截一些过度设计。

3、需求约束法(5W1H验证矩阵)

设计决策

Why需求

Where使用

When变更

Who维护

How验证

使用RTOS

多任务

核心逻辑

永不

资深

压力测试

硬件抽象层

跨平台

驱动层

可能

中级

接口测试

  • 设计决策:列出了“使用RTOS”和“硬件抽象层”两个决策。

  • Why需求:解释采用该决策的原因,如使用RTOS是为了多任务处理,硬件抽象层用于跨平台,帮助开发人员理解采用该决策的原因,避免盲目开发。

  • Where使用:说明决策应用的位置,前者用于核心逻辑,后者在驱动层。

  • When变更:预估决策发生变更的可能性,前者为“永不”,后者是“可能”。

  • Who维护:指出维护人员的水平,分别为“资深”和“中级”。

  • How验证:表明验证决策效果的方式,分别是压力测试和接口测试。

最后,完美主义在嵌入式领域需要适可而止。正如嵌入式大师Michael Barr在《Programming Embedded Systems》中强调的:"最好的嵌入式代码,是刚好满足需求的最简实现。"