原文作者:Tom Demarco,写于2009年7月

作者简介:Tom DeMarco是大西洋系统协会(www.atlsysguild.com)的负责人。他的职业生涯开始于贝尔实验室,是结构化分析和设计的创始人之一,研究领域主要集中在对软件组织和项目的风险管理。已经出版了好几本经典图书,包括《人件》、《最后期限》、《与熊共舞》等。

遥想当年在德国的加米施举行的NATO(North Atlantic Treaty Organization,即北大西洋公约组织)软件工程大会,迄今已有40载了。在那次会议上,软件工程(Software Engineering)作为一门学科被首次提出。因为我早年的一些工作成果被吸收入那个新学科,现在似乎是时候来重新评估一下了。

我早年写过一本关于软件度量的书,书名叫《Controlling Software Projects: Management, Measurement, and Estimates》(由Prentice Hall出版社于1986年出版)。很多初露头角的软件工程师在量化工作和规划项目时都把那本书奉为圭璧。如今我在反思之中,我想知道:书里的建议在那时候正确吗?现在还有用吗?我现在仍然相信“度量”是任何成功的软件开发活动所必需的吗?我的回答全部是否定的。

在我看来,那本书是一种古怪的组合——书里每一页上写的东西大体都是正确的,但把它们组合起来形成的中心思想却走向了谬误。似乎年轻的作者从未遇到过一个他不喜欢的度量。那本书诠释的内涵似乎是:度量是好东西,多多益善,我们应该来者不拒。现如今,我们都已经明白:软件度量是要花费金钱和时间的,使用起来要小心、有节制。另外,软件开发在本质上与自然科学(比如物理)是不同的;相应地,软件度量在获取它们要求的东西时会不精确得多。它们是值得怀疑的——我们不能毫无保留地相信它们。

控制是出于无奈

那本书被引用得最多的是它的第一句话:“你无法控制一个不能度量的东西。”这是一句大实话,但我越来越感受到它的不妥。这句话(其实还有那本书的书名)暗示着,“控制”是任何软件项目里很重要的一方面,也许还是最重要的。其实不然!很多项目都没有引入大量的控制,但它们开展得很好,而且还产出了绝妙的成果,比如Google Earth或Wikipedia。

为了真正地理解控制的作用,你必须区分两种截然不同的项目:

  • A项目:最终花费的成本将是100万美元,而创造的价值大概是110万美元;
  • B项目:最终花费的成本将是100万美元,但创造的价值超过5000万美元。

我们的第一反应是,控制对于A项目来说非常重要,但对于B项目几乎就是无所谓的。于是,我们得出了一个奇怪的结论:严格的控制对于相对而言无用的项目意义重大,而对于有用的项目的意义要小得多。这也暗示着,你在控制方面投入得越多,你越可能在累死累活地做着一个产出卑微的项目。

在我看来,与其纠结在“如何控制一个软件项目”,我们须面对的比那重要得多的问题是:我们究竟为什么要做这么多价值不高的项目?

项目无须控制,或者只需要相对而言很少的控制——我真的可以这么说吗?也差不多吧。我的建议是,我们首先应该选择做那些不太需要精确控制的项目。然后,不管我们将如何在控制方面施力,我们必须降低对自己控制能力的期望。

一个令人不安的类比

想象一下,你正在尽力抚养一个10几岁的少年。你想要控制你的孩子,这必定让你感到有些不适。然而,你不能加大控制的力度。搞不好的话,你会彻底失败,生活也就毁了。毋庸置疑的是,你不能完全放任自流。你就像是一个正在学习握剑的剑客,应该把手中之剑视作为一只小鸟——如果握得太紧,它会受伤;如果握得太松,它便飞走了。

接下来,把“你无法控制一个不能度量的东西”这句话用到你的孩子身上。你会发现,大部分重要的东西(比如荣誉、尊严、纪律、品格、压力下的风度、价值、道德、智慧、忠诚、幽默、善良等)都是无法度量的。你必须在没有很多反馈的情况下竭尽全力去指导你的孩子。这做起来很难,但为人父母本来就不是一件易事。说起来,你可以通过学校里的成绩来获取一些度量,你还为此暗自庆幸。不过,你也知道,与孩子的西班牙语成绩比起来,他的数学成绩更能反映他的学习情况,因为对数学的掌握程度更易于度量。他在举止风度上的“成绩”更可能反映的是老师的教学水平(而不是孩子的学习情况)。

那么,怎样才能在没有控制的情况下管理项目呢?其实,你要管理的是人,而你要控制的是时间和资金投入。举例来说,你要对团队主管这么说,“我已经想好了项目的交付日期,但我现在不会告诉你。将来有一天,我会去找你,告诉你需要在一周之内结束项目。你必须时刻准备着收拾局面,把已经完成的东西打包成最终产品交付出来。你要做的工作是,以递增的方式来开展项目,根据各块功能的价值高低顺序依次叠加进主产品,持续不断地做集成、文档以及验收测试。”

我建议的应对之策听起来像敏捷方法吧。不过,如今的我已经离软件开发前线很远很远,由我来推荐具体的方法是不合适的。我所主张的是一种管理方法,它可能恰恰把团队引向了敏捷方法(至少是敏捷流派提倡的增量开发模式)。

到目前为止,我谈论的几乎都是软件工程的度量这一部分。那么,其他方面怎么样呢?我慢慢地得出这样的结论:软件工程——这个概念流行过,但现在已经过时了。我仍然相信软件值得精耕细作。但是,那与软件工程并不完全是一回事。软件工程的范畴包含一系列特定的学科,包括明确的流程、检验与走查、需求工程、可追溯性模型、度量、精确的质量控制、严格的计划与追踪、编码与文档规范等等。所有这一切都为了追求实践的一致性和可预测性。

