1. 甘特图被吐槽"没用",问题往往不在图本身
我见过太多团队在项目管理里用甘特图,最后得出一个结论:这东西中看不中用。会议上一张五颜六色的横道图铺满投影,领导看着点头,散会后没人再打开过。三个月后项目延期,回头翻那张图,任务条还是当初画的那些——进度没更新过,依赖关系一条没连,关键路径压根没算。于是有人总结:甘特图是给汇报用的,不是给干活用的。
这个结论是错的,但错得很有道理。甘特图作为一种项目管理可视化工具,本质上是把"时间"和"任务"这两个维度压缩到一张平面图上,让抽象的排期变成可以一眼扫过去的图形。它真正的价值不在于好看,而在于把三件很容易被含糊掉的事情强行摊开:谁在什么时候做什么、任务之间谁等谁、哪条链子一旦拖延会直接顶到交付日。这三件事只要有一件没画清楚,甘特图就退化成装饰画。
这篇内容我打算用一个完整的虚构案例贯穿到底——某公司内部数据看板重构项目,从零开始做WBS拆解、工期估算、依赖梳理、关键路径计算、手工搭一版可自动更新的甘特图,最后用脚本把排期表批量导出成图片。中间会穿插几个我自己踩过的坑,包括依赖漏画导致的"假并行"、进度百分比的自欺、基线被随手重置这些。适合两类人看:一类是刚接手项目管理、拿着任务清单不知道从哪儿开始排的新人;另一类是用了几年甘特图但总觉得"画了也没用"的老手,可能会在中间某一段找到共鸣。
先把话说在前面:甘特图不是万能的,它解决的是"时间轴上的排布与依赖"这一类问题。如果你的项目更像是源源不断的工单流,任务边界模糊、优先级天天变,那看板或者简单的优先级队列反而更合适。这一点我在最后会单独聊。
2. 画图之前,先把任务、工期、依赖三张底表立起来
2.1 任务拆到什么颗粒度,决定这张图能不能活
绝大多数甘特图死掉的第一个原因,是任务拆得太粗。一行写"系统开发",工期30天,这条横道从月初横到月末,中间没有任何信息量。进度更新的时候,负责人只能拍脑袋报一个"大概完成60%",而这个60%既不可验证也不可干预。反过来,拆得太细也不行,一个任务0.5天,一个项目拆出两百行,维护成本高于收益,更新两次就没人愿意动了。
我的经验区间是:单个任务的工期控制在1到3个工作日,最长不超过5个工作日。这个区间不是拍出来的,背后有两条约束。一是人对自己一周内的工作有相对准确的预判,超过一周就必然出现"还有时间"的松弛;二是5天正好是一个完整的工作周,跨周的任务在周一例会上汇报时天然模糊。管理学里有个说法叫"8到80小时原则",讲的是工作包最好落在8到80小时之间,跟我这个区间是同一个逻辑。
拆解方法上,我习惯用"交付物倒推"而不是"动作罗列"。比如"数据接口改造"这个粗任务,动作罗列会拆成"看代码、改代码、写测试、提测",这四步的完成标准都很虚;交付物倒推则是"接口文档定稿、改造后的接口联调通过、回归测试报告出。"每一项都有明确的完成标志,能不能算完成一目了然。
提示:判断一个任务是否拆到位,用"完成定义测试"——问负责人"这个任务完成的标志是什么",如果对方需要想三秒以上,说明还没拆清楚。
WBS的层级建议不超过三层。第一层是阶段(如设计、开发、测试、上线),第二层是工作包,第三层是具体任务。再往下拆,甘特图的纵向就会失控,一屏放不下,滚动查看的时候上下文全丢了。
2.2 工期估算的三种口径,以及为什么我总在原始估算上打八折
工期估算是甘特图里最容易产生系统性偏差的环节,而且偏差方向永远一致——偏乐观。原因不复杂:估算的人通常是被分配任务的人,人在承诺时间时天然倾向于给出"一切顺利情况下"的数字,而现实里"一切顺利"几乎不成立。
常用的三种估算口径,各有适用场景:
| 估算方法 | 具体做法 | 适用场景 | 主要缺陷 |
|---|---|---|---|
| 专家判断 | 由做过类似任务的人直接给天数 | 团队有同类经验积累 | 依赖个人,易受情绪影响 |
| 类比估算 | 参照历史同类任务的真实耗时 | 有历史数据可查 | 项目差异大时失准 |
| 三点估算 | 取乐观、最可能、悲观三个值加权 | 不确定性高的新任务 | 三个值本身也是拍的 |
三点估算的公式是(乐观值 + 4×最可能值 + 悲观值) / 6,这个加权方式给"最可能值"赋了最高权重,同时把两端的极端情况纳入考虑。举个具体例子:某个数据清洗脚本的开发,乐观3天、最可能5天、悲观11天,代入公式得到 (3+20+11)/6 ≈ 5.7天,取整6天。同时可以算标准差 (11-3)/6 ≈ 1.3天,意思是这个任务大概率落在4.7到7天之间。标准差大于均值的三分之一,就说明这个任务的估算可信度很低,需要再拆细或者先做技术验证。
不管用哪种方法,我都会在最终数字上做一个统一的修正。这个修正系数是多少?我自己的经验是乘以1.2到1.3。理由不是什么玄学,而是三块固定损耗:上下文切换(一个人同时挂两个项目,实际专注时间打七折)、沟通协调(评审、对齐、等回复)、返工(第一次做出来的东西被推翻重来的概率)。这三块在估算时几乎从来不被计入,但它们真实存在。
有个反面教训值得说。早年我做一个内部工具,估算时把所有任务按"纯编码时间"拍了一遍,总计40人天,结果实际用了62人天,超支55%。事后复盘,超支的部分里真正的技术难题只占不到10天,剩下全是等接口、等评审、等环境、改了需求重做。从那以后我做估算一定会单列一行"协调与返工缓冲",占总量15%左右,而不是把它藏在每个任务里——藏进去的话,任务工期的可信度就没了。
2.3 四种依赖关系,用错一种整张图就失真
依赖关系是甘特图区别于普通任务清单的核心。没有依赖的甘特图,本质上就是一个横过来的待办列表。常见的依赖有四种:
- 完成到开始(FS):A做完,B才能开始。这是最常用的一种,占实际项目的八成以上。
- 开始到开始(SS):A开始后,B才能开始,通常带一个延迟量。比如"开发启动3天后,测试用例编写启动"。
- 完成到完成(FF):A完成,B才能完成。典型场景是"所有模块开发完成,集成构建才能完成"。
- 开始到完成(SF):A开始,B才能完成。这个在实践中极少用,一般出现在交接场景。
用错的地方主要在两个:一是把本该FS的关系写成SS,制造出虚假的并行;二是漏画跨模块的隐性依赖。
先说第一个。SS依赖看起来很美,因为它能压缩总工期。但SS有个隐藏前提:两个任务之间的延迟量必须是可靠的。比如"接口设计开始5天后,前端页面开发开始",前提是接口设计在第5天能产出足够前端开工的信息。现实里接口设计经常在第5天只完成了一半,前端要么空转,要么按错误的假设先写一版再推翻。这种SS依赖一旦多了,整个排期的可信度就会崩掉。我的原则是:SS依赖只在有明确中间交付物的情况下使用,并且要在任务备注里写清楚"第N天需产出什么"。
再说第二个。隐性依赖是排期翻车的重灾区。比如前端开发和后端开发在图上看起来完全并行,但实际上前端要联调就必须等后端接口可用,这就是一条没画出来的FS依赖。这类依赖没画在图上,不代表它不存在,它会在执行阶段以"等待"的形式冒出来,把并行变成串行。识别方法是在每条任务上问一句"这个任务开工需要什么输入",把输入逐条对应到其他任务的产出上,对不上的就是隐性依赖。
3. 案例拆解:一个21个工作日的重构项目怎么排出来
3.1 项目背景与范围边界
案例设定是这样的:某公司内部的数据看板系统,运行了三年,前端框架老旧、数据接口是一堆硬编码的SQL,业务方提出要重构。项目组一共四个人:一名后端、一名前端、一名数据开发、一名兼职的项目负责人。交付要求是"新看板上线,老看板下线,业务不中断"。
范围边界必须先划清楚,否则任务拆解会无限膨胀。这个项目里我明确排除掉三件事:不做权限体系改造、不做历史数据迁移清洗、不做移动端适配。这三件事都有人提过,但都放到下一期。排除项要写进排期文档,而不是口头说说,因为项目进行到一半的时候,"顺手把权限也改了吧"这种声音一定会出现,白纸黑字写着的排除项是最好的挡箭牌。
剩下的范围就是:需求确认、接口梳理与改造、前端框架搭建、可视化组件开发、联调测试、上线切换。这六个工作包,往下拆成具体任务。
3.2 从WBS到初版排期表
拆解结果如下,全部按工作日计,假设项目从某个周一开始:
| ID | 任务 | 负责人 | 工期 | 前置任务 |
|---|---|---|---|---|
| A | 需求梳理与确认 | 项目负责人 | 3 | — |
| B | 数据接口梳理与文档化 | 数据开发 | 2 | A |
| C | 前端框架搭建 | 前端 | 4 | A |
| D | 数据接口改造 | 后端 | 5 | B |
| E | 可视化组件开发 | 前端 | 6 | C、D |
| F | 联调与回归测试 | 全员 | 3 | E |
| G | 上线演练与切换 | 后端 | 2 | F |
这张表有几处值得说明。第一,E依赖C和D两个前置任务,这是典型的汇聚点,也是整个排期的瓶颈。第二,B的工期只有2天,但它卡在A和D之间,一旦拖延会连累后面整条链。第三,G只给了2天,看起来紧,但上线演练这件事在A阶段就已经开始准备(写切换方案、准备回滚脚本),到G的时候更多是执行,所以2天是够的。
有人可能会问:为什么C(前端框架搭建)不依赖B(接口梳理)?因为前端框架搭建主要是工程脚手架、路由、状态管理这些,跟具体接口无关,只要知道有哪几类数据就行。这就属于前面说的"逐条问输入"得到的结论——把C的开工输入列出来,发现没有一项来自B,所以两条线可以并行。
3.3 关键路径怎么算,浮动时间有什么用
初版计划画出来,总工期看起来是 3+2+5+6+3+2 = 21 天?不对,得老老实实算。手工算法是正推求最早开始(ES)和最早完成(EF),再逆推求最晚开始(LS)和最晚完成(LF)。
正推:
| 任务 | 前置 | ES | 工期 | EF |
|---|---|---|---|---|
| A | — | 0 | 3 | 3 |
| B | A | 3 | 2 | 5 |
| C | A | 3 | 4 | 7 |
| D | B | 5 | 5 | 10 |
| E | C、D | max(7,10)=10 | 6 | 16 |
| F | E | 16 | 3 | 19 |
| G | F | 19 | 2 | 21 |
总工期21个工作日。逆推时把G的LF设为21:
| 任务 | 后继 | LF | LS = LF - 工期 | 总浮动 = LS - ES |
|---|---|---|---|---|
| G | — | 21 | 19 | 0 |
| F | G | 19 | 16 | 0 |
| E | F | 16 | 10 | 0 |
| D | E | 10 | 5 | 0 |
| C | E | 10 | 6 | 3 |
| B | D | 5 | 3 | 0 |
| A | B、C | min(3,6)=3 | 0 | 0 |
总浮动为0的任务连起来就是关键路径:A → B → D → E → F → G。C的总浮动是3天,意思是前端框架搭建这件事就算晚开始3天,也不会影响21天的总工期。这个信息非常有用——如果前端那边临时被抽去做别的事,我作为负责人可以心里有数:3天以内的延迟可以接受,超过就得干预。
这里有个实操上的细节:关键路径会随着进度推移而改变。C有3天浮动,如果它真的用掉了这3天,那么后面的E的ES就从10变成max(10,10)=10,路径没变;但如果C拖了4天,EF变成11,E的ES就变成11,整条路径转移,C也就变成关键任务了。所以我每周更新进度之后,都会重新算一次关键路径,而不是沿用最初的结论。
提示:很多人以为关键路径是项目开始时算一次就完事的东西。它不是,它是一条会移动的线,更新频率应该跟进度更新频率一致。
3.4 资源冲突:图上没问题,人身上有问题
按上面的排期,图看起来很漂亮,21天完工。但如果把人放进去看,立刻发现一个问题:前端同时被C和E占用。C是第4到第7天,E是第11到第16天,时间上不冲突,看起来没事。但再看E的开发期间,前端只有一个人,6天要做完整个可视化组件,这6天里如果C阶段留下任何技术债,都会在E阶段爆掉。
更明显的问题在后端身上:D是第6到第10天,G的准备工作其实从项目一开始就要做,但后端只有一个人,D做完紧接着就要参与F的联调(第17到第19天),然后立刻进G(第20到第21天)。这条线上没有任何缓冲,后端一旦生病或者被别的事情打断,整个项目就瘫了。
资源冲突的处理有三种常见做法,我在这个案例里选择的是第二种:
- 加人:把前端的组件开发分一部分给外部支援。成本高,且新人上手需要时间,6天任务分给两个人可能变成8天。
- 调顺序:把E拆成两批,第一批核心图表(折线、柱状)在第11到第14天做,第二批次要图表(漏斗、热力)挪到F联调之后用增量方式补。这样能错开资源压力,也降低了首次上线的复杂度。
- 拉长工期:直接承认资源不够,把总工期从21天调到25天。最诚实,但业务方通常不接受。
我选了方案2,同时在排期里显式加了一行"增量补充:次要图表开发,3天,负责人在F完成后"。这一行在甘特图上是一个浮动的虚线块,不参与关键路径计算,但能保证它不被忘掉。
4. 用表格工具手工搭一版会自己更新的甘特图
4.1 底表字段设计:把计算和展示彻底分开
很多人做甘特图是把日期直接手填在格子里的,任务一动就得全表重画。正确做法是底表只存原始数据,所有日期都靠公式推出来。我在表格工具里用的字段结构是这样的:
| 列 | 字段 | 类型 | 说明 |
|---|---|---|---|
| A | 任务ID | 文本 | A、B、C…… |
| B | 任务名称 | 文本 | 与WBS一致 |
| C | 负责人 | 文本 | 便于按人筛选 |
| D | 工期(工作日) | 数值 | 只填这一个数 |
| E | 前置任务 | 文本 | 多个用逗号分隔 |
| F | 开始日期 | 公式 | 由前置任务推算 |
| G | 结束日期 | 公式 | 由开始日期和工期推算 |
| H | 进度 | 百分比 | 手工更新 |
| I | 是否为里程碑 | 布尔 | 是则工期为0 |
关键在公司F和G。前置任务的结束日期需要先查找出来,多个前置任务取最大值。在表格工具里可以用这样的思路:
F3 = WORKDAY.INTL(MAX(IFERROR(VLOOKUP(前置ID列表, 底表区域, 7, FALSE), 项目起始日-1)), 1, 1, 节假日表) G3 = WORKDAY.INTL(F3, D3-1, 1, 节假日表)WORKDAY.INTL的第三个参数是周末规则,填 1 表示周六日双休,如果团队是大小周就改成对应的编码。第四个参数是节假日表,把春节、国庆这些日期单独列一张表引用进来,这一步千万别省——跨春节的项目如果按自然工作日算,排期能差出七八天。
G3里用D3-1是因为WORKDAY.INTL(F3, n)表示从F3往后推n个工作日,工期包含开始当天,所以要减1。这个减1是新手最容易漏的,漏了之后所有任务的结束日期都会晚一天,误差累积下来很吓人。
4.2 用条件格式把条形画出来
底表有了,接下来是画出横道。做法是在底表右侧铺一整行日期,作为日历网格的列头:
J2 = 项目起始日 K2 = J2 + 1 L2 = K2 + 1 …… 一直铺到项目结束日之后然后整片网格区域(比如 J3 到 ZZ20)加一条条件格式公式:
=AND(J$2>=$F3, J$2<=$G3)含义是"这一格的日期落在任务的开始和结束之间就填色"。再叠加一条区分进度的规则:
=AND(J$2>=$F3, J$2<=$G3, J$2<=$F3+ROUND(($G3-$F3+1)*$H3,0)-1)这条规则把已完成部分涂成深色,未完成部分保持浅色。两条规则的优先级顺序要对,深色在上。
这套方案的优点是:改任何一个任务的工期或前置关系,整张图自动重排,不用手动拖任何一个色块。缺点是网格列数受限于项目跨度,超过两百天会卡。真遇到跨度大的项目,我的做法是按月折叠,每列代表一周而不是一天,精度损失可以接受。
对于"今天"这条参考线,可以在网格上加一条条件格式:日期等于今天的列整列加边框。这样每次打开文件,一眼就能看到进度落后到什么程度。
4.3 基线对比:没有基线的甘特图等于没有刻度尺
甘特图上如果只有一根横道,你只能看到"计划是这样",看不到"我们现在比原计划慢了多少"。所以基线是必须的:在项目启动时把当时的开始日期、结束日期冻结一份,存到另外两列,然后在图上用不同颜色画第二根细条。
具体做法是在底表加P、Q两列存基线开始和基线结束,用值粘贴的方式固定下来(不能用公式,否则会跟着变)。网格上再加一条条件格式:
=AND(J$2>=$P3, J$2<=$Q3, J$2<$F3)这条规则覆盖的区域涂成灰色,表示"原本该在这段时间做完,但现在推迟了"。这种做法会让延期变得非常显眼,谁都不想自己的任务后面拖着一条灰尾巴,这种心理压力本身就是一种管理工具。
基线什么时候可以更新?我的规矩是:只有在范围发生正式变更、并且变更记录留档之后,才允许重置基线。日常的进度拖延一律不动基线。这条规矩定下来,团队才会认真对待最初那份排期,而不是把它当成一个随时可以改的草稿。我见过最糟糕的情况是某个团队每周重置一次基线,三个月后所有人都说"项目按计划进行",因为计划跟着实际一起走了,永远不会有偏差。
5. 用脚本把排期批量出图:适合经常性汇报的场景
5.1 什么时候值得写代码,什么时候不值得
用表格工具做甘特图,日常更新完全够用。但有两种场景我会切到脚本:一是需要定期把多张不同维度的图(按人、按模块、按周)批量导出成图片发给不同的人;二是排期数据本身已经存在数据库或项目管理工具里,手工导表格再做图属于重复劳动。
脚本方案我一般用 Python 的 matplotlib,因为它的横向条形图能力足够,且不需要联网。核心思路是把每个任务画成一根横条,横轴的起点是开始日期,长度是工期,纵轴是任务名。用broken_barh可以一次画很多根,也可以用循环一根一根画,后者更容易给每根条单独上色和加标注。
5.2 数据准备与字段约定
脚本读取的输入是一份 CSV,字段和前面的底表保持一致,日期统一用YYYY-MM-DD格式。约定好了,后面的代码就不用改:
task,start,end,owner,progress,critical 需求梳理,2025-03-03,2025-03-05,项目负责人,1.0,true 接口梳理,2025-03-06,2025-03-07,数据开发,1.0,true 框架搭建,2025-03-06,2025-03-11,前端,0.6,false 接口改造,2025-03-10,2025-03-14,后端,0.3,true 组件开发,2025-03-17,2025-03-24,前端,0.0,true 联调测试,2025-03-25,2025-03-27,全员,0.0,true 上线切换,2025-03-28,2025-03-31,后端,0.0,truecritical这一列很关键,它让关键路径上的任务在图上用不同颜色标出来。这个信息必须从外部分析结果带进来,脚本本身不做关键路径计算——把排期逻辑和绘图逻辑分开,改排期的时候不用碰代码。
5.3 完整绘图代码
import csv from datetime import datetime import matplotlib.pyplot as plt import matplotlib.dates as mdates def load(path): rows = [] with open(path, encoding="utf-8") as f: for r in csv.DictReader(f): r["start"] = datetime.strptime(r["start"], "%Y-%m-%d") r["end"] = datetime.strptime(r["end"], "%Y-%m-%d") r["progress"] = float(r["progress"]) r["critical"] = r["critical"].strip().lower() == "true" rows.append(r) return rows def draw(rows, out="gantt.png"): fig, ax = plt.subplots(figsize=(12, 0.6 * len(rows) + 2)) # 纵轴倒序,让第一个任务画在最上面 names = [r["task"] for r in rows][::-1] for i, r in enumerate(rows[::-1]): total = (r["end"] - r["start"]).days + 1 base = "#B23A3A" if r["critical"] else "#4C78A8" light = "#E8C7C7" if r["critical"] else "#C9D8E8" # 未完成部分:浅色 ax.barh(i, total, left=r["start"], height=0.55, color=light, edgecolor="white") # 已完成部分:深色覆盖 if r["progress"] > 0: ax.barh(i, total * r["progress"], left=r["start"], height=0.55, color=base, edgecolor="white") ax.set_yticks(range(len(names))) ax.set_yticklabels(names, fontsize=10) ax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=mdates.MO)) ax.xaxis.set_major_formatter(mdates.DateFormatter("%m-%d")) ax.grid(axis="x", linestyle=":", alpha=0.5) ax.axvline(datetime.today(), color="#555555", linestyle="--", linewidth=1) ax.set_title("项目排期(红色为关键路径任务)", fontsize=12) fig.tight_layout() fig.savefig(out, dpi=150) plt.close(fig) if __name__ == "__main__": draw(load("schedule.csv"))这段代码有几个地方值得解释。barh的left参数控制起点,total控制长度,两次调用叠加就形成了"浅色底 + 深色进度"的效果,比单色条信息量大。纵轴倒序是因为 matplotlib 的 y 轴默认从下往上增长,不倒序的话第一个任务会画在最底下,读起来别扭。WeekdayLocator让刻度对齐到每周一,比自动刻度好读。
如果要输出按人拆分的图,把load之后的数据按owner分组,各组单独调一次draw就行。这套东西我用了几年,稳定的地方在于数据格式不变,代码就不用动;别扭的地方在于字体——中文标签在某些环境需要手动指定字体,报一堆 missing glyph 的警告,加上plt.rcParams["font.sans-serif"] = ["SimHei"]之类就能压下去。
6. 六个翻车现场,以及它们背后的同一个毛病
6.1 假并行:图上两条线并排,实际在互相等
这是我在实际项目里见过最多的坑。图上前端和后端两条横道从同一周开始,看起来齐头并进,实际上后端接口没出来之前前端根本没法真正联调。等到了联调阶段,两边代码风格不一致、字段定义不一致,返工的时间比原本串行还长。
根因是依赖识别只做了显式部分。显式依赖容易想,比如"测试依赖开发完成";隐性依赖难想,比如"前端联调依赖后端接口部署到测试环境",而这个部署动作在WBS里根本没有对应的任务行。解决办法是在WBS里把这类"环境准备""部署""配置"动作单独列成任务,哪怕它只有0.5天。看不见的任务不会出现在甘特图上,也就不会被排进计划。
6.2 进度百分比的自欺:80%卡了三周
有个任务连续三次周报都写着"完成80%"。第一次看到我觉得挺快,第二次觉得正常,第三次我就去问了。结果是这个任务的核心难点一直没解决,所谓的80%是把容易的部分都做完了,剩下20%是最硬的部分。
百分比进度这个指标的问题在于它是一个自我报告的数字,缺乏统一定义。同样叫"完成50%",有人指工作量完成一半,有人指功能点完成一半,有人指代码写完一半(还不含测试)。我的对策是弱化百分比,强化里程碑:把任务拆到1到3天,每个任务的完成就是二元的(做了或没做),进度自然就准确了。非要保留百分比的话,就规定"只有当任务通过了自测才能报100%",把定义钉死。
6.3 粒度失控:两百行的甘特图等于没有甘特图
前面说过拆太粗不行,这里补一句拆太细同样不行。我见过一个项目把甘特图拆到了"上午写代码、下午写代码"的程度,两百多行。结果每周更新要花两个小时,更新三次之后负责人放弃了,图停留在第一周的版本。
判断标准是维护成本要远低于它带来的价值。如果更新一次图的时间超过半小时,说明粒度有问题。合理的行数我一般控制在一屏半到两屏之间,大概30到50行。超过这个数量,就把相近的任务合并成一个工作包,只在需要跟踪的时候展开。
6.4 基线随手重置:永远准时的项目
这一条在前面的基线部分提过,值得单独强调。基线被频繁重置的团队,通常还有一个伴生现象:他们从不复盘延期原因,因为"计划本来就是这样"。基线的意义是提供一把固定的尺子,尺子会变,测量就失去意义。如果确实因为范围变更需要调整基线,那就正规走一次变更:记录变更原因、影响的任务数、总工期变化,然后才允许重置。这个过程本身就能过滤掉大量随意的变更请求。
6.5 只画不管:甘特图不进周会
最后一条最朴素:图做出来了,但周会上没人看。周会讨论的还是"这周做了什么、下周做什么",跟甘特图上那条关键路径毫无关系。
要让图活起来,周会的议程里必须有一项固定动作:对着图过一遍关键路径上的任务,问三个问题——有没有延期、延期是否影响关键路径、需要什么支持。这三个问题问完,图的更新才有动力,因为大家知道不更新会在会上被问住。
把上面这些坑归拢一下,会发现它们背后是同一个毛病:把甘特图当成一个交付物,而不是一个持续运行的模型。交付物做完就完了,模型需要持续输入、持续校准。区别就在这里。
7. 什么时候该把甘特图换成别的视图
甘特图有它明确的能力边界。它擅长的是"任务边界清晰、依赖明确、时间跨度可预期"的项目,比如版本发布、活动筹备、产线改造、装修施工。这类项目的共同点是有明确的起止点,任务之间的先后关系可以事先想清楚。
但有两类场景,甘特图会明显水土不服。第一类是持续运维类的工单流,任务源源不断进来,优先级每周都在变,画甘特图意味着每天重画。这类场景用看板更合适,限制在制品数量、按列流动,反而能看出瓶颈在哪里。第二类是探索性强的前期研发,任务本身做多久都说不准,可能三天出结果也可能三周推翻重来。这种项目硬排甘特图,只会得到一张频繁失真的图,不如用短周期的迭代加每期目标。
即便是适合甘特图的项目,我一般也会配一张资源负载表。因为甘特图看的是时间,看不出人是否被压满。一张简单的"人 × 周"矩阵,每格填这个人在这一周被分配的任务数,超过两个就要预警。时间和人力这两个维度分开看,问题会更容易暴露。
最后分享一个我自己养成的小习惯:每次项目收尾,把最终版的甘特图和最初版的基线并排打印出来,对着看哪几条任务延期最多、延期是从哪个节点开始滚起来的。这个动作花不了十分钟,但积累几年下来,你对"哪类任务估不准""哪类依赖最容易漏"会有非常具体的手感,下一次排期的时候,这些手感会直接体现在你打的那个折扣系数上。