1968 年,北约在西德加米施开了一场会,会议主题匪夷所思:软件。不是因为软件多成功要办庆功会,而是因为大规模软件项目大面积失控:超支、延期、质量失控,IBM 的 OS/360(370 人年)延期数年,IBM 总裁公开承认「我们造的房子比卖出去的多」。会议借用建筑工程的词,造了 software engineering 这个术语,试图把「建大软件」从手工艺变成工程。本章讲清三件事:危机到底危机在哪、传统工程的解法为什么不完全适用、以及软件工程真正的核心问题是什么。
OS/360 时代的问题清单,今天的项目照样复发,值得逐一认识:
复杂度。硬件的复杂度是「算术级」的(加零件,部件间关系线性),软件的复杂度是「指数级」的:模块间的交互关系随模块数平方级增长。一个 10 万行代码的系统,没有任何人能完全理解它。Brooks 在《没有银弹》里把这叫本质复杂度(essence),它源自问题域本身,不是实现失误。
不可见性。软件没有空间实体,画成图都是抽象投影(流程图、UML,第 6 章),而盖楼有图纸有进度有实体墙。人脑对「看不见的东西」的进度估算天生不行。
易变性。客户的需求会变(而且理直气壮地变),代码改起来比改楼容易得多,于是「需求变更」成了软件世界的常态而非异常。盖楼没人说「改一版,窗户全朝北吧」,软件天天被这么要求。
这三个病灶合起来解释了一个反直觉的现象:加人不能加快延期的项目(Brooks 定律:「往延期项目里加人只会更延期」):新人要培训、沟通路径 n(n-1)/2 增长。人月神话的书名即此。
土木工程的解法(详尽图纸 → 按图施工 → 验收)映射到软件就是瀑布模型(第 2 章),它在需求稳定时有效。但软件的需求天然易变,而代码的可变性恰恰是优势:与其抵制变更,不如组织过程拥抱变更。这是敏捷运动(2001 敏捷宣言)的出发点,也是本课第 2 章的主线。
另一个照搬失败的是「测试在末端」:盖楼封顶后验收,软件这么做等于把 80% 的缺陷留到最后修,修复成本按阶段指数上涨(需求期的错到上线期修,贵 100 倍,这是软件工程里少数有可靠数据支撑的结论)。所以现代实践把验证往前挪:需求期评审、开发期持续测试(第 8 章)、提交前 CI(第 10 章)。
排除掉「像盖楼一样盖软件」的幻想,这门课剩下的核心命题只有一条:控制复杂度。所有具体手段都能挂到这个母题下:
Java 课的面向对象、数据库课的范式、本课的设计模式,本质都是复杂度管理在某层的具体形态。把这个母题记住,后面每章你都知道「这个手段在管什么复杂度」。
用一个真实场景结束本章:大一课设,两个人合作,三个月。没有软件工程思维的做法:开闷头写,git 用得稀碎(整周一个 commit),最后三天通宵集成,merge 冲突三百行,演示前一晚发现两个人对「用户登录」的理解完全不同。有软件工程思维的做法:第一周对齐需求(写一页纸的需求清单,第 3 章)、按模块分界(第 4 章)、每天小步提交(第 9 章)、核心逻辑带测试(第 8 章)。同样的两个人,工时一样,结局天差地别,这门课的全部价值就在这类对比里。