|
|
|
| |
|

《人月神话》

||
|

编程为什么有趣?它的从业者能得到什么样的快乐?

  • 首先是一种创建事物的纯粹快乐。如同小孩在玩泥巴时感到愉快一样,成年人喜欢创建事物,特别是自己进行设计。我想这种快乐是上帝创造世界的折射,一种呈现在每片独特、崭新的树叶和雪花上的喜悦。

  • 其次,快乐来自于开发对其他人有用的东西。内心深处,我们期望其他人使用我们的劳动成果,并能对他们有所帮助。从这个方面,这同小孩用粘土为”爸爸办公室”捏制铅笔盒没有本质的区别。

  • 第三是整个过程体现出魔术般的力量–将相互啮合的零部件组装在一起,看到它们精妙地运行,得到预先所希望的结果。比起弹珠游戏或点唱机所具有的迷人魅力,程序化的计算机毫不逊色。

  • 第四是学习的乐趣,来自于这项工作的非重复特性。人们所面临的问题,在某个或其它方面总有些不同。因而解决问题的人可以从中学习新的事物:有时是实践上的,有时是理论上的,或者兼而有之。

  • 最后,乐趣还来自于工作在如此易于驾驭的介质上。程序员,就像诗人一样,几乎仅仅工作在单纯的思考中。程序员凭空地运用自己的想象,来建造自己的”城堡”。很少有这样的介质–创造的方式如此得灵活,如此得易于精炼和重建,如此得容易实现概念上的设想。(不过我们将会看到,容易驾驭的特性也有它自己的问题)然而程序毕竟同诗歌不同,它是实实在在的东西;可以移动和运行,能独立产生可见的输出;能打印结果,绘制图形,发出声音,移动支架。神话和传说中的魔术在我们的时代已变成了现实。在键盘上键入正确的咒语,屏幕会活动、变幻,显示出前所未有的或是已经存在的事物。 编程非常有趣,在于它不仅满足了我们内心深处进行创造的渴望,而且还愉悦了每个人内在的情感。

职业的苦恼

然而这个过程并不全都是喜悦。我们只有事先了解一些编程固有的烦恼,这样,当它们真的出现时,才能更加坦然地面对。

首先,必须追求完美。因为计算机也是以这样的方式来变戏法:如果咒语中的一个字符、一个停顿,没有与正确的形式一致,魔术就不会出现。(现实中,很少的人类活动要求完美,所以人类对它本来就不习惯。)实际上,我认为学习编程的最困难部分,是将做事的方式往追求完美的方向调整。

其次,是由他人来设定目标,供给资源,提供信息。编程人员很少能控制工作环境和工作目标。用管理的术语来说,个人的权威和他所承担的责任是不相配的。不过,似乎在所有的领域中,对要完成的工作,很少能提供与责任相一致的正式权威。而现实情况中,实际(相对于正式)的权威来自于每次任务的完成。

对于系统编程人员而言,对其他人的依赖是一件非常痛苦的事情。他依靠其他人的程序,而往往这些程序设计得并不合理,实现拙劣,发布不完整(没有源代码或测试用例),或者文档记录得很糟。所以,系统编程人员不得不花费时间去研究和修改,而它们在理想情况下本应该是可靠完整的。

下一个烦恼–概念性设计是有趣的,但寻找琐碎的bug却只是一项重复性的活动。 伴随着创造性活动的,往往是枯燥沉闷的时间和艰苦的劳动。程序编制工作也不例外。

另外,人们发现调试和查错往往是线性收敛的,或者更糟糕的是,具有二次方的复杂度。结果,测试一拖再拖,寻找最后一个错误比第一个错误将花费更多的时间。

最后一个苦恼,有时也是一种无奈–当投入了大量辛苦的劳动,产品在即将完成或者终于完成的时候,却已显得陈旧过时。可能是同事和竞争对手已在追逐新的、更好的构思;也许替代方案不仅仅是在构思,而且已经在安排了。

这,就是编程。一个许多人痛苦挣扎的焦油坑以及一种乐趣和苦恼共存的创造性活动。

美酒的酿造需要年头,美食的烹调需要时间;片刻等待,更多美味,更多享受。

  • 新奥尔良Antoine餐厅的菜单

Good cooking takes time. If you are made to wait, it is to serve you better, and to please you.

  • MENU OF RESTAURANT ANTOINE, NEW ORLEANS

第二个谬误的思考方式是在估计和进度安排中使用的工作量单位:人月。成本的确随开发产品的人数和时间的不同,有着很大的变化,进度却不是如此。因此我认为用人月作为衡量一项工作的规模是一个危险和带有欺骗性的神话。它暗示着人员数量和时间是可以相互替换的。 人数和时间的互换仅仅适用于以下情况:某个任务可以分解给参与人员,并且他们之间不需要相互的交流。这在割小麦或收获棉花的工作中是可行的,而在系统编程中近乎不可能。

无论多少个母亲,孕育一个生命都需要十个月。

在计算机领域的会议中,常常听到年轻的软件经理声称:他们喜欢由头等人才组成的小型精干的队伍,而不是那些几百人的大型团队,这里的”人”当然暗指平庸的程序员。其实我们也经常有相同的看法。 但这种幼稚的观点回避了一个很困难的问题–如何在有意义的时间进度内创建大型的系统?

软件经理很早就认识到优秀程序员和较差的程序员之间生产率的差异,但实际测量出的差异还是令我们所有的人吃惊。在他们的一个研究中,Sackman、Erikson和Grand曾对一组具有经验的程序人员进行测量。在该小组中,最好的和最差的表现在生产率上平均为10:1;在运行速度和空间上具有5:1的惊人差异!简言之,$20,000/年的程序员的生产率可能是$10,000/年程序员的10倍。数据显示经验和实际的表现没有相互联系。

对于效率和概念的完整性来说,最好由少数干练的人员来设计和开发,而对于大型系统,则需要大量的人手,以使产品能在时间上满足要求。

Mills建议大型项目的每一个部分由一个团队解决,但是该队伍以类似外科手术的方式组建,而并非一拥而上。 也就是说,同每个成员截取问题某个部分的做法相反,由一个人来进行问题的分解,其他人给予他所需要的支持,以提高效率和生产力。

外科医生。Mills称之为首席程序员。他亲自定义功能和性能技术说明书,设计程序,编制源代码,测试以及书写技术文档。他使用例如PL/I的结构化编程语言,拥有对计算机系统的访问能力;该计算机系统不仅仅能进行测试,还存储程序的各种版本,以允许简单的文件更新,并对他的文档提供文本编辑能力。首席程序员需要极高的天分、十年的经验和应用数学、业务数据处理或其他方面的大量系统和应用知识。

副手。他是外科医生的后备,能完成任何一部分工作,但是相对具有较少的经验。他的主要作用是作为设计的思考者、讨论者和评估人员。外科医生试图和他沟通设计,但不受到他建议的限制。副手经常在与其他团队的功能和接口讨论中代表自己的小组。他需要详细了解所有的代码,研究设计策略的备选方案。显然,他充当外科医生的保险机制。他甚至可能编制代码,但针对代码的任何部分,不承担具体的开发职责。

管理员。外科医生是老板,他必须在人员、加薪等方面具有决定权,但他决不能在这些事务上浪费任何时间。因而,他需要一个控制财务、人员、工作地点安排和机器的专业管理人员,该管理员充当与组织中其他管理机构的接口。Baker建议仅在项目具有法律、合同、报表和财务方面的需求时,管理员才具有全职责任。否则,一个管理员可以为两个团队服务。

编辑。外科医生负责产生文档–出于最大清晰度的考虑,他必须书写文档。对内部描述和外部描述都是如此。而编辑根据外科医生的草稿或者口述的手稿,进行分析和重新组织,提供各种参考信息和书目,对多个版本进行维护以及监督文档生成的机制。

