人月神话心得

人月神话心得

《人月神话》这本书是我大学图书馆借的最后一本书了,是一本it项目管理的书。一直想看,但一拖再拖,其实书不厚。我看的都是40周年纪念版,也是两三天看完了,所以也记一些读书心得吧。

这一本书的一些观念在40年后的今天,使我还是有一点收获的。我读这本书其实很多地方是没有看懂的,但一些观点还是很大地启发了我。特别是《没有银弹》的这一章,更是对以前的一些编程疑惑有了一些答案,明白了人工智能等方向对编程届的影响不是第一次了,即使AI不如今天的这么热。

其实这本书的一个主要观点是一个程序的完成是由 人员(单位为人) 和 时间(单位为月)两个坐标完成的,但这两个坐标不是毫无关系的。

例如一个程序由一个人完成需要12个月,但不代表12个人同时进行1个月可以完成。

心得主要结合书后面18章的观点: 是与非 来写一下

01 焦油坑

  1. 过去几十年的大型系统开发就犹如一个焦油坑,很多大型动物在其中剧烈挣扎,他们中大多数开发出了可运行的系统–不过,其中只有非常少数的项目满足了目标、时间进度和预算的要求。

    各种团队,大型的和小型的,庞杂的和精干的,一个接一个淹没在了焦油坑中。表面上看起来好像没有任何一个单独的问题会导致困难,每个都能被解决,但是当它们相互纠缠和累积在一起的时候,团队的行动就会变得越来越慢且很难看清问题的本质。

  2. 编程行业带来的乐趣:

    • 创造事物的快乐
    • 面对不重复的任务,终身学习的快乐
    • 工作完全是思想的运动,不需要劳力运动
  3. 编程行业带来的苦恼:

    • 追求完美是编程最大的困难
    • 由他人设定目标,依靠自己来完成,并会有一些枯燥艰苦的劳动
    • 项目进度管理太难

02 人月神话

  1. 缺乏合理的时间进度是造成项目滞后的最主要原因,它比其他所有因素加起来影响还大。同时,一些任务是单进程的,就像烹饪煮菜,无法加速。

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

  1. 向软件项目中增派人手从三个方面增加了项目必要的总体工作量:

    • 任务重新分配本身和所造成的工作中断;
    • 培训新人员;
    • 额外的相互沟通。
  2. 关于进度安排,我的经验是为1/3计划、1/6编码、1/4构件测试以及1/4系统测试。

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

特别需要指出的是,不为系统测试安排足够的时间简直就是一场灾难。

在现实情况中,一旦开发团队观察到进度的偏差,总是倾向于对任务进行削减。当项目延期所导致的后续成本非常高时,这常常是唯一可行的方法。

03 外科手术队伍

同样是两年的工作经验下,优秀的程序员效率是较差的程序员10倍。

小型、精干队伍是最好的–思绪尽可能的少,少一点争执。

需要协作沟通的人员的数量影响着开发成本,因为成本的主要组成部分是相互的沟通和交流,以及更正沟通不当所引起的不良结果(系统调试)。

Mills建议大型项目的每一个部分由一个团队解决,但是该队伍以类似外科手术的方式组建,而并非一拥而上。

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

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

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

为了反映一系列连贯的设计思路,宁可省略一些不规则的特性和改进,也不提倡独立和无法整合的系统,哪怕它们其实包含着许多很好的设计。

同时,对于项目,体系结构的工作与具体实现相分离可以获得概念完整性;软件实现和硬件实现等可以并行。

同工作的水平分割相比,垂直划分从根本上大大减少了劳动量,结果是使交流彻底地简化,概念完整性得到大幅提高。

05 画蛇添足

一种普遍倾向是过分地设计第二个系统,向系统添加很多修饰功能和想法,它们曾在第一个系统中被小心谨慎地推迟了。

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

面对估算过高的难题,结构师有两个选择:削减设计或者建议成本更低的实现方法–挑战估算的结果

同时体现在软件编程不需要过早优化,先把大体功能实现了再去想旁枝末节的小功能

06 贯彻执行

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

允许体系结构师对实现人员的询问做出电话应答解释是非常重要的,并且必须进行日志记录和整理发布。

对于存有疑问的实现人员,应鼓励他们打电话询问相应的结构师,而不是一边自行猜测一边工作,这是一项很基本的措施。

07 为什么巴比伦塔会失败?

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

“因为左手不知道右手在做什么,从而进度灾难、功能的不合理和系统缺陷纷纷出现。

随着工作的进行,许多小组慢慢地修改自己程序的功能、规模和速度,他们明确或者隐含地更改了一些有效输入和输出结果用法上的约定,而因此给其他部分引发了BUG。

解决方案:
团队应该以尽可能多的方式进行相互之间的交流:非正式、常规项目会议,会上进行简要的技术陈述、共享的正式项目工作手册。举行常规项目会议,会议中,团队一个接一个地进行简要的技术陈述。这种方式非常有用,能澄清成百上千的细小误解。