一致性和可预测性仍然是吸引人的,但它们从来就不是最重要的东西。要知道,在过去的40年里,我们一直在折磨着自己——我们始终无法在预算之内按时完成一个软件项目。但是,正如我前面暗示的那样,这也绝不应该成为最高的目标。实际上,更重要的目标是“改革”——创建能够改变世界、或者让一个公司脱胎换骨或改变其运营方式的软件。我们在改革方面是相当成功的,但这时常发生在控制的包围圈之外。无论是现在还是将来,软件开发总是带有点试验性质的。尽管实际的软件构造未必是试验,但它的概念却是。这是我们应该专注的地方。我们原本也应该一直专注在这方面。

Tom DeMarco:软件工程这个概念已过时?的更多相关文章

  1. 解决Maven项目编译时提示:源值1.5已过时,将在未来所有版本中删除

    每次编译项目时,都提示:源值1.5已过时,将在未来所有版本中删除 查了一些资料,发现是因为IDEA默认把项目的源代码版本设置为jdk1.5,目标代码设置为jdk1.5 解决方案:  修改Maven的S ...

  2. 某些输入文件使用或覆盖了已过时的 API

    android出现注: 某些输入文件使用或覆盖了已过时的 API. 注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译. 注: 某些输入文件使用了未经检查或不安全的操作. 注 ...

  3. 【转】android出现注: 某些输入文件使用或覆盖了已过时的 API。 注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。 注: 某些输入文件使用了未经检查或不安全的操作。 注

    使用Android studio打包应用程序出现如下错误: 注: 某些输入文件使用或覆盖了已过时的 API. 注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译. 注: 某些 ...

  4. Android Studio编译OsmAnd出现警告:GeoPointParserUtil.java使用或覆盖了已过时的 API。有关详细信息请使用-Xlint:deprecation重新编译

    [背景] 之前折腾: [记录]Android Studio中导入OsmAnd并编译 期间,遇到了编译警告: 1 2 3 4 5 :OsmAnd-java:compileJava 注: E:\crifa ...

  5. 关于SVN 操作 提示文件已过时,请先update

    提示文件已过时,请先update 错误产生原因:修改文件前没有先update,从svn获取该文件的最新版本. 解决方法:备份你修改后的文件,通过Revert恢复到服务器版本后,再比较之前备份的文件,进 ...

  6. WebMvcConfigurerAdapter已过时

    Spring Boot2.0的版本(创建的时候自动选择的这个版本),然后编译器告诉我WebMvcConfigurerAdapter已过时了 @Deprecated public abstract cl ...

  7. PoI 3.17 已过时代码对比

    PoI 3.17 已过时代码对比颜色定义变化旧版本 : HSSFColor.BLACK.index新版本 : IndexedColors.BLACK.index 获取单元格格式旧版本 : cell.g ...

  8. 使用IDEA运行项目时提示:Warning:java: 源值1.5已过时, 将在未来所有发行版中删除

    如图 在使用IDEA运行项目时,在下方提示:Warning:java: 源值1.5已过时, 将在未来所有发行版中删除 这是因为JDK版本问题 解决方法如下:左上角 file ——> Projec ...

  9. ConsoleLoggerExtensions.AddConsole(ILoggerFactory)已过时代码修复

    0x00.问题 netcoreapp2.2环境下, Startup.cs 代码配置如下 public void Configure(IApplicationBuilder app, IHostingE ...

随机推荐

  1. 从JVM角度看i++ 与++i

    1.i++和++i的问题 反编译结果为 Code:  0:   iconst_1  1:   istore_1  2:   iinc    1, 1 //这个个指令,把局部变量1,也就是i,增加1,这 ...

  2. 关于 form表单 嵌套问题的解决方案

    我们经常是这样嵌套的: <form id="formId1" action="" method="post"> //表单1 &l ...

  3. jquery easyui combobox 高度自适应

    data-options="required:true,editable:false,panelHeight:'auto'"  加上panelHeight:'auto'即可 列合并 ...

  4. Python学习札记-eval函数

    eval()函数 eval()官方文档里面给出来的功能解释是:将字符串string对象转化为有效的表达式参与求值运算返回计算结果 语法上:调用的是:eval(expression,globals=No ...

  5. Java 程序运行过程中的内存分析

    作为 java 程序员,都应该知道 Java 程序运行在 JVM(Java Virtual Machine,Java 虚拟机)上,可以把 JVM 理解成 Java 程序和操作系统之间的桥梁,JVM 实 ...

  6. c++ public,protected,private

    基类的私有成员被继承后不可见(优先级最高) 公有继承不改变基类成员属性 保护继承(私有继承)把基类成员变为保护成员(私有成员) public 公开的 protected 受保护的 private 私有 ...

  7. linux 3.10 缺页异常(TLB_invalid)通用处理框架

  8. MySQL where 子句

    MySQL where 子句 我们知道从MySQL表中使用SQL SELECT 语句来读取数据. 如需有条件地从表中选取数据,可将 WHERE 子句添加到 SELECT 语句中. 语法 以下是SQL ...

  9. 实验与作业(Python)-04 数据类型、数学函数与字符串

    截止日期 实验目标 继续熟悉for循环与turtle 数值运算符 math库常用函数 字符串转化为数值类型(int, float, complex) 字符串常用函数 实验内容 任务1.使用for代替w ...

  10. C/C++静态数组与动态数组的区别

    简介 以下三行代码有什么区别? int a[10]; int *a = (int*)malloc(sizeof(int)*10); int *a = new int[10]; 第一行代码定义a为包含1 ...