两个秘书。管理员和编辑每个人需要一个秘书。管理员的秘书负责项目的协作一致和非产品文件。

程序职员。他负责维护编程产品库中所有团队的技术记录。该职员接受秘书性质的培训,承担机器码文件和可读文件的相关管理责任。 所有的计算机输入汇集到这个职员处。如果需要,他会对它们进行记录或者标识。输出列表会提交给程序职员,由他进行归档和编制索引。另外,他负责将任何模型的最新运行情况记录在状态日志中,而所有以前的结果则按时间顺序进行归档保存。

程序职员的专业化分工,使程序员从书记的杂事中解放出来,同时还可以对那些杂事进行系统整理,确保了它们的质量,并强化了团队最有价值的财富–工作产品。

工具维护人员。现在已经有很多文件编辑、文本编辑和交互式调试等工具,因此团队很少再需要自己的机器和机器操作人员。但是这些工具使用起来必须毫无疑问地令人满意,而且需要具备较高的可靠性。外科医生则是这些工具、服务可用性的唯一评判人员。他需要一个工具维护人员,保证所有基本服务的可靠性,以及承担团队成员所需要的特殊工具(特别是交互式计算机服务)的构建、维护和升级责任。即使已经拥有非常卓越的、可靠的集中式服务,每个团队仍然要有自己的工具人员。因为他的工作是检查他的外科医生所需要的工具。工具维护人员常常要开发一些实用程序、编制具有目录的过程库以及宏库。

测试人员。外科医生需要大量合适的测试用例,用来对他所编写的工作片段,以及对整个工作进行测试。因此,测试人员既是为他的各个功能设计系统测试用例的对头,同时也是为他的日常调试设计测试数据的助手。他还负责计划测试的步骤和为测试搭建测试平台。

语言专家。随着Algol语言的出现,人们开始认识到大多数计算机项目中,总有一两个乐于掌握复杂编程语言的人。这些专家非常有帮助,很快大家会向他咨询。这些天才不同于外科医生,外科医生主要是系统设计者以及考虑系统的整体表现。而语言专家则寻找一种简洁、有效的使用语言的方法来解决复杂、晦涩或者棘手的问题。他通常需要对技术进行一些研究(两到三天)。通常一个语言专家可以为两个到三个外科医生服务。

十个人,其中七个专业人士在解决问题,而系统是一个人或者最多两个人思考的产物,因此客观上达到了概念的一致性。

在外科手术团队中,外科医生和副手都了解所有的设计和全部的代码。这节省了空间分配、磁盘访问等的劳动量,同时也确保了工作概念上的完整性。

第二,在传统的队伍中大家是平等的,出现观点的差异时,不可避免地需要讨论和进行相互的妥协和让步。由于工作和资源的分解,不同的意见会造成策略和接口上的不一致,例如谁的空间会被用作缓冲区,然而最终它们必须整合在一起。而在外科手术团队中,不存在利益的差别,观点的不一致由外科医生单方面来统一。这两种团队组建上的差异–对问题不进行分解和上下级的关系–使外科手术队伍可以达到客观的一致性。 另外,团队中剩余人员职能的专业化分工是高效的关键,它使成员之间采用非常简单的交流模式成为可能。

就目前情况而言,还不错。然而,现在所面临的问题是如何完成5000人年的项目。

扩建过程的成功依赖于这样一个事实,即每个部分的概念完整性得到了彻底的提高–决定设计的人员是原来的七分之一或更少。所以,可以让200人去解决问题,而仅仅需要协调20个人,即那些”外科医生”的思路。

功能,而非简洁,总是被用来衡量设计人员工作的出色程度。

我当然不认为只有结构师才有好的创意。新的概念经常来自实现者或者用户。

我一直试图表达,并且我所有的经验使我确信:系统的概念完整性决定了使用的容易程度。不能与系统基本概念进行整合的良好想法和特色,最好放到一边,不予考虑。

如果出现了很多非常重要但不兼容的构想,就应该抛弃原来的设计,对不同基本概念进行合并,在合并后的系统上重新开始。

面对估算过高的难题,结构师有两个选择:削减设计或者建议成本更低的实现方法–挑战估算的结果。后者是固有的主观感性反应。此时,结构师是在向开发人员的做事方式提出挑战。想要成功,结构师必须:

  • 牢记是开发人员承担创造性和发明性的实现责任,所以结构师只能建议,而不能支配;

  • 时刻准备着为所指定的说明建议一种实现的方法,同样准备接受其他任何能达到目标的方法;

  • 对上述的建议保持低调和平静;

  • 准备放弃坚持所作的改进建议;

  • 一般开发人员会反对体系结构上的修改建议。通常他是对的–当正在实现产品时,某些特性的修改会造成意料不到的成本开销。

一种普遍倾向是过分地设计第二个系统,向系统添加很多修饰功能和想法,它们曾在第一个系统中被小心谨慎地推迟了。结果如同Ovid所述,这是一个”大馅饼”。

在设计第一个项目时,他会面对不断产生的装饰和润色功能。这些功能都被搁置在一边,作为”下一个”项目的内容。第一个项目迟早会结束,而此时的结构师,对这类系统充满了十足的信心,熟练掌握了相应的知识,并且时刻准备开发第二个系统。

结构师如何避免画蛇添足–开发第二个系统所引起的后果(second-system effect)?是的,他无法跳过二次系统。但他可以有意识关注那些系统的特殊危险,运用特别的自我约束准则,来避免那些功能上的修饰;根据系统基本理念及目的变更,舍弃一些功能。

手册、或者书面规格说明,是一个非常必要的工具,尽管光有文档是不够的。手册是产品的外部规格说明,它描述和规定了用户所见的每一个细节;同样的,它也是结构师主要的工作产物。手册不但要描述包括所有界面在内的用户可见的一切,它同时还要避免描述用户看不见的事物。

一句古老的格言警告说:”决不要携带两个时钟出海,带一个或三个。”同样的原则也适用于形式化和记叙性定义。如果同时具有两种方式,则必须以一种作为标准,另一种作为辅助描述,并照此明确地进行划分

既然他们具备了所有的这些条件,为什么项目还会失败呢?他们还缺乏些什么?两个方面–交流,以及交流的结果–组织。他们无法相互交谈,从而无法合作。当合作无法进行时,工作陷入了停顿。通过史书的字里行间,我们推测交流的缺乏导致了争辩、沮丧和群体猜忌。很快,部落开始分裂–大家选择了孤立,而不是互相争吵。

那么技术主管的角色是什么?他对设计进行构思,识别系统的子部分,指明从外部看上去的样子,勾画它的内部结构。他提供整个设计的一致性和概念完整性;他控制系统的复杂程度。当某个技术问题出现时,他提供问题的解决方案,或者根据需要调整系统设计。用Al Capp所喜欢的一句谚语,他是”攻坚小组中的独行侠”(inside-man at the skunk works.)。他的沟通交流在团队中是首要的。他的工作几乎完全是技术性的。

产品负责人的角色是什么?他组建团队,划分工作及制订进度表。他要求,并一直要求必要的资源。这意味着他主要的工作是与团队外部,向上和水平地沟通。他建立团队内部的沟通和报告方式。最后,他确保进度目标的实现,根据环境的变化调整资源和团队的构架。

产品负责人和技术主管是同一个人。这种方式非常容易应用在很小型的队伍中,可能是三个或六个开发人员。在大型的项目中则不容易得到应用。原因有两个:

  • 第一,同时具有管理技能和技术技能的人很难找到。思考者很少,实干家更少,思考者-实干家太少了。

  • 第二,大型项目中,每个角色都必须全职工作,甚至还要加班。