制定项目工作手册,并实时记录变更:首先,必须在页面上标记发生改变的文本,例如,使用页边上的竖线标记每行变化的文字。第二,分发的变更页附带独立的总结性文字,对变更的重要性以及批注进行记录。

08 胸有成竹

编码大约只占了项目时间的六分之一左右,编码估计或者比率的错误可能会导致不合理的荒谬结果。

对常用编程语句而言。生产率似乎是固定的。这个固定的生产率包括了编程中需要注释,并可能存在错误的情况.

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

09 削足适履

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

为了满足目标,每个人都在局部优化自己的程序,很少会有人停下来,考虑一下对客户的整体影响。

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

10 提纲挈领

如果要制造一台机器,哪些是关键的文档呢?

目标:定义待满足的目标和需要,定义迫切需要的资源、约束和优先级。

首先,书面记录决策是必要的。只有记录下来,分歧才会明朗,矛盾才会突出。项目经理常常会不断发现,许多理应被普遍认同的策略,完全不为团队的一些成员所知。每个文档本身就可以作为检查列表或者数据库。

项目经理的基本职责是使每个人都向着相同的方向前进。项目经理的主要日常工作是沟通,而不是做出决定;文档使各项计划和决策在整个团队范围内得到交流。

通过周期性的回顾,他能清楚项目所处的状态,以及哪些需要重点进行更改和调整。

11未雨绸缪

  1. 变更的客观需要

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

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

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

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

  1. 为变更计划组织结构

当系统发生变化时,管理结构也需要进行调整。只要管理人员和技术人才的天赋允许,老板必须对他们的能力培养给予极大的关注,使管理人员和技术人才具有互换性。

为什么缺陷不能更彻底地被修复?

首先,看上去很轻微的错误,似乎仅仅是局部操作上的失败,实际上却是系统级别的问题,通常这不是很明显。

设计实现的人员越少、接口越少,产生的错误也就越少。

所有修改都倾向于破坏系统的架构,增加了系统的混乱程度。用在修复原有设计上瑕疵的工作量越来越少,而早期维护活动本身的漏洞所引起修复工作越来越多。

随着时间的推移,系统变得越来越无序,修复工作迟早会失去根基 ,尽管理论上系统一直可用,但实际上,整个系统已经面目全非,无法再成为下一步进展的基础。

机器在变化,配置在变化,用户的需求在变化,所以现实系统不可能永远可用。崭新的、对于原有系统的重新设计是完全必要的。

12 干将莫邪

每个编程人员也保留着编辑器、排序、内存信息转储、磁盘实用程序等工具。 这种方法对软件项目来说是愚蠢的。首先,项目的关键问题是沟通,个性化的工具妨碍–而不是促进沟通。

节省最大工作量的工具可能是文件编辑器。

主程序库应该被划分为: 1)一系列独立的私有开发库;2)正在系统测试下的系统集成子库;3)发布版本

13 整体部分

许许多多的失败完全源于那些产品未精确定义的地方。

细致的功能定义、详细的规格说明、规范化的功能描述说明以及这些方法的实施,大大减少了系统中必须查找的bug数量。

* 注: 需求文档越详细,bug越少*

在编写任何代码之前,规格说明必须提交给测试小组,以详细地检查说明的完整性和明确性 注: 需求文档给测试过一遍

将程序开发划分成体系结构设计、设计实现和物理编码实现,每个步骤可以使用自顶向下的方法很好地实现。

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

首先,清晰的结构和表达方式更容易对需求和模块功能进行精确的描述。

其次,模块分割和模块独立性避免了系统级的bug。

另外,细节的隐藏使结构上的缺陷更加容易识别。

最后,设计在每个精化步骤的层次上是可以测试的,所以测试可以尽早开始,并且每个步骤的重点可以放在合适的级别上。

一些糟糕的系统往往就是试图挽救一个基础很差的设计,而对它添加了很多表面装饰般的补丁。自顶向下的方法减少了这样的企图。

14 祸起萧墙

当人们听到某个项目的进度发生了灾难性偏离时,可能会认为项目一定是遭受了一系列重大灾难。然而,通常灾祸来自白蚁的肆虐,而不是龙卷风的侵袭。

严格控制项目进度第一个步骤是制定进度表,进度表有由里程碑和日期组成。

  1. 里程碑

里程碑的选择只有一个原则:里程碑必须是具体的、特定的、可度量的事件,能够进行清晰定义。

例如:”结构师和实现人员签字认可的规格说明”,”100%源代码编制完成,纸带打孔完成并输入到磁盘库”,”测试通过了所有的测试用例”。

如果里程碑很模糊,老板就常常会得到一份与实际情况不符的报告。

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

如果在某项活动开始之前就着手估计,并且每两周进行一次仔细的修订,根据实际情况动态调整时间。当里程碑没有正确反映损失的时间,并对人们形成误导,以致事态无法挽回的时候,它会彻底碾碎小组的士气。

  1. 保持进度透明可见

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

有两种掀开毯子把污垢展现在老板面前的方法,它们必须都被采用。

一种是减少角色冲突和鼓励状态共享

