arrow_back返回文章列表

软件项目为什么越加人越慢:重读《人月神话》

项目延期时,加人是很自然的反应。剩下二十个任务,原来四个人做,现在八个人做,似乎就能把时间缩短一半。困难在于,任务清单上的二十行,未必是二十份可以独立完成的工作。

《人月神话》讨论的正是这种差别。Brooks 根据参与 IBM System/360 和 OS/360 的经历,分析了大型软件项目中的分工与管理问题。书里对概念完整性的重视,也与这种分工直接相关:更多人参与之后,怎样让他们仍在建设同一个系统?出版方介绍

重读这本书,我更关心一个具体问题:在宣布增援之前,我们究竟有没有弄清项目为什么慢?

任务数量不等于可并行程度

下面是一个构造的工程场景,不对应真实项目。

一个移动端团队正在增加离线消息能力。页面、数据库和同步模块分别有人负责,距离发布还有两周。此时发现,“已发送”到底指服务器接收,还是对端已经收到,三个模块的理解并不相同。产品还要求退出账号后清除消息,但同步任务可能仍在后台写入。

负责人又调来两名开发者。一人接手消息状态,一人负责账号退出。表面上工作分散了,实际两人都需要先了解同一套生命周期:哪些状态可以回退,消息标识在哪里生成,数据库删除之后是否允许补写,网络重试由谁取消。

原来的开发者因此暂停实现,解释历史和讨论接口。新同事修改后,页面和同步模块又要跟着调整。新增人数增加了局部产出,却没有解决状态定义这个共同前提。

Brooks 定律提醒我们:向已经延期的软件项目增加人手,可能使它更晚完成。书中的警告针对把人和时间当作可自由交换资源的排期方式;它不能代替对具体任务的分析。独立的数据核验可以分给多人,尚未确定的消息协议却很难靠人数直接缩短讨论时间。

这里可以借用一个简单模型理解排期。假设某项工作有四天必须顺序完成的设计与联调,还有八个人日可以独立实现。即使八个人同时进入,后半段理想情况下缩到一天,前面四天仍然存在;若再计入培训和整合,工期还会更长。这个模型只是说明依赖关系,不是实际项目的估算公式。

增援会先消耗老成员的时间

“新同事能力很强”并不能省掉学习项目的过程。一个人懂数据库,不代表他知道当前表里哪一列背负着兼容承诺;熟悉网络库,也不代表他了解服务器对重复消息的处理方式。

增援初期,老成员的有效工作时间可能下降。这部分成本容易漏掉,因为排期只记录了新同事能够贡献多少,却没有记录谁来回答问题、谁来检查理解、谁来处理第一次集成。

因此,决定加人时,至少应该说清两件事:新成员先完成哪项有明确输入输出的工作,谁为这项工作提供上下文。如果答案只是“哪里忙就帮哪里”,他很可能在多个模块之间等待确认。

对于前面的示例,比较合适的增援任务可能是建立数据库迁移用例,或者验证已有同步接口在断网后的行为。它们仍需交接,但边界更清楚,也能释放熟悉状态机的人去解决共同决策。

沟通成本取决于需要共同决定什么

人多之后,所有人两两沟通的潜在关系数量会增长,但软件团队通常并不需要全员互相确认每个细节。真正值得检查的是:一次普通修改,要经过多少人同意才能继续?

如果修改缓存淘汰策略需要页面、网络和存储负责人一起判断,可能是缓存语义已经散落在多个地方。此时减少会议并不会减少依赖,问题只是延后到联调阶段出现。

反过来,一个可靠的边界能让多数沟通提前发生。存储模块承诺退出账号后拒绝旧会话写入,调用方就不必了解数据库如何加锁;同步模块承诺状态不会从成功退回发送中,页面便不需要自行修补乱序回调。

本文据此提出一个排期判断:先找必须共同决定的事情,再看哪些工作可以分开。接口名称确定还不够,失败行为和责任归属同样需要确定。否则大家只是拿着相同的方法签名,实现不同的系统。

概念完整性会影响交付时间

统一缩进和目录结构当然有用,但“消息”“会话”“已读”在各模块中的含义更直接地决定集成是否顺利。一个模块把删除视为立即消失,另一个把删除视为等待服务器确认,最终用户就会看到刚删掉的内容重新出现。

概念一致并不意味着只允许一个人思考。实现者应当提出反例,测试人员应当指出边界,产品需要解释用户预期;讨论之后,团队要有一份共同采用的决定。若每个人都保留自己的解释,问题不会因为意见受到尊重而消失。

也不必因此建立庞大的文档体系。示例项目可能只需要一张消息状态表、一份账号退出规则,以及几个能运行的失败场景。重要的是有人维护它们,并让代码变更同步更新这些约定。

加人之前,重新检查剩余工作

延期项目最需要的往往是一轮诚实的盘点。有些任务“完成百分之九十”,剩下的却是尚未验证的跨模块行为;有些接口已经写完,但从未与真实调用方一起运行。继续按任务个数估算,会把不确定性当成少量收尾工作。

可以把剩余事项分成三类:可以独立实现的、等待明确决策的、需要联合验证的。增援优先进入第一类;第二类需要缩短决策等待;第三类需要尽早组成完整链路,而不是继续堆积局部完成的功能。

如果发布范围允许调整,还应考虑暂缓哪个功能最能减少共同依赖。示例中的离线消息,可能先限定一种消息类型,而不是让每种附件都同时支持离线。缩范围要由产品接受,并明确剩余承诺,不能偷偷删掉失败处理来换取准时。

对下一次增援,我会先问四个问题:

  1. 当前拖住发布日期的是实现量,还是一个未解决的共同前提?
  2. 新成员能否在有限交接后独立完成一项工作?
  3. 谁承担培训、评审和集成,它们是否进入排期?
  4. 新的局部产出怎样进入一条可验证的完整流程?

这四问不保证项目准时,但能让“加人”成为一个有依据的选择。有人确实缺少执行资源,也有人缺少的是共同决定。两种项目需要的帮助很不一样。

flare

保持好奇,继续思考。