对负责人来说,很难在承担全部管理责任的同时,还能抽出时间进行技术工作。对技术主管来说,很难在保证设计的概念完整性,没有任何妥协的前提下,担任管理工作。 产品负责人作为总指挥,技术主管充当其左右手。这种方法有一些困难。很难在技术主管不参与任何管理工作的同时,建立在技术决策上的权威。

产品负责人必须预先声明技术主管的技术权威,在即将出现的绝大部分测试用例中,他必须支持后者的技术决定。要达到这一点,产品责任人和技术主管必须在基本的技术理论上具有相似观点;他们必须在主要的技术问题出现之前,私下讨论它们;产品责任人必须对技术主管的技术才能表现出尊重。

小技巧:产品责任人可以通过一些微妙状态特征暗示来(如,办公室的大小、地毯、装修、复印机等等)体现技术主管的威信,尽管决策权力的源泉来自管理。

对于真正大型项目中的一些开发队伍,我认为产品负责人作为管理者是更合适的安排。

Coster低下头,双手捂着脸,接着,抬起头。”我知道。我了解需要做什么–但每次我试图解决技术问题时,总有些该死的笨蛋要我做一些关于卡车、或者电话、以及其他一些讨厌的事情。我很抱歉。Harriman先生,我原以为我可以处理好。”

“如果要做任何非技术的事情,不需要自己动手。只需按个按钮知会一声,它们就会被完成!

实践是最好的老师,但是,如果不能从中学习,再多的实践也没有用。

  • 《可怜的理查年鉴》

Practice is the best of all instructors. - PUBILIUS Experience is a dear teacher, but fools will learn at no other.

  • POOR RICHARD’S ALMANAC

为什么要有正式的文档?

  • 首先,书面记录决策是必要的。只有记录下来,分歧才会明朗,矛盾才会突出。书写这项活动需要上百次的细小决定,正是由于它们的存在,人们才能从令人迷惑的现象中得到清晰、确定的策略。

  • 第二,文档能够作为同其他人的沟通渠道。项目经理常常会不断发现,许多理应被普遍认同的策略,完全不为团队的一些成员所知。正因为项目经理的基本职责是使每个人都向着相同的方向前进,所以他的主要工作是沟通,而不是做出决定。这些文档能极大地减轻他的负担。

  • 最后,项目经理的文档可以作为数据基础和检查列表。通过周期性的回顾,他能清楚项目所处的状态,以及哪些需要重点进行更改和调整。

项目经理的任务是制订计划,并根据计划实现。但是只有书面计划是精确和可以沟通的。

普遍的做法是,选择一种方法,试试看;如果失败了,没关系,再试试别的。不管怎么样,重要的是先去尝试。

  • 富兰克林 D. 罗斯福

There is nothing in this world constant but inconstancy.

唯一不变的就是变化本身

最重要的措施是使用高级语言和自文档技术,以减少变更引起的错误。采用编译时的操作来整合标准声明,在很大程度上帮助了变化的调整。

从技术角度而言,整个团队可以灵活地安排。在大型的项目中,项目经理需要有两个和三个顶级程序员作为技术轻骑兵,当工作繁忙最密集的时候,他们能急驰飞奔,解决各种问题。

对于一个广泛使用的程序,其维护总成本通常是开发成本的40%或更多。令人吃惊的是,该成本受用户数目的严重影响。用户越多,所发现的错误也越多。

巧匠因为他的工具而出名。

  • 谚语 A good workman is known by his tools. - PROVERB

每个骨干人员都仔细地保管自己工作生涯中搜集的一套工具集,这些工具成为个人技能的直观证明。

我能召唤遥远的精灵。 那又怎么样,我也可以,谁都可以,问题是你真的召唤的时候,它们会来吗?

  • 莎士比亚,《亨利四世》,第一部分

I can call spirits from the vasty deep. Why, so can I, or so can any man; but will they come when you do call for them?

  • SHAKESPEARE, KING HENRY IV, Part I

带来坏消息的人不受欢迎。

  • 索福克里斯

地毯的下面

当一线经理发现自己的队伍出现了计划偏离时,他肯定不会马上赶到老板那里去汇报这个令人沮丧的消息。团队可以弥补进度偏差,他可以想出应对方法或者重新安排进度以解决问题,为什么要去麻烦老板呢?从这个角度来看,好像还不错。解决这类问题的确是一线经理的职责。老板已经有很多需要处理的真正的烦心事了,他不想被更多的问题打搅。因此,所有的污垢都被隐藏在地毯之下。

但是每个老板都需要两种信息:需要采取行动的计划方面的问题,用来进行分析的状态数据。出于这个目的,他需要了解所有开发队伍的情况,但得到状态的真相是很困难的。

一线经理的利益和老板的利益是内在冲突的。一线经理担心如果汇报了问题,老板会采取行动,这些行动会取代经理的作用,降低自己的威信,搞乱了其他计划。所以,只要项 目经理认为自己可以独立解决问题,他就不会告诉老板。

有两种掀开毯子把污垢展现在老板面前的方法,它们必须都被采用。一种是减少角色冲突和鼓励状态共享,另一种是猛地拉开地毯。 减少角色的冲突。首先老板必须区别行动信息和状态信息。他必须规范自己,不对项目经理可以解决的问题做出反应,并且决不在检查状态报告的时候做安排。我曾经认识一个老板,他总是在状态报告的第一个段落结束之前,拿起电话发号施令。这样的反应肯定压制信息的完全公开。 不过,当项目经理了解到老板收到项目报告之后不会惊慌,或者不会越俎代庖时,他就逐渐会提交真实的评估结果。




猛地拉开地毯。不论协作与否,拥有能了解状态真相的评审机制是必要的。PERT图以及频繁的里程碑是这种评审的基础。大型项目中,可能需要每周对某些部分进行评审,大约一个月左右进行整体评审。

不了解,就无法真正拥有。

  • 歌德 - 克雷布

What we do not understand we do not possess.

  • GOETHE

我认为”自文档化”方法的基本思想可以得到大规模的应用。”“自文档化”方法”对空间和格式要求更为严格,这一点的应用可能会受限;而命名和结构化声明显然可以利用起来,在这方面,宏可以起到很大的帮助;另外,段落注释的广泛使用在任何语言中都是一个很棒的实践。

自文档化方法激发了高级语言的使用,特别是用于在线系统的高级语言–无论是对批处理还是交互式,它都表现出最强的功效和应用的理由。如同我曾经提到的,上述语言和系统强有力地帮助了编程人员。因为是机器为人服务,而不是人为机器服务。因此从各个方面而言,无论是从经济上还是从以人为本的角度来说,它们的应用都是非常合情合理的

没有任何技术或管理上的进展,能够独立地许诺十年内使生产率、可靠性或简洁性获得数量级上的进步。 There is no single development, in either technology or management technique, which by itself promises even one order-of-magnitude improvement within a decade in productivity, in reliability, in simplicity.

所有软件活动包括根本任务–打造由抽象软件实体构成的复杂概念结构,次要任务–使用编程语言表达这些抽象实体,在空间和时间限制内将它们映射成机器语言。

我们看看近十年来的情况,没有银弹的踪迹。没有任何技术或管理上的进展能够独立地许诺在生产率、可靠性或简洁性上取得数量级的提高。

软件开发总是非常困难的。天生就没有银弹。 让我们来考虑现代软件系统中这些无法规避的内在特性:复杂度、一致性、可变性和不可见性。

勿庸置疑,软件生产率、可靠性和简洁性上最有力的突破是使用高级语言编程。大多数观察者相信开发生产率至少提高了五倍,同时可靠性、简洁性和理解程度也大为提高。

寄存器、条件、分支、通道、磁盘等等。高级语言所达到的抽象程度包含了(抽象)程序所需要的要素,避免了更低级的元素,它消除了并不是程序所固有的整个级别的复杂度

