《人月神话》精华笔记整合“字字珠玑”值得收藏

《人月神话》精华笔记整合“字字珠玑”值得收藏

2290发表于2017-05-14

编程为什么有趣?作为回报,它的从业者期望得到什么样的快乐?
首先是一种创建事物的纯粹快乐。如同小孩在玩泥巴时感到愉快一样,成年人喜欢创建事物,特别是自己进行设计。我想这种快乐是上帝创造世界的折射,一种呈现在每片独特、崭新的树叶和雪花上的喜悦。


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


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


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


最后,乐趣还来自于工作在如此易于驾驭的介质上。程序员,就像诗人一样,几乎仅仅工作在单纯的思考中。程序员凭空地运用自己的想象,来建造自己的“城堡”。很少有这样的介质——创造的方式如此得灵活,如此得易于精炼和重建,如此得容易实现概念上的设想。(不过我们将会看到,容易驾驭的特性也有它自己的问题)


卡内基-梅隆大学的D.L.Parnas提出了更彻底的解决方法1。

他认为,编程人员仅了解自己负责的部分,而不是整个系统的开发细节时,工作效率最高。


这个观点不知道是不是正确的,我个人的看法和他是有些相同的。如果编程人员仅仅了解自己负责的部分,那么他就不会分散精力去想一些别的东西,只会努力把要做的做到最好。
这个方法也可能会有缺点,比如说如果分配任务的时候对于每个具体的编程人员的具体任务的划分不明确,产生歧义,那么编程人员在不了解整体的情况下只会把这个部分按照他理解的去做好,而不会去想我为什么要做这些,做这些是有什么用的。发现错误的概率会降低。这个问题存在的假设是设计模块分配任务的那个人做得不够好。
所以,如果能够确保分配任务的做得足够好,那么这种方式是有它的可取之处的。

软件的复杂度是必要属性,不是次要因素。

对于非常大型的项目,将设计方法、体系结构方面的工作与具体实现相分离是获得概念完整性的强有力方法。
设计方法、体系结构这些东西,应该是统一比高效更重要的。
如果不统一,即使那个部分设计得比较高效,也是没有意义的,会出现矛盾。
由此也能看出,设计方法、体系结构可能是由一个人活着默契非常好的少数几个人完成比较好,而不是大家共同商议。
对于软件任务的进度安排,以下是我使用了很多年的经验法则: 

1/3计划 

1/6编码 

1/4构件测试和早期系统测试 

1/4系统测试,所有的构件已完成

原来测试竟然能够占到进度安排的一半,哇!
以前自己做程序的时候,甚至都不进行测试,只有给定条件输出结果正确就可以了。
跟实际情况相对比,才知道自己的不足究竟有多么严重!在许多重要的方面,它与传统的进度安排方法不同:
1. 分配给计划的时间比寻常的多。即便如此,仍不足以产生详细和稳定的计划规格说明,也不足以容纳对全新技术的研究和摸索。
2. 对所完成代码的调试和测试,投入近一半的时间,比平常的安排多很多。
3. 容易估计的部分,即编码,仅仅分配了六分之一的时间。


第二个谬误的思考方式是在估计和进度安排中使用的工作量单位:人月。
以及
因此我认为用人月作为衡量一项工作的规模是一个危险和带有欺骗性的神话。它暗示着人员数量和时间是可以相互替换的。
这个问题之前真的没有详细地思考过,人数的增加并不一定能够加快开发速度。
==============

所以系统编程的进度安排背后的第一个假设是:一切都将运作良好,每一项任务仅花费它所“应该”花费的时间。
这个确实是的,我在计划东西的时候也一般是用乐观的态度去假设所有的事情都会正常地进行,不会有什么事情在预料之外占用额外的时间。但是之前一直都没有注意过这点

在众多软件项目中,缺乏合理的进度安排是造成项目滞后的最主要原因,它比其他所有因素加起来的影响还要大。
向进度落后的项目增加人手,只会使进度更加落后。
在此之前我还一直没有认识到合理的时间进度对于一个软件项目是如此的重要

如果一个项目多余一个人(程序员),那么他们一定不能是对等的关系,至少在设计大体结构的时候不是。
然而并不是说那个主刀的有更多牛逼,而是每个人需要达成共识,把充满创造性的精力放在不同的地方(大局和细节实现)。这就是为什么总说协作最难。
  
  
goto语句,存在即有它的道理。
特别是在多次连续的错误判断和处理时,goto语句可以使结构变清晰和简洁


“功欲善其事,必先利其器也”
现在在编程过程中如果需要工具,大家基本上会先搜索有无开源的。