减少角色的冲突。老板必须规范自己,不对项目经理可以解决的问题做出反应。当项目经理了解到老板收到项目报告之后不会惊慌,或者不会越俎代庖时,他就逐渐会提交真实的评估结果。

另一种是猛地拉开地毯。

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

15 网开一面

文档可以在客户<->程序;程序用户<->作者;开发进度<->懒惰中起很好的作用;文档最好可以结合程序实时更新,例如doxygen;

文档注重于what多于how;

16 没有银弹:软件工程中的根本和次要问题

软件开发中困难的部分在于规格化,设计和测试这些概念上的结构,而不是对概念惊醒表达和对实现逼真程度进行验证。语言的语法错误在这些困难面前显得微不足道。

  1. 所以,没有任何技术或管理上的进展,能够独立地许诺十年内使生产率、可靠性或简洁性获得数量级上的进步。因为软件有无法规避的特性:复杂度、一致性、可变性、不可见性。

    • 产品复杂度:
      由于复杂度,团队成员之间的沟通非常困难,导致了产品瑕疵、成本超支和进度延迟;

    由于复杂度,列举和理解所有可能的状态十分困难,影响了产品的可靠性;

    由于函数的复杂度,函数调用变得困难,导致程序难以使用;

    由于结构性复杂度,程序难以在不产生副作用的情况下用新函数扩充;由于结构性复杂度,造成很多安全机制状态上的不可见性。

    复杂度不仅仅导致技术上的困难,还引发了很多管理上的问题。它使全面理解问题变得困难,从而妨碍了概念上的完整性;它使所有离散出口难以寻找和控制;它引起了大量学习和理解上的负担,使开发慢慢演变成了一场灾难。

    • 一致性
      程序接口,函数命名,程序兼容性等一致性也是一个比较大的问题。软件工程师面对变化,接口随着需求的不同而而变化,时间而变化,很难保持一致性。

    • 软件可变性:
      软件实体经常会遭受到持续的变更压力

    现实工作中,经常发生两种情况。

    当人们发现软件很有用时,会在原有应用范围的边界,或者在超越边界的情况下使用软件。功能扩展的压力主要来自那些喜欢基本功能,又对软件提出了很多新用法的用户们。

    其次,软件一定是在某种计算机硬件平台上开发,成功软件的生命期通常比当初的计算机硬件平台要长。即使不是更换计算机,则有可能是换新型号的磁盘、显示器或者打印机。软件必须与各种新生事物保持一致。

    • 软件不可见性
      软件是不可见的和无法可视化的。 其中的秘密就是逐步发育成长,而不是一次性搭建。

软件开发是一件棘手的事情,并不会有魔术般的解决方案,现在是从业者研究和分析革命性进展的时刻,而不是等待或希望它的出现。

  1. 解决一些次要的问题
    现在有一些手段可能可以在软件生产率上取得逐步的进展,而不是等待不可能到来的大突破。

    • 高级语言
      高级语言可以提升开发生产率5倍,比机器语言提供更好的抽象。
      但有时候高级语言的の一些复杂深奥的元素也带来脑力运动的负担。

    • 分时
      指的是机器运行速度,带来开发环境的提升。

  2. 银弹的希望
    实际也是解决次要的问题

    • Ada和其他高级编程语言

    作用也类似高级语言

    • 面向对象编程O-O
      抽象数据类型(类class)和层次化的设计只是解决高级别的次要困难,无法改变软件的复杂度问题。
    • 人工智能
      人工智能分为两种,弱人工智能和强人工智能。前者只是解决以前通过人类智慧的问题;后者是启发式,类似无监督学习机器学习的技术,也即专家系统。

    专家系统的能力来自于大数据,不是前所未有的推断机制。但专家系统最强有力的贡献是给缺乏经验的开发人员提供服务,使用的是最优秀的开发者的经验。

    • 自动编程
      系统的复杂性使得自动编程很难普及和推广。

    • 图形化编程
      流程图本身是一个非常差劲的软件结构表示方法,但软件本身也是难以可视化的。

    • 程序验证
      程序验证指的是在系统设计阶段和源代码阶段消除bug。和软件测试相比,也需要投入大量的精力。

    • 环境和工具,工作站
      提供一定的效率提高,但肯定是有限的

  3. 针对概念根本问题的较好方法
    次要的技术工作都可以归为下面公式:
    任务时间 = 使用技术频率 * 时间
    但解决一些概念问题还是可以通过:

    • 购买更好的工具,而非自己造轮子
    • 更精炼的需求和快速原型

    • 增量开发——增长,而非搭建系统

      • 应该使用增量开发,指的是系统应该能够运行,即使还没完成所有的功能。然后系统一点一点被充实,子系统再开发。
    • 卓越的设计人员

      • 尽可能早地识别优秀的设计人员
      • 为设计人员指派一位职业导师,负责他们的技术成长
      • 为各方面制定和维护一份职业计划
      • 为成长中的设计人员提供互相交流和激励的机会

结语

第一次读完就到这里了,好多都是在地铁上读的,以后多看看复一下盘吧。

你可能感兴趣的:(程序人生)