对于较少使用那些复杂深奥语言要素的用户,高级语言在某种程度上增加而不是减少了脑力劳动上的负担。

“自动”编程。近四十年中,人们一直在预言和编写有关”自动编程”的文字,从问题的一段陈述说明自动产生解决问题的程序。现在,仍有一些人期望这样的技术能够成为下一个突破点

构建专家系统的必要前提条件是拥有专家。 专家系统最强有力的贡献是给缺乏经验的开发人员提供服务,用最优秀开发者的经验和知识积累为他们提供了指导。这是非常大的贡献

随着工作站的处理能力和内存容量的稳固和快速提高,我们能期望在软件领域取得多大的收获呢?现在的运算速度已经可以完全满足程序编制和文档书写的需要。编译还需要一些提高,不过一旦机器运算速度提高十倍,那么程序开发人员的思考活动将成为日常工作的主要活动。实际上,这已经是现在的情况。

以上提到的任何软件,购买都要比重新开发要低廉一些。即使支付100,000美元,购买的软件也仅仅是一个人年的成本。而且软件是立即可用的!至少对于现有的产品、对于那些专注于该领域开发者的成果而言,它们是可以立刻投入使用的。并且,它们往往配备了书写良好的文档,在某种程度上比自行开发的软件维护得更加完备。

昨天的复杂性是今天的规律。

我的妻子、同事和我的编辑发现我犯乐观主义错误的几率远远大于悲观主义。 毕竟,我的从业背景是程序员,乐观主义是这个行业的职业病。

全书回顾总结

第一章

编程行业”满足我们内心深处的创造渴望和愉悦所有人的共有情感”,提供了五种乐趣:

  • 创建事物的快乐

  • 开发对其他人有用的东西的乐趣

  • 将可以活动、相互啮合的零部件组装成类似迷宫的东西,这个过程所体现出令人神魂颠倒的魅力

  • 面对不重复的任务,不间断学习的乐趣

  • 工作在如此易于驾驭的介质上的乐趣–纯粹的思维活动,其存在、移动和运转方式完全不同于实际物体。

同样,这个行业具有一些内在固有的苦恼:

  • 将做事方式调整到追求完美,是学习编程的最困难部分

  • 由其他人来设定目标,并且必须依靠自己无法控制的事物(特别是程序);

  • 权威不等同于责任

  • 实际情况看起来要比这一点好一些:真正的权威来自于每次任务的完成

  • 任何创造性活动都伴随着枯燥艰苦的劳动,编程也不例外

  • 人们通常期望项目在接近结束时,(bug、工作时间)能收敛得快一些,然而软件项目的情况却是越接近完成,收敛得越慢

  • 产品在即将完成时总面临着陈旧过时的威胁

第二章

人月神话

2.1 缺乏合理的时间进度是造成项目滞后的最主要原因,它比其他所有因素加起来影响还大。

2.2 良好的烹饪需要时间,某些任务无法在不损害结果的情况下加快速度。

2.3 所有的编程人员都是乐观主义者:”一切都将运作良好”。

2.4 由于编程人员通过纯粹的思维活动来开发,所以我们期待在实现过程中不会碰到困难。

2.5 但是,我们的构思是有缺陷的,因此总会有bug。

2.6 我们围绕成本核算的估计技术,混淆了工作量和项目进展。人月是危险和带有欺骗性的神话,因为它暗示人员数量和时间是可以相互替换的。

2.7 在若干人员中分解任务会引发额外的沟通工作量–培训和相互沟通。

2.8 关于进度安排,我的经验是为1/3计划、1/6编码、1/4构件测试以及1/4系统测试。 2.9 作为一个学科,我们缺乏数据估计。

2.10 因为我们对自己的估计技术不确定,所以在管理和客户的压力下,我们常常缺乏坚持的勇气。

2.11 Brook法则:向进度落后的项目中增加人手,只会使进度更加落后。

2.12 向软件项目中增派人手从三个方面增加了项目必要的总体工作量:任务重新分配本身和所造成的工作中断;培训新人员;额外的相互沟通。

外科手术队伍

3.1 同样有两年经验而且在受到同样的培训的情况下,优秀的专业程序员的工作效率是较差程序员的十倍。(Sackman、Erikson和Grand)

3.2 Sackman、Erikson和Grand的数据显示经验和实际表现之间没有相互联系。我怀疑这种现象是否普遍成立。

3.3 小型、精干队伍是最好的–尽可能的少。

3.4 两个人的团队,其中一个项目经理,常常是最佳的人员使用方法。[留意一下上帝对婚姻的设计。]

3.5 对于真正意义上的大型系统,小型精干的队伍太慢了。

3.6 实际上,绝大多数大型编程系统的经验显示出,一拥而上的开发方法是高成本、速度缓慢、不充分的,开发出的产品无法进行概念上的集成。

3.7 一位首席程序员、类似于外科手术队伍的团队架构提供了一种方法–既能获得由少数头脑产生的产品完整性,又能得到多位协助人员的总体生产率,还彻底地减少了沟通的工作量。

贵族专制、民主政治和系统设计

4.1 “概念完整性是系统设计中最重要的考虑因素”。

4.2 “功能与理解上的复杂程度的比值才是系统设计的最终测试标准”,而不仅仅是丰富的功能。[该比值是对易用性的一种测量,由简单和复杂应用共同验证。]

4.3 为了获得概念完整性,设计必须由一个人或者具有共识的小型团队来完成。

4.4 “对于非常大型的项目,将设计方法、体系结构方面的工作与具体实现相分离是获得概念完整性的强有力方法。”[同样适用于小型项目。]

4.5 “如果要得到系统概念上的完整性,那么必须控制这些概念。这实际上是一种无需任何歉意的贵族专制统治。”

4.6 纪律、规则对行业是有益的。外部的体系结构规定实际上是增强,而不是限制实现小组的创造性。

4.7 概念上统一的系统能更快地开发和测试。