独立的测试小给当然有存在的必要。
对于实现人员来说单元测试也是必需要作的,你的代码必须是可测试和被测试的且最好是完全地自动化测试,当然不一定要走TDD那一套。


我主张在系统设计中,概念完整性应该是最重要的考虑因素。
也就是说为了反映一系列连贯的设计思路,宁可省略一些不规则的特性和改进,也不提倡独立和无法整合的系统,哪怕它们其实包含着许多很好的设计
完美主义者 + 个人主义者 + 一点强迫症


协作沟通的成本,不能忽视,它在很大程序上决定了项目的进展,质量和最终的成败。同时协作人员的数量和质量也影响着沟通的成本。
结论:程序员在工作上也需要很好的情商。


?里程碑还是沉重的负担
里程碑的选择只有一个原则,那就是必须要是具体的,特定的,可度量的事件,能够清晰定义。
里程碑的边界和明显没有歧义,比他容易被老板核实更为重要。

定义里程碑是一项很关键的任务,在里程碑的选取上也需要十分讲究技巧,不是选择容易被核实的里程碑,而是选择容易被定义被理解被程序员接受的里程碑,容易被老板核实的里程碑未必是边界清晰的,迷糊的边界会造成进度的误报,有可能实际情况是无法被老板核实的。这也是项目进度会落后的原因之一。实际上,在商业项目的开发中,如果不是因为兴趣而聚集到一起的人进行的开发很有可能是无法完全准确地汇报当前的进程的。这点不管怎样都是很难解决的问题,除非你能保证每一个组员都对于这项任务又无可比拟的热情或是有共同的利益目标。
第二就是在里程碑的设置上,讲求的应该是一个短期快速实现,不断迭代估计设置的方法。我觉得里程碑不应该只在项目的开始时候设置一次,或者说,项目的每个阶段,甚至是每周都要明确里程碑,这实际上也是对于项目进度的一个控制,但是不宜设置过于频繁,过于频繁地设置会带来心理上的压力。

?“其他的部分反正会落后”
并不是每一天的滞后都是灾难
随着项目的推进,PERT图为前面那个泄气的借口,“其他部分反正会落后”提供了答案。它展示了某人为了使自己的工作远离关键路径,需要超前多少,也建议了补偿其他部分失去时间的方法。

评价一个人的工作是不是滞后了,是不是会影响到项目整体的进度,不是单凭一个人某一天的计划完成的状况而制定的,而是根据项目的关键路径来进行判断的,根据这一个观点,可以找到项目滞后的原因,也可以找到着力点来进一步提高项目在下一阶段的生产效率。
第一份PERT图通常是很恐怖的

我们永远无法完美的制定计划?注意,永远无法?实际上无论计划的怎么好最后都会出现意料之外的变迁。后面调整的PERT图可能会更加适应本团队在该项目上的计划进度之类,可作为进度规划辅助参考工具之一。

?地毯的下面
有两种掀开毯子把污垢展现在老板面前的方法,它们都必须被采用。一种是减少角色冲突和鼓励状态共享,另一种是猛地拉开地毯。

在一个大型项目中,拥有一个计划控制小组是很有必要的,该小组首先是对于项目进度有一个控制,其次是对于未完成的部分进行一个计划。这点很像风险评估,一个项目组中,这样的小组存在是很有意义和必要的,尤其是大型的项目种,所有的计划评估均有项目经理来完成的话显然是不妥的。并且使用有经验的人来进行这一职务的担当更为有利。


?为什么要有正式的文档
首先,书面记录决策是很有必要的。只有记录下来,分歧才会明朗,矛盾才会突出。
第二,文档能够作为同其他人的沟通渠道。
最后,项目经理的文档还可以作为数据基础和检查列表。

这章的内容相当少也相当简单,主要阐述的就是文档的重要性,就和章节标题所显示的那样﹣提纲挈领,其实这就是文档主要的工作。
一开始的时候我们其实都会很疑惑文档到底是用来做什么的,甚至在很长的一段时间里面,大家都是糊差事,糊弄完文档了事,认为文档是一个十分无关紧要的鸡肋,实际上并非如此,我们认为其无关紧要,甚至很多时候都是弄完代码之后再进行文档的补足,表面上看起来可以交出比价理想的差事,实际上是因为我们所参与的项目规模十分十分的小(可以用微型来解释么(<_<))。
在大型,其实是比较正式的一个项目中,我们要写的文档其实是十分必要而且作用也是十分重要的,规定了软件大致的骨架,其实也是团队内部同志们之间进行交流的一项较为有利的依据。
最近的敏捷也好,极限也好,有同志们简单的觉得是不需要写文档的,代码即文档。我觉得不妥,除非队员之间默契度十分的高,或者是项目各项需求及边界规范的十分明确,大家不会有任何歧义,否则文档就是必要的,哪怕是只言片语…又或者是,除非代码风格十分优秀,可以保证注释的质量相当的高,另当别论。


