4. 进度规划的核心:关键路径法(CPM)与甘特图在嵌入式固件开发中的应用
进度规划,说白了就是回答三个问题:做什么、谁来做、做多久。但在嵌入式固件开发里,事情没那么简单。你想想看,一个固件项目里,驱动层没写完,应用层就没法联调;Bootloader 没搞定,固件更新功能就是空中楼阁。这些任务之间的依赖关系,才是进度管理的真正难点。
我个人习惯,拿到项目需求后,第一件事不是排时间,而是画任务依赖图。为什么?因为只有把依赖关系理清了,你才知道哪些任务可以并行,哪些必须串行,哪些一旦延期就会拖垮整个项目。
4.1 关键路径法(CPM):找到那条不能延期的链
关键路径法,英文叫 Critical Path Method,简称 CPM。它不是什么高深理论,就是帮你找出项目中最长的任务链。这条链上的任何一个任务延期,项目整体就延期。
我在项目中遇到过好几次这样的情况:团队觉得某个模块很简单,随手估了个时间,结果它偏偏就在关键路径上。一延期,整个项目跟着遭殃。所以,识别关键路径,是进度规划的第一步。
4.1.1 四个核心参数
要算关键路径,你得先搞清楚四个参数:
| 参数 | 含义 | 说明 |
|---|---|---|
| ES (Earliest Start) | 最早开始时间 | 前置任务全部完成后,本任务最早能开始的时间 |
| EF (Earliest Finish) | 最早完成时间 | ES + 任务工期 |
| LS (Latest Start) | 最晚开始时间 | 不影响项目总工期的情况下,本任务最晚能开始的时间 |
| LF (Latest Finish) | 最晚完成时间 | LS + 任务工期 |
关键路径上的任务,ES = LS,EF = LF。说白了,就是一点缓冲都没有。
4.1.2 计算步骤:前推法与后推法
计算过程分两步:
- 前推法:从项目开始往结束推,算 ES 和 EF。遇到分叉,取最大值。
- 后推法:从项目结束往开始推,算 LS 和 LF。遇到分叉,取最小值。
举个例子,一个简单的固件开发任务分解:
| 任务 | 工期(天) | 前置任务 |
|---|---|---|
| A. 需求分析 | 3 | 无 |
| B. 架构设计 | 5 | A |
| C. 驱动开发 | 10 | B |
| D. 应用层开发 | 8 | B |
| E. 联调测试 | 4 | C, D |
前推法算出来:A(0-3) → B(3-8) → C(8-18) → E(18-22),总工期 22 天。D 的 ES 是 8,EF 是 16,比 C 早结束,所以 D 不在关键路径上。
关键路径:A → B → C → E,总工期 22 天。
D 有 2 天的浮动时间(18 - 16 = 2 天),可以适当调整。
4.2 甘特图:把计划画出来
关键路径算出来了,下一步就是把它变成可视化的进度条。甘特图就是干这个的。
我习惯用甘特图来做三件事:
- 展示任务时间线:每个任务的起止时间一目了然。
- 标注依赖关系:用箭头把前置和后置任务连起来。
- 跟踪实际进度:用不同颜色标记已完成、进行中和未开始的任务。
嗯,这里要注意:甘特图不是画完就完事了。你得每周更新一次,把实际进度和计划进度做对比。我曾经有个项目,甘特图画得漂漂亮亮,结果两个月没更新,最后发现进度已经偏离了 30%。那叫一个惨。
4.2.1 嵌入式固件开发的典型甘特图结构
下面是一个典型的嵌入式固件项目甘特图结构,我把它简化成表格形式:
| 阶段 | 任务 | 工期 | 依赖 | 资源 |
|---|---|---|---|---|
| 需求 | 需求评审 | 3天 | 无 | PM, 架构师 |
| 设计 | 系统架构设计 | 5天 | 需求评审 | 架构师 |
| 设计 | 硬件接口定义 | 3天 | 系统架构设计 | 嵌入式工程师 |
| 开发 | Bootloader 开发 | 7天 | 硬件接口定义 | 嵌入式工程师 A |
| 开发 | 驱动层开发 | 10天 | 硬件接口定义 | 嵌入式工程师 B |
| 开发 | 应用层开发 | 8天 | 驱动层开发 | 嵌入式工程师 C |
| 测试 | 单元测试 | 5天 | 驱动层开发, 应用层开发 | 测试工程师 |
| 测试 | 集成测试 | 5天 | 单元测试 | 测试工程师 |
我的习惯:在甘特图上用红色标记关键路径上的任务,用绿色标记有浮动时间的任务。这样一眼就能看出哪些任务碰不得。
4.3 依赖关系的四种类型
嵌入式固件开发中,依赖关系不只是简单的「做完 A 才能做 B」。我总结了一下,常见的有四种:
| 类型 | 说明 | 嵌入式场景举例 |
|---|---|---|
| 完成-开始 (FS) | 前置任务完成后,后续任务才能开始 | 驱动开发完成后,应用层开发才能开始 |
| 开始-开始 (SS) | 前置任务开始后,后续任务就可以开始 | 硬件设计开始后,PCB 布局就可以开始(有重叠) |
| 完成-完成 (FF) | 前置任务完成后,后续任务才能完成 | 所有模块测试完成后,集成测试才能完成 |
| 开始-完成 (SF) | 前置任务开始后,后续任务才能完成 | 比较少用,比如旧系统下线前,新系统必须上线 |
实际项目中,FS 类型占 80% 以上。但 SS 和 FF 类型用好了,能帮你压缩工期。比如驱动开发和应用层开发,如果接口定义清楚了,完全可以 SS 方式并行一部分。
避坑指南:我曾经在一个项目中,把两个任务设成了 SS 关系,结果前置任务改了接口,后置任务已经基于旧接口写了一半代码,返工了三天。所以,SS 关系一定要确保接口稳定,或者有变更通知机制。
4.4 关键路径与甘特图的联动:一个完整的嵌入式案例
我们来看一个真实的嵌入式固件项目案例。假设我们要开发一个智能传感器固件,功能包括数据采集、协议转换、OTA 升级。
任务分解如下:
- 需求确认(2天)
- 系统设计(3天,依赖 1)
- Bootloader 开发(5天,依赖 2)
- 传感器驱动开发(4天,依赖 2)
- 通信协议栈移植(6天,依赖 2)
- 数据采集逻辑开发(5天,依赖 4)
- OTA 功能开发(4天,依赖 3)
- 应用层联调(3天,依赖 5, 6, 7)
- 系统测试(4天,依赖 8)
通过 CPM 计算,关键路径是:1 → 2 → 5 → 8 → 9,总工期 2+3+6+3+4 = 18 天。
任务 3、4、6、7 都有浮动时间。比如任务 3(Bootloader)有 2 天浮动,任务 4(传感器驱动)有 3 天浮动。这意味着,如果关键路径上的任务延期了,你可以从这些有浮动的任务上临时调人支援。
下面是我为这个案例画的 CPM 网络图:
4.5 管理依赖关系的三个实战技巧
理论讲完了,说点实际的。我在多个嵌入式项目中总结出来的三个技巧:
4.5.1 技巧一:建立依赖清单
不要只靠脑子记。我每个项目都会建一个依赖清单,格式很简单:
依赖ID | 前置任务 | 后置任务 | 依赖类型 | 状态 | 风险等级
D001 | 驱动开发 | 应用开发 | FS | 已确认 | 低
D002 | 硬件设计 | 驱动开发 | SS | 待确认 | 高
每周例会过一遍这个清单,看看有没有新增的依赖,或者已有的依赖状态变了。
4.5.2 技巧二:给关键路径加缓冲
关键路径上的任务,我建议不要排得太满。比如估算出来是 10 天,我通常会加 10%-15% 的缓冲。为什么?因为嵌入式开发中,硬件问题、芯片缺货、调试环境出问题,这些都是常事。
我曾经有个项目,关键路径上的驱动开发估了 8 天,结果芯片勘误表里有个坑,多花了 3 天才绕过去。从那以后,我学乖了,关键路径上的任务,一定要留余量。
4.5.3 技巧三:用里程碑卡住关键节点
在甘特图上,我会在关键路径的每个阶段结束时设置一个里程碑。比如:
- M1:需求确认完成
- M2:系统设计评审通过
- M3:协议栈移植完成
- M4:联调通过
- M5:系统测试通过
里程碑不占工期,但它是一个检查点。如果某个里程碑延期了,说明关键路径出问题了,需要立刻调整资源或计划。
核心总结:
- CPM 帮你找到不能延期的任务链,甘特图帮你可视化整个计划。
- 依赖关系不只是 FS,SS 和 FF 用好了能压缩工期,但风险也更高。
- 关键路径上的任务,一定要加缓冲、设里程碑、每周跟踪。