4.8 体系结构(architecture)、设计实现(implementation)、物理实现(realization)的许多工作可以并发进行。[软件和硬件设计同样可以并行。

画蛇添足

5.1 尽早交流和持续沟通能使结构师有较好的成本意识,以及使开发人员获得对设计的信心,并且不会混淆各自的责任分工。

5.2 结构师如何成功地影响实现:

  • 牢记是开发人员承担创造性的实现责任;结构师只能提出建议。

  • 时刻准备着为所指定的说明建议一种实现的方法,准备接受任何其他可行的方法。

  • 对上述的建议保持低调和平静。

  • 准备对所建议的改进放弃坚持。

  • 听取开发人员在体系结构上改进的建议。

5.3 第二个系统是人们所设计的最危险的系统,通常的倾向是过分地进行设计。

5.4 OS/360是典型的画蛇添足(second-system effect)的例子。[Windows NT似乎是90年代的例子。]

5.5 为功能分配一个字节和微秒的优先权值是一个很有价值的规范化方法。

第6章 贯彻执行

6.1 即使是大型的设计团队,设计结果也必须由一个或两个人来完成,以确保这些决定是一致的。

6.2 必须明确定义体系结构中与先前定义不同的地方,重新定义的详细程度应该与原先的说明一致。

6.3 出于精确性的考虑,我们需要形式化的设计定义,同样,我们需要记叙性定义来加深理解。

6.4 必须采用形式化定义和记叙性定义中的一种作为标准,另一种作为辅助措施;它们都可以作为表达的标准。

6.5 设计实现,包括模拟仿真,可以充当一种形式化定义的方法;这种方法有一些严重的缺点。

6.6 直接整合是一种强制推行软件的结构性标准的方法。[硬件上也是如此–考虑内建在ROM中的Mac WIMP接口。]

6.7 “如果起初至少有两种以上的实现,那么(体系结构)定义会更加整洁,会更加规范。”

6.8 允许体系结构师对实现人员的询问做出电话应答解释是非常重要的,并且必须进行日志记录和整理发布。[电子邮件是一种可选的介质。]

6.9 “项目经理最好的朋友就是他每天要面对的敌人–独立的产品测试机构/小组。”

第7章 为什么巴比伦塔会失败?

7.1 巴比伦塔项目的失败是因为缺乏交流,以及交流的结果–组织。

7.2 “因为左手不知道右手在做什么,从而进度灾难、功能的不合理和系统缺陷纷纷出现。”由于对其他人的各种假设,团队成员之间的理解开始出现偏差。

7.3 团队应该以尽可能多的方式进行相互之间的交流:非正式、常规项目会议,会上进行简要的技术陈述、共享的正式项目工作手册。[以及电子邮件。] 项目工作手册

7.4 项目工作手册”不是独立的一篇文档,它是对项目必须产生的一系列文档进行组织的一种结构。”

7.5 “项目所有的文档都必须是该(工作手册)结构的一部分。”

7.6 需要尽早和仔细地设计工作手册结构。

7.7 事先制订了良好结构的工作手册”可以将后来书写的文字放置在合适的章节中”,并且可以提高产品手册的质量。

7.8 “每一个团队成员应该了解所有的材料(工作手册)。”[我想说的是,每个团队成员应该能够看到所有材料,网页即可满足要求。]

7.9 实时更新是至关重要的。

7.10 工作手册的使用者应该将注意力集中在上次阅读后的变更,以及关于这些变更重要性的评述。

7.11 OS/360项目工作手册开始采用的是纸介质,后来换成了微缩胶片。

7.12 今天[即使在1975年],共享的电子手册是能更好达到所有这些目标、更加低廉、更加简单的机制。

7.13 仍然需要用变更条和修订日期[或具备同等功能的方法]来标记文字;仍然需要后进先出(LIFO)的电子化变更小结。

7.14 Parnas强烈地认为使每个人看到每件事的目标是完全错误的;各个部分应该被封装,从而没有人需要或者允许看到其他部分的内部结构,只需要了解接口。

7.15 Parnas的建议的确是灾难的处方。 组织架构

7.16 团队组织的目标是为了减少必要的交流和协作量。

7.17 为了减少交流,组织结构包括了人力划分(division of labor)和限定职责范围(specialization of function)。

7.18 传统的树状组织结构反映了权力的结构原理–不允许双重领导。

7.19 组织中的交流是网状,而不是树状结构,因而所有的特殊组织机制(往往体现成组织结构图中的虚线部分)都是为了进行调整,以克服树状组织结构中交流缺乏的困难。 7.20 每个子项目具有两个领导角色–产品负责人、技术主管或结构师。这两个角色的职能有着很大的区别,需要不同的技能。

7.21 两种角色中的任意组合可以是非常有效的: .. 产品负责人和技术主管是同一个人。 .. 产品负责人作为总指挥,技术主管充当其左右手。 .. 技术主管作为总指挥,产品负责人充当其左右手。

第8章 胸有成竹

8.1 仅仅通过对编码部分的估计,然后乘以任务其他部分的相对系数,是无法得出对整项工作的精确估计的。

8.2 构建独立小型程序的数据不适用于编程系统项目。

8.3 程序开发呈程序规模的指数增长。

8.4 一些发表的研究报告显示指数约为1.5。[Boehm的数据并不完全一致,在1.05和1.2之间变化。1]

8.5 Portman的ICL数据显示相对于其他活动开销,全职程序员仅将50%的时间用于编程和调试。

8.6 IBM的Aron数据显示,生产率是系统各个部分交互的函数,在1.5K千代码行/人年至10K千代码行/人年的范围内变化。

8.7 Harr的Bell实验室数据显示对于已完成的产品,操作系统类的生产率大约是0.6KLOC/人年,编译类工作的生产率大约为2.2KLOC/人年。

8.8 Brooks的OS/360S数据与Harr的数据一致:操作系统0.6~0.8KLOC/人年,编译器2~3 KLOC/人年。

8.9 Corbato的MIT项目MULTICS数据显示,在操作系统和编译器混合类型上的生产率是1.2KLOC/人年,但这些是PL/I的代码行,而其他所有的数据是汇编代码行。

8.10 在基本语句级别,生产率看上去是个常数。

8.11 当使用适当的高级语言时,程序编制的生产率可以提高5倍。

第9章 削足适履

9.1 除了运行时间以外,所占据的内存空间也是主要开销。特别是对于操作系统,它的很多程序是永久驻留在内存中。

9.2 即便如此,花费在驻留程序所占据内存上的金钱仍是物有所值的,比其他任何在配置上投资的效果要好。规模本身不是坏事,但不必要的规模是不可取的。

9.3 软件开发人员必须设立规模目标,控制规模,发明一些减少规模的方法–就如同硬件开发人员为减少元器件所做的一样。

9.4 规模预算不仅仅在占据内存方面是明确的,同时还应该指明程序对磁盘的访问次数。

9.5 规模预算必须与分配的功能相关联;在指明模块大小的同时,确切定义模块的功能。

9.6 在大型的团队中,各个小组倾向于不断地局部优化,以满足自己的目标,而较少考虑队用户的整体影响。这种方向性的问题是大型项目的主要危险。

9.7 在整个实现的过程期间,系统结构师必须保持持续的警觉,确保连贯的系统完整性。

9.8 培养开发人员从系统整体出发、面向用户的态度是软件编程管理人员最重要的职能。

9.9 在早期应该制订策略,以决定用户可选项目的粗细程度,因为将它们作为整体大包能够节省内存空间。[常常还可以节约市场成本。]

9.10 临时空间的尺寸,以及每次磁盘访问的程序数量是很关键的决策,因为性能是规模的非线性函数。[这个整体决策已显得过时–起初是由于虚拟内存,后来则是成本低廉的内存。现在的用户通常会购买能容纳主要应用程序所有代码的内存。]

9.11 为了取得良好的空间-时间折衷,开发队伍需要得到特定与某种语言或者机型的编程技能培训,特别是在使用新语言或者新机器时。

9.12 编程需要技术积累,每个项目需要自己的标准组件库。

9.13 库中的每个组件需要有两个版本,运行速度较快和短小精炼的。[现在看来有些过时。]

9.14 精炼、充分和快速的程序。往往是战略性突破的结果,而不仅仅技巧上的提高。

9.15 这种突破常常是一种新型算法。

9.16 更普遍的是,战略上突破常来自于数据或表的重新表达。数据的表现形式是编程的根本。

第10章 提纲挈领

10.1 “前提:在一片文件的汪洋中,少数文档形成了关键的枢纽,每个项目管理的工作都围绕着它们运转。它们是经理们的主要个人工具。”

10.2 对于计算机硬件开发项目,关键文档是目标、手册、进度、预算、组织机构图、空间分配、以及机器本身的报价、预测和价格。

10.3 对于大学科系,关键文档类似:目标、课程描述、学位要求、研究报告、课程表和课程的安排、预算、教室分配、教师和研究生助手的分配。

10.4 对于软件项目,要求是相同的:目标、用户手册、内部文档、进度、预算、组

第10章 提纲挈领

10.1 “前提:在一片文件的汪洋中,少数文档形成了关键的枢纽,每个项目管理的工作都围绕着它们运转。它们是经理们的主要个人工具。”

10.2 对于计算机硬件开发项目,关键文档是目标、手册、进度、预算、组织机构图、空间分配、以及机器本身的报价、预测和价格。

10.3 对于大学科系,关键文档类似:目标、课程描述、学位要求、研究报告、课程表和课程的安排、预算、教室分配、教师和研究生助手的分配。

10.4 对于软件项目,要求是相同的:目标、用户手册、内部文档、进度、预算、组织机构图和工作空间分配。

10.5 因此,即使是小型项目,项目经理也应该在项目早期规范化上述的一系列文档。

10.6 以上集合中每一个文档的准备工作都将注意力集中在对讨论的思索和提炼,而书写这项活动需要上百次的细小决定,正是由于它们的存在,人们才能从令人迷惑的现象中得到清晰、确定的策略。

10.7 对每个关键文档的维护提供了状态监督和预警机制。

10.8 每个文档本身就可以作为检查列表或者数据库。

10.9 项目经理的基本职责是使每个人都向着相同的方向前进。

10.10 项目经理的主要日常工作是沟通,而不是做出决定;文档使各项计划和决策在整个团队范围内得到交流。

10.11 只有一小部分管理人员的时间–可能只有20%–用来从自己头脑外部获取信息。

10.12 出于这个原因,广受吹捧的市场概念–支持管理人员的”完备信息管理系统”并不基于反映管理人员行为的有效模型。

第11章 未雨绸缪

11.1 化学工程师已经认识到无法一步将实验室工作台上的反应过程移到工厂中,需要一个实验性工厂(pilot planet)来为提高产量和在缺乏保护的环境下运作提供宝贵经验。

11.2 对于编程产品而言,这样的中间步骤是同样必要的,但是软件工程师在着手发布产品之前,却并不会常规地进行试验性系统的现场测试。[现在,这已经成为了一项普遍的实践,beta版本。它不同于有限功能的原型,alpha版本,后者同样是我所倡导的实践。]

11.3 对于大多数项目,第一个开发的系统并不合用。它可能太慢、太大,而且难以使用,或者三者兼而有之。

11.4 系统的丢弃和重新设计可以一步完成,也可以一块块地实现。这是个必须完成的步骤。

11.5 将开发的第一个系统–丢弃原型–发布给用户,可以获得时间,但是它的代价高昂–对于用户,使用极度痛苦;对于重新开发的人员,分散了精力;对于产品,影响了声誉,即使最好的再设计也难以挽回名声。

11.6 因此,为舍弃而计划,无论如何,你一定要这样做。

11.7 “开发人员交付的是用户满意程度,而不仅仅是实际的产品。”(Cosgrove)

11.8 用户的实际需要和用户感觉会随着程序的构建、测试和使用而变化。

11.9 软件产品易于掌握的特性和不可见性,导致了它的构建人员(特别容易)面临着永恒的需求变更。

11.10 目标上(和开发策略上)的一些正常变化无可避免,事先为它们做准备总比假设它们不会出现要好得多。

11.11 为变更计划软件产品的技术,特别是细致的模块接口文档–非常地广为人知,但并没有相同规模的实践。尽可能地使用表驱动技术同样是有所帮助的。[现在内存的成本和规模使这项技术越来越出众。]

11.12 高级语言的使用、编译时操作、通过引用的声明整合和自文档技术能减少变更引起的错误。

11.13 采用定义良好的数字化版本将变更量子(阶段)化。[当今的标准实践。] 为变更计划组织架构

11.14 程序员不愿意为设计书写文档的原因,不仅仅是由于惰性。更多的是源于设计人员的踌躇–要为自己尝试性的设计决策进行辩解。(Cosgrove)

11.15 为变更组建团队比为变更进行设计更加困难。

11.16 只要管理人员和技术人才的天赋允许,老板必须对他们的能力培养给予极大的关注,使管理人员和技术人才具有互换性;特别是希望能在技术和管理角色之间自由地分配人手的时候。

11.17 具有两条晋升线的高效组织机构,存在着一些社会性的障碍,人们必须警惕和积极地同它做持续的斗争。

11.18 很容易为不同的晋升线建立相互一致的薪水级别,但要同等威信的建立需要一些强烈的心理措施:相同的办公室、一样的支持和技术调动的优先补偿。

11.19 组建外科手术队伍式的软件开发团队是对上述问题所有方面的彻底冲击。对于灵活组织架构问题,这的确是一个长期行之有效的解决方案。 前进两步,后退一步–程序维护

11.20 程序维护基本上不同于硬件的维护;它主要由各种变更组成,如修复设计缺陷、新增功能、或者是使用环境或者配置变换引起的调整。

11.21 对于一个广泛使用的程序,其维护总成本通常是开发成本的40%或更多。

11.22 维护成本受用户数目的严重影响。用户越多,所发现的错误也越多。

11.23 Campbell指出了一个显示产品生命期中每月bug数的有趣曲线,它先是下降,然后攀升。

11.24 缺陷修复总会以(20-50)%的机率引入新的bug。

11.25 在每次修复之后,必须重新运行先前所有的测试用例,从而确保系统不会以更隐蔽的方式被破坏。

11.26 能消除、至少是能指明副作用的程序设计方法,对维护成本有很大的影响。

11.27 同样,设计实现的人员越少、接口越少,产生的错误也就越少。 前进一步,后退一步–系统熵随时间增加

11.28 Lehman和Belady发现模块数量随大型操作系统(OS/360)版本号的增加呈线性增长,但是受到影响的模块以版本号指数的级别增长。

11.29 所有修改都倾向于破坏系统的架构,增加了系统的混乱程度。即使是最熟练的软件维护工作,也只是放缓了系统退化到不可修复混乱的进程,从中必须要重新进行设计。 [许多程序升级的真正需要,如性能等,尤其会冲击它的内部结构边界。原有边界引发的不足常常在日后才会出现。

第12章 干将莫邪

12.1 项目经理应该制订一套策略,以及为通用工具的开发分配资源,与此同时,他还必须意识到专业工具的需求。

12.2 开发操作系统的队伍需要自己的目标机器,进行调试开发工作。相对于最快的速度而言,它更需要最大限度的内存,还需要安排一名系统程序员,以保证机器上的标准软件是即时更新和实时可用的。

12.3 同时还需要配备调试机器或者软件,以便在调试过程中,所有类型的程序参数可以被自动计数和测量。

12.4 目标机器的使用需求量是一种特殊曲线:刚开始使用率非常低,突然出现爆发性的增长,接着趋于平缓。

12.5 同天文工作者一样,系统调试总是大部分在夜间完成。

12.6 抛开理论不谈,一次分配给某个小组连续的目标时间块被证明是最好的安排方法,比不同小组的穿插使用更为有效。

12.7 尽管技术不断变化,这种采用时间块来安排匮乏计算机资源的方式仍得以延续20年[在1975年],是因为它的生产率最高。[在1995年依然如此]

12.8 如果目标机器是新产品,则需要一个目标机器的逻辑仿真装置。这样,可以更快地得到辅助调试平台。即使在真正机器出现之后,仿真装置仍可提供可靠的调试平台。

12.9 主程序库应该被划分成(1)一系列独立的私有开发库;(2)正处在系统测试下的系统集成子库;(3)发布版本。正式的分离和进度提供了控制。

12.10 在编制程序的项目中,节省最大工作量的工具可能是文本编辑系统。

12.11 系统文档中的巨大容量带来了新的不理解问题[例如,看看Unix],但是它比大多数未能详细描述编程系统特性的短小文章更加可取。

12.12 自顶向下、彻底地开发一个性能仿真装置。尽可能早地开始这项工作,仔细地听取 “它们表达的意见”。

12.13 只有懒散和惰性会妨碍高级语言和交互式编程的广泛应用。[如今它们已经在全世界使用。]

12.14 高级语言不仅仅提升了生产率,而且还改进了调试:bug更少,以及更容易寻找。

12.15 传统的反对意见–功能、目标代码的尺寸、目标代码的速度,随着语言和编译器技术的进步已不再成为问题。

12.16 现在可供合理选择的语言是PL/I。[不再正确。] 交互式编程

12.17 某些应用上,批处理系统决不会被交互式系统所替代。[依然成立。]

12.18 调试是系统编程中很慢和较困难的部分,而漫长的调试周转时间是调试的祸根。

12.19 有限的数据表明了系统软件开发中,交互式编程的生产率至少是原来的两倍。

第13章 整体部分

13.1 第4、5、6章所意味的煞费苦心、详尽体系结构工作不但使产品更加易于使用,而且使开发更容易进行以及bug更不容易产生。

13.2 V.A.Vyssotsky提出,”许许多多的失败完全源于那些产品未精确定义的地方。”

13.3 在编写任何代码之前,规格说明必须提交给测试小组,以详细地检查说明的完整性和明确性。开发人员自己不会完成这项工作。(Vyssotsky)

13.4 “十年内[1965~1975],Wirth的自顶向下进行设计[逐步细化]将会是最重要的新型形式化软件开发方法。”

13.5 Wirth主张在每个步骤中,尽可能使用级别较高的表达方法。

13.6 好的自顶向下设计从四个方面避免了bug。

13.7 有时必须回退,推翻顶层设计,重新开始。

13.8 结构化编程中,程序的控制结构仅由支配代码块(相对于任意的跳转)的给定集合所组成。这种方法出色地避免了bug,是一种正确的思考方式。

13.9 Gold结果显示了,在交互式调试过程中,第一次交互取得的工作进展是后续交互的三倍。这实际上获益于在调试开始之前仔细地调试计划。[我认为在1995年依然如此。]

13.10 我发现对良好终端系统的正确使用,往往要求每两小时的终端会话对应于两小时的桌面工作:1小时会话后的清理和文档工作;1小时为下一次计划变更和测试。

13.11 系统调试(相对于单元测试)花费的时间会比预料的更长。

13.12 系统调试的困难程度证明了需要一种完备系统化和可计划的方法。

13.13 系统调试仅仅应该在所有部件能够运作之后开始。(这既不同于为了查出接口bug所采取 “合在一起尝试” 的方法;也不同于在所有构件单元的bug已知,但未修复的情况下,即开始系统调试的做法。)[对于多个团队尤其如此。]

13.14 开发大量的辅助调试平台(scaffolding 脚手架)和测试代码是很值得的,代码量甚至可能会有测试对象的一半。

13.15 必须有人对变更进行控制和文档化,团队成员应使用开发库的各种受控拷贝来工作。

13.16 系统测试期间,一次只添加一个构件。

13.17 Lehman和Belady出示了证据,变更的阶段(量子)要么很大,间隔很宽;要么小和频繁。后者很容易变得不稳定。[Microsoft的一个团队使用了非常小的阶段(量子)。结果是每天晚上需要重新编译生成增长中的系统。]

第14章 祸起萧墙

14.1 “项目是怎样延迟了整整一年的时间?.一次一天。”

14.2 一天一天的进度落后比起重大灾难,更难以识别、更不容易防范和更加难以弥补。

14.3 根据一个严格的进度表来控制项目的第一个步骤是制订进度表,进度表由里程碑和日期组成。

14.4 里程碑必须是具体的、特定的、可度量的事件,能进行清晰能定义。

14.5 如果里程碑定义得非常明确,以致于无法自欺欺人时,程序员很少会就里程碑的进展弄虚作假。

14.6 对于大型开发项目中的估计行为,政府的承包商所做的研究显示:每两周进行仔细修订的活动时间估计,随着开始时间的临近不会有太大的变化;期间内对时间长短的过高估计,会随着活动的进行持续下降;过低估计直到计划的结束日期之前大约三周左右,才有所变化。

14.7 慢性进度偏离是士气杀手。[Microsoft的Jim McCarthy说:”如果你错过了一个最终期限(deadline),确保制订下一条deadline。2”>

14.8 进取对于杰出的软件开发团队,同优秀的棒球队伍一样,是不可缺少的必要品德。

14.9 不存在关键路径进度的替代品,使人们能够辨别计划偏移的情况。

14.10 PERT的准备工作是PERT图使用中最有价值的部分。它包括了整个网状结构的展开、任务之间依赖关系的识别、各个任务链的估计。这些都要求在项目早期进行非常专业的计划。

14.11 第一份PERT图总是很恐怖的,不过人们总是不断进行努力,运用才智制订下一份PERT图。

14.12 PERT图为前面那个泄气的借口,”其他的部分反正会落后”,提供了答案。

14.13 每个老板同时需要采取行动的异常信息以及用来进行分析和早期预警的状态数据。

14.14 状态的获取是困难的,因为下属经理有充分的理由不提供信息共享。

14.15 老板的不良反应肯定会对信息的完全公开造成压制;相反,仔细区分状态报告、毫无惊慌地接收报告、决不越俎代庖,将能鼓励诚实的汇报。

14.16 必须有评审的机制,从而所有成员可以通过它了解真正的状态。出于这个目的,里程碑的计划和完成文档是关键。

14.17 Vyssotsky:我发现在里程碑报告中很容易记录”计划(老板的日期)”和”估计(最基层经理的日期)”的日期。项目经理必须停止对这些日期的怀疑。”

14.18 对于大型项目,一个对里程碑报告进行维护的计划和控制(Plan and Control)小组是非常可贵的。

第15章 另外一面

15.1 对于软件编程产品来说,程序向用户所呈现的面貌与提供给机器识别的内容同样重要。

15.2 即使对于完全开发给自己使用的程序,描述性文字也是必须的,因为它们会被用户-作者所遗忘。

15.3 培训和管理人员基本上没有能向编程人员成功地灌输对待文档的积极态度–文档能在整个生命周期对克服懒惰和进度的压力起促进激励作用。

15.4 这样的失败并不都是因为缺乏热情或者说服力,而是没能正确地展示如何有效和经济地编制文档。

15.5 大多数文档只提供了很少的总结性内容。必须放慢脚步,稳妥地进行。

15.6 由于关键的用户文档包含了跟软件相关的基本决策,所以它的绝大部分需要在程序编制之前书写,它包括了9项内容(参见相应章节)。

15.7 每一份发布的程序拷贝应该包括一些测试用例,其中一部分用于校验输入数据,一部分用于边界输入数据,另一部分用于无效的输入数据。

15.8 对于必须修改程序的人而言,他们所需要程序内部结构文档,同样要求一份清晰明了的概述,它包括了5项内容(参见相应章节)。

15.9 流程图是被吹捧得最过分的一种程序文档。详细逐一记录的流程图是一件令人生厌的事情,而且高级语言的出现使它显得陈旧过时。(流程图是图形化的高级语言。)

15.10 如果这样,很少有程序需要一页纸以上的流程图。[在这一点上,MILSPEC军用标准实在错得很厉害。]

15.11 即使的确需要一张程序结构图,也并不需要遵照ANSI的流程图标准。

15.12 为了使文档易于维护,将它们合并至源程序是至关重要的,而不是作为独立文档进行保存。

15.13 最小化文档负担的3个关键思路: .. 借助那些必须存在的语句,如名称和声明等,来附加尽可能多的”文档”信息。 .. 使用空格和格式来表现从属和嵌套关系,提高程序的可读性。 .. 以段落注释,特别是模块标题的形式,向程序中插入必要的记叙性文字。

15.14 程序修改人员所使用的文档中,除了描述事情如何以外,还应阐述它为什么那样。对于加深理解,目的是非常关键的,但即使是高级语言的语法,也不能表达目的。

15.15 在线系统的高级语言(应该使用的工具)中,自文档化技术发现了它的绝佳应用和强大功能。

我一直不断地在表达一个观点–委派一名产品结构师是最重要的行动。结构师负责产品所有方面的概念完整性,这些是用户能实际感受到的。结构师开发用于向用户解释使用的产品概念模型,概念模型包括所有功能的详细说明以及调用和控制的方法。结构师是这些模型的所有者,同时也是用户的代理。在不可避免地对功能、性能、规模、成本和进度进行平衡时,卓有成效地体现用户的利益。这个角色是全职工作,只有在最小的团队中,才能和团队经理的角色合并。结构师就像电影的导演,而经理类似于制片人。

概念完整性是产品质量的核心。拥有一位结构师是迈向概念完整性的最重要一步。这个原理决不仅限于软件系统,它适用于所有的复杂事物,如计算机、飞机、防御系统、全球定位系统等。在软件工程试验室进行20次以上的讲授之后,我开始坚持每4个学生左右的小组就选择不同的经理和结构师。在如此小的队伍中定义截然不同的角色可能是有点极端,但我仍然发现这种方法即使对小型团队也运作良好,并且促使了设计的成功。

盲目的功能(Featuritis)。对于如电子表格或字处理等通用工具的结构师,一个不断困扰他们的诱惑是以性能甚至是可用性的代价,过多地向产品添加边界实用功能。 功能建议的吸引力在初期阶段是很明显的,性能代价在系统测试时才会出现。而随着功能一点一点地添加,手册慢慢地增厚,易用性损失以不易察觉的方式蔓延。

对幸存和发展了若干代的大众软件产品,这种诱惑特别强烈。数百万的用户需要成百上千的功能特色,任何需求本身就是一种”市场需要它”的证明。而常见的情况是,原有的系统结构师得到了嘉奖,正工作在其他岗位或项目上,现在负责体系结构的结构师,在均衡表达用户的整体利益方面,往往缺乏经验。一个对Microsoft Word 6.0的近期评价声称”Word 6.0对功能特性进行了打包,通过包缓慢地更新..Word 6.0同样是大型和慢速的。”有点令人沮丧的是–Word 6.0需要4MB内存,丰富的新增功能意味着”甚至Macintosh IIfx都不能胜任Word 6的任务”。

定义用户群。用户群越大和越不确定,就越有必要明确地定义用户群,以获得概念完整性。设计队伍中的每个成员对用户都有一幅假想的图像,并且每个设计者的图像都是不同的。结构师的用户图像会有意或者无意地影响每个结构决策,因此有必要使设计队伍共享一幅相同的用户图像。这需要把用户群的属性记录下来,包括: .. 他们是谁 .. 他们需要(need)什么 .. 他们认为自己需要(need)什么

对幸存和发展了若干代的大众软件产品,这种诱惑特别强烈。数百万的用户需要成百上千的功能特色,任何需求本身就是一种”市场需要它”的证明

频率。对于软件产品,任何用户群属性实际上都是一种概率分布,每个属性具有若干可能的值,每个值有自己的发生频率。结构师如何成功地得到这些发生频率?对并未清晰定义的对象进行调查是一种不确定和成本高昂的做法3。经过很多年,我现在确信,为了得到完整、明确和共有的用户群描述,结构师应该猜测(guess),或者假设(postulate)完整的一系列属性和频率值。 这种不是很可靠的过程有很多好处。首先,仔细猜测频率的过程会使结构师非常细致地考虑对象用户群。其次,把它们写下来一般会引发讨论,这能起到解释的作用,以及澄清不同设计人员对用户图像认识上的差异。另外,明确地列举频率能帮助大家认识到哪些决策依赖于哪些用户群属性。这种非正式的敏感性分析也是颇有价值的。当某些非常重要的决策需要取决于一些特殊的猜测时,很值得为那些数值花费精力来取得更好的估计。

开发第二个系统所引起的后果:盲目的功能和频率猜测

总结:为用户群的属性明确地记载各种猜测。清晰和错误都比模糊不清好得多。

Mac界面在另一个方面很值得注意。没有任何强迫,它的设计人员在所有的应用程序中使用标准界面,包括了大量的第三方程序。从而,用户在界面上获得的概念一致性不仅仅局限在机器所配备的软件,而且遍及所有的应用程序。

这些获取一致性的措施得到了足够广泛的应用,以致于可以形成实际的标准。

他的结果充分地吻合了《人月神话》的结论,即人力(人)和时间(月)之间的平衡远不是线性关系,使用人月作为生产率的衡量标准实际是一个神话。

人就是一切(或者说,几乎是一切)

更基本的是,这来自一个信念,即对于项目的成功而言,项目人员的素质、人员的组织管理是比使用的工具或采用的技术方法更重要的因素。

Boehm的COCOMO模型发现团队质量目前是项目成功最大的决定因素,实际上是下一个次重要因素的4倍。

我也非常鼓励对软件管理动态特征–对人的关注、激励、培养–的持续研究。

人件。近年来,软件工程领域的一个重大贡献是DeMarco和Lister在1987年出版的数据,《人件:高生产率的项目和团队》

它所表达的观点是”我们行业的主要问题实质上更侧重于社会学(sociological)而不是科学技术(technological)

“管理人员的职责不是要人们去工作,而是是创造工作的可能。”它涉及了如空间、布置、团队的餐饮等主题。DeMarco和Lister从他们的Coding War Games项目中提供的数据,显示了相同组织中开发人员的表现之间,和工作空间和生产率以及缺陷水平之间令人吃惊的关联。 顶尖人员的空间更加安静、更加私人、保护得更好以免受打断,还有很多..这对你真的很要紧吗..是否安静、空间和免受打搅能够帮助你的人员更好地完成工作,或者[换个角度]能帮助你吸引和留住更好的人员? 我衷心地向我的读者推荐这本书。

项目转移。DeMarco和Lister对团队融合给予了相当大的关注,团队融合是一个无形的,但是非常关键的特性。很多地点分散的公司,项目从一个实验室转移到另一个。从中,我认为团队融合正是管理上被忽视的因素。 我的观察和经验大约局限在六、七个项目转移中,其中没有一个是成功的。任务可以成功地转移,但是对于项目的转移,即使拥有良好的文档、先进的设计以及保留部分原有人员,新队伍实际上依然是重新开始。我认为正是由于破坏了原有团队的整体性,导致了产品雏形的夭折,项目重新开始。 放弃权力的力量 如果人们认同我在文中多处提到的观点–创造力来自于个人,而不是组织架构或者开发过程,那么项目管理面对的中心问题是如何设计架构和流程,来提高而不是压制主动性和创造力。

微软的Jim AcCarthy向我描述了他在解放团队上的经验: 每个队伍(30至40人)拥有自己的任务、进度,甚至如何定义、构建、发布的过程。团队由4或5个专家组成,包括开发、测试和书写文档等。由团队而不是老板对争论进行仲裁。我无法形容授权和由团队自行负责项目的成功与否的重要性。

Earl Wheeler,IBM软件业务的退休主管,告诉我他着手下放IBM部门长期集权管理权力的经验: [近年来]关键的措施是将权力向下委派。这就像是魔术!改进的质量、提高的生产率、高涨的士气。我们的小型团队,没有中心控制。团队是流程的所有者,并且必须拥有一个流程。他们有不同的流程。他们是进度计划的所有者,因此感受到市场的压力。这种压力导致他们使用和利用自己的工具。

授权是朝着正确方向迈出的一大步,它产生了像Pius XI所预言的好处:通过权力委派,中心的权威实际上是得到了加强;从整体而言,组织机构实际上更加融洽和繁荣。

软件工程的焦油坑在将来很长一段时间内会继续地使人们举步维艰,无法自拔。软件系统可能是人类创造中最错综复杂的事物,只能期待人们在力所能及的或者刚刚超越力所能及的范围内进行探索和尝试。这个复杂的行业需要:

  • 进行持续的发展;

  • 学习使用更大的要素来开发;

  • 新工具的最佳使用;

  • 经论证的管理方法的最佳应用;

  • 良好判断的自由发挥;

  • 以及能够使我们认识到自己不足和容易犯错的–上帝所赐予的谦卑。

文档信息