在开发第一个系统时,结构师倾向于精炼和简洁。他知道自己对正在进行的任务不够了解,所以他会仔细谨慎地工作。
一种普遍倾向是过分的设计第二个系统,向系统添加很多的修饰功能和想法,他们曾在第一个系统中被小心翼翼地放在次要位置。

中国人讲的"艺高人胆大","擅泳者溺"大概有一点点这样的意味,一开始的时候往往小心谨慎,通常是人之常情,这会是第一个项目无论是在项目周期上还是项目具体实现上均大致符合预期发展,不会带来较大的出入的原因,在第二个项目的设计上,往往就会出现“因为有经验了,所以觉得可以根据第一次成功的背景将一些次要方案加入设计的想法。”往往会失败,不仅仅是作项目,很多事情都会是这样(难道这也有心理学的解释么哟喂…)。
所以解决这个问题的关键?如果是搭配两个结构师进行设计(一个老鸟一个新手),那么风险是降低了,但是新手一旦进行独立的真正意义上的第二个项目时间是不可避免还是会遇到同样的问题,因此项目经理或是负责人员分配的高管必须尤其注意这个问题,或者让这种第二次设计放在一个所需承担风险较小的项目中?减少因项目失败而带来的损失。或是系统评估人员需要首先对于设计出的系统方案进行评估,每一次的改进或是功能的设计划分都需要进行自习的后果评估和风险评估后才能进行实施?


首先,苦恼来自追求完美。

其次,苦恼来自他人来设定目标、供给资源和提供信息。

最后一个苦恼,有时也是一种无奈——当投入了大量辛苦的劳动,产品在即将完成或者终于完成的时候,却已显得陈旧过时。

要想成功,结构师必须
1.牢记是开发人员承担创造性和发明性的实现责任,所以结构师只能建议,而不能支配;
2.时刻准备着为所指定的说明建议一种实现的方法,同样准备接受其它任何能达到目标的方法
3.对上述的建议保持低调和不公开
4.准备放弃坚持 所作的改进建议


项目经理的基本职责是使每个人都向着相同的方向前进,所以他的主要工作是沟通,而不是作出决定。

项目经理的任务是制定计划,并实现计划。

这不仅是项目经理的任务,也是每个人实现自己人生理想所必需的任务,不过通常制定的计划不太现实,偏离实际,或者计划的顺序步骤等衔接有问题。至于实现计划,更是困难重重,也许是没有了坚持下去的意志,或者是遇到的问题太多太复杂,超出了自己的能力。在这方面,也许项目经理对任务的管理、控制和实行等可以给我们不少参考。

只有书面计划是精确和可以沟通的。 ...... 通过遵循文档开展工作,项目经理能够更清晰和快速的设定自己的方向。


“我们对估算技术缺乏有效的研究,更加严肃的说,它反映了一种悄无声息,但并不真实的假设----一切都将运作良好”。
有哪个程序员能够准确的估算出自己任务所花费的时间?
对于整个系统而言,细微的修改都可能导致极大的变动,进而带进许多隐晦的bug。
能够准确判断出自己的修改所造成影响的程序员,对于整个系统必定是非常地了解。
但是在现在团队合作开发的背景下,还有谁能够了解整个系统吗?

项目进度为何总是估算失败,作者从以下几个方面进行了论述:
1.程序员的乐观主义
所有的程序员都是乐观主义?我怎么感觉不太像呢,不是还有个词叫“码农”的嘛......自从团队合作开始之后,就必须有程序员去从事一些无关紧要、琐碎的事情,他们已经感觉不到创造新事物的快乐,只有日复一日的重复劳动。
2.对人月的错误观念

增加人手不能提高工作的效率?估计这会让很多项目经理感到吃惊。“软件开发本质上是一项系统工作----错综复杂关系下的一种实践,沟通、交流的工作量非常大”。

增加人手所带来的沟通成本远高于所增加的劳动力,同样,员工的流动对项目的工作也有极大的影响,没有人能够把自己的所知完整的传递下去。

3.系统测试的滞后
为什么测试的时候才发现那么多问题呢?是开发人员太平庸,还是系统太过复杂?如果由开发人员自己做测试而取消测试人员,能否解决这个问题呢?
4.估算缺乏依据
估算能有切实的依据吗?也许功能都开发得差不多了,但是谁能说测试不会发现新的问题而导致大的修改呢?
 
 
概念完整性是产品质量的核心。对于效率和概念的完整性来说,最好由少数干练的人员来设计和开发,而对于大型系统,则需要大量的人手,以使产品能在时间上满足要求。

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

解决方案不是一蹴而就,原型迭代

然而大型的编程工作,或多或少包含了很多任务,某些任务间还具有前后的次序,从而一切正常的概率变得非常小,甚至接近于无。由此可见我们的乐观是多么盲目的呀

显然,对于存有疑问的实现人员,应鼓励他们打电话询问相应的结构师,而不是一边自行猜测一边工作,这是一项很基本的措施。
如果带着猜疑做工作,一方面由于存在猜疑,效率可能不高。另一方面如果实现人员的猜测是错误的,那么他们的工作可能就浪费了,这样既浪费时间也打击人的热情。
所以有不清楚的地方,哪怕会被看做能力低,也一定要问清楚的,因为这样一来,至少工作中能少出很多意外。

在堆积如山的文件资料中,少数文件是关键枢纽,每一件项目管理的工作都围绕着他们运转。这些文档是项目经理最重要的个人工具。


系统应该保持多大的规模才是合适的呢?在系统编程中,项目经理必须对系统的规模进行控制,可以从以下几个方面进行:

1.不能仅对核心程序设置规模目标,所有方面的规模都要编入预算。

2.在指明模块大小的同时,确切定义模块的功能。

3.加强对开发人员管理和沟通,培养他们从系统整体出发,面向用户的态度。

4.提高开发人员的空间编程技能,对这方面的技术进行积累。

5.数据的表现形式是编程的根本,系统编程应该从数据出发,寻求更优越的算法,对数据或者表进行重新表达。


1.“人类历史是一个舞台,总是上演着相同的故事”。

2.作者依然确信,概念完整性是产品质量的核心。因此需要一名负责产品所有方面的概念完整性的结构师,并且将体系结构和设计实现、物理实现相分离。

3.第二个系统?呃,没怎么注意过,不过作者说得挺有道理的,第一个成功的系统总会带来臃肿的第二个系统。和《神秘的程序员们》的第20个漫画很类似。

4.在我看来,图形界面已经成功的取代了字符界面。不过是在Windows下,还是Linux下,图形界面的操作都是相似,为两个系统间转移减少了很多代价。

5.“应该一块块地丢弃和重新设计系统,而不是一次性地完成替换”。作者认为瀑布模型是完全错误的,系统应该渐进式地进行精化。让系统尽快的运行起来,哪怕什么功能也还没有实现,这样的开发方式可以时刻从整体上对软件进行把握,也避免了到最后软件开发完了,却漏洞百出的问题。

6.编程人员应该只看到定义良好的接口,还是应该了解内部的实现逻辑呢?完全采用一种方式都不太好吧?嗯,以后可以多注意下。

7.“对于项目的成功而言,项目人员的素质、人员的组织和管理是比使用的工具或采用的技术方法更重要的因素”。项目中的很多问题都是因为技术上的原因造成的,而多是由于人员之间的沟通和协调不顺导致的。

8.最后作者将软件工程和化学工程进行了比较,对软件工程这个焦油坑的未来还是充满了希望的,可是我怎么就没有这样的乐观呢-_-...... 


用户的需求总是源源不断的,所以系统也必须保持不断更新。“软件产品易于掌握的特性和不可见性,导致它的构建人员面临永恒的需求变更”。因此需要从以下几个方面着手:

1.为变更计划系统。在设计系统时就要考虑到系统的变化,采用模块化、可扩展的函数等手段,更重要的是,将变更阶段化。每隔一段时间就发布一个新的版本,将变更限制在各个版本之内。

2.为变更计划组织架构。这个观点倒是首次看到,组织架构也能随时变更?“这其中的障碍是社会性的,人们必须同顽固的戒心做斗争”,也许正是因为这一点让我潜意识里一直认为组织架构是不能随意变更的。要使管理人员和技术人员具有可换性,首先要使两者在项目中是平等的,但事实上管理人员却拥有着更高的威信。另外,还要对管理人员和技术人员进行相应的培训,这对于公司来讲,也是不小的投资吧。目前只看到过技术人员向管理人员的转变,而相反的转变却没遇到过。

最后讲述了软件的维护。发布后的软件系统,在增加新功能的时候,总是难免会引入新的bug,“看上去很微小的错误,似乎仅仅是局部操作上的失败,实际上却是系统级别的问题”,因此“基于原有系统的重新设计是完全必要的”,每隔一段时间,总是需要发布一个全新的系统,尽管他是基于原有的系统进行设计的,但它显然更合理,缺陷更少。这是一个周而复始的过程......


整理:

https://book.douban.com/subject/2230248/annotation

小编蓝狐