非原创,整合朋友的
人是程序员,月是时间,如果1人干10个月如果等同10人干1个月,那就成神话
而“人月神话”反映出的,就是软件开发在项目管理中所遇到的难题:管理人员因为盲目乐观,对项目开发过程中的困难没有充分的认识,在计算项目的工作量和交付时间上采用了错误的计算方法,忽略了细节对整体的巨大影响,而这很可能会导致项目延期。
初听这个词,会认为它是神话故事或者寓言,实际人月是估计和进度安排中使用的工作量单位。作者揭示了它具有欺骗性,因为它会给我们一种感觉:时间与人力是可交换的,如果时间不够了,多加点人手就万事大吉!但是实际软件开发中可以用简化了的Brooks法则来描述这种状况:Adding mapower to a late software project makes it later. 翻译过来就是向进度落后的项目增加人手,只会使进度更加落后
向软件项目中增派人手从三个方面增加了项目必要的总体工作量:
- 任务重新分配本身和所造成的工作中断;
- 培训新人员;
- 额外的相互沟通
当项目延期所导致的后续成本非常高时,对于任务进行削减,这常常是唯一可行的方法
焦油坑
过去几十年的大型系统开发就犹如一个焦油坑,很多大型动物在其中剧烈挣扎,他们中大多数开发出了可运行的系统—不过,其中只有非常少数的项目满足了目标、时间进度和预算的要求
各种团队,大型的和小型的,庞杂的和精干的,一个接一个淹没在了焦油坑中。表面上看起来好像没有任何一个单独的问题会导致困难,每个都能被解决,但是当它们相互纠缠和累积在一起的时候,团队的行动就会变得越来越慢且很难看清问题的本质
外科手术队伍
小型、精干队伍是最好的—尽可能的少
需要协作沟通的人员的数量影响着开发成本,因为成本的主要组成部分是相互的沟通和交流,以及更正沟通不当所引起的不良结果(系统调试)。
Mills建议大型项目的每一个部分由一个团队解决,但是该队伍以类似外科手术的方式组建,而并非一拥而上。
一位首席程序员、类似于外科手术队伍的团队架构提供了一种方法—既能获得由少数头脑产生的产品完整性,又能得到多位协助人员的总体生产率,还彻底地减少了沟通的工作量
外科手术队伍,如书中所提供的一个研究数据:最好的和最差的表现在生产率上平均为10:1,在运行速度和空间上具有5:1的惊人差异!简言之,$20,000/年的程序员的生产率可能是$10,000/年程序员的10倍
这样看来我们的团队应该精而小,但是根据书中计算,OS/360(一个大型系统)如果让10名非常强大的编程人员来进行开发(比一般人员各方面生产率高7倍),仍然需要10年时间,但我们知道软件行业变化太快了,10年之后这个系统会得到注意吗?不会显得过时吗?所以,如书中所言:面对真正意义上的大型系统,它太慢了。
那该如何解决了?Harlan Mills的提议提供了一个崭新的、创造性的解决方案。他建议大型项目的每一个部分由一个团队解决,该团队类似外科手术队伍,一个人完成问题的分解,其他人给予他所需要的支持,以提高效率和生产力。具体的角色分工可以参考下图:
我们可以看出平均主义、民主与平等在大型系统软件开发中不是那么起作用,我们反而看到早期英雄式编程风格的影子,外科医生承担了大部分工作,其他人成为副手,协助工作。
贵族专制、民主政治和系统设计
为什么兰斯教堂经过几个世纪的迭代,还能保持一致的风格?因为设计师们在几代人的传承中,保持了设计风格概念的一致性和完整性。返回到我们的软件开发和设计,你是想要哥特式教堂模式的软件还是兰斯教堂式的软件?
我想大部人都是想要兰斯教堂式的。为了达到这个目标,这里需要引入一个概念-“贵族专制”。因为要保持概念的完整性,就要求设计必须由一个人做,或者非常少数互有默契的人来做。只能由少数精英做决定的事情,是不是有点像-贵族专制。
但进度压力会要求很多人来开发这个系统,怎么解决这种矛盾呢?
1、分析设计和实现,将设计和实现分离,设计由我们的结构师来做,比如我们的结构师可以把接口都定义好,把类图画好,实现则由开发人员来做,这样整体的架构风格就保持了一致。
2、已“外科手术队伍”讲的方式组建开发团队
如果体系结构队伍工作缓慢,实现人员只能空闲地坐着等吗?
1、实际上开发分为体系结构、设计实现、物理实现,3个独立的阶段,在实际情况中,他们可以并行的开发。
2、需求->设计->实现,我们传统的思维,采用水平分割任务的方式,串行地执行,实际上我们可以换种思维方式,垂直的划分我们的任务
水平划分:
垂直划分:
同工作的水平分割相比,垂直划分从根本上大大减少了劳动量,结果是使交流彻底地简化,概念完整性得到大幅提高
现在让我们来处理具有浓厚感情色彩的问题——贵族统治和民主政治
结构师难道不是新贵?他们是一些智力精英,专门来告诉可怜的实现人员如何工作?是否所有的创造性活动都被这些精英单独占有,实现人员仅仅是机器中的齿轮?难道不能遵循民主的理论,从所有的员工中搜集好的创意,以得到更好的产品,而不是将技术说明的开发工作仅限定于少数人?
最后一个问题是最简单的。我当然不认为只有结构师才有好的创意。新的概念经常来自实现人员或者用户。然而,我一直试图表达,并且我 所有的经验使我确信,系统的概念完整性决定了其使用的容易程度。不能与系统基本概念进行整合的良好想法和特色,最好放到一边,不予考虑。如果出现了很多非常重要但不兼容的构想,就应该抛弃原来的设计,对不同基本概念进行合并,在合并后的系统上重新开始。
至于贵族专制统治的问题,必须回答“是”或者“否”。就只能存在少数的结构师而言,答案是肯定的,他们的工作产物的生命周期比那些实现人员的产物要长,并且结构师一直处在解决用户问题,实现用户利益的核心地位。若要得到系统概念上的完整性,必须有人控制这些概念。这实际上是一种无需任何歉意的贵族专制统治
第二个问题的答案是否定的,因为外部技术说明的编制工作并不比具体设计实现更富有创造性,它只是一项性质不同的创造工作而已。在给定体系结构下实现其设计,同样需要同编制技术说明一样的创造性、同样新的思路和卓越的才华。实际上,产品的成本性能比在很大程度上依靠实现人员,就如同易用性在很大程度上依赖结构师一样。
有很多行业和领域中的案例让人相信纪律和规则对行业是有益的。实际上,如同某艺术家的格言所述,“没有规矩,不成方圆。”最差的建筑往往是那些预算远远超过其实目标的项目。
通过作者的自我问答,我们可以得出结论:软件体系结构设计中,贵族专制必须实行。少数结构师决定整体框架,普通程序员是被专制对象。对于普通程序员来说,成为贵族就是其目标之一了。
保有成本意识
一种普遍倾向是过分地设计第二个系统,向系统添加很多修饰功能和想法,它们曾在第一个系统中被小心谨慎地推迟了。
项目经理接到一个需求的时候,通常是下面的这种场景。
1、架构师从技术架构设计上给出解决方案;
2、财务需要考虑开发成本支出,想尽量的节流;
3、客户经理又想尽可能多的增加系统的功能;
三方的矛盾最终要在“时间”这个通常的限定条件下达成妥协。
做出的牺牲主要有:
- 削减设计,相当于挑出主要矛盾,次要矛盾尽量往后挪;
- 以更低成本的实现方法实现;
大多数情况下,作为技术控的架的构师,很少去考虑成本因素,这就需要项目经理尽快的和持续的和其沟通,让其有较好的成本意识。
与此同时,角色分工也要清晰,架构师只需要做好设计,并准备好一种建议的实现方式,记住是建议的,因为最终的实现由工程师去做。工程师有自己的创造热情,优先做到导流,之后才是堵流(偏离的时候做)。
再者,在成功开发一个系统之后,会导致自我欣赏和盲目自信,从而过度设计第二个系统。比如过度琢磨系统的可伸缩性;需求健全的系统而忽略时间和成本的考量;做了不少花哨但不实用的功能 and so on。
所以不要画蛇添足,在职责方面,也在设计方面。
实际情况中,尽早交流和持续沟通能使结构师有较好的成本意识,以及使开发人员获得对设计的信心,并且不会混淆各自的责任分工。
面对估算过高的难题,结构师有两个选择:削减设计或者建议成本更低的实现方法—挑战估算的结果
保障制度执行
即使是大型的设计团队,设计结果也必须由一个或两个人来完成,以确保这些决定是一致的
允许体系结构师对实现人员的询问做出电话应答解释是非常重要的,并且必须进行日志记录和整理发布。
对于存有疑问的实现人员,应鼓励他们打电话询问相应的结构师,而不是一边自行猜测一边工作,这是一项很基本的措施项目经理如何确保每个人听到、理解并实现结构师的决策呢?
- 文档化的规格说明———-手册
- 形式化定义
- 直接整合
- 会议和大会
- 多重实现
- 电话日志
- 产品测试
团队交流
巴比伦塔项目的失败是因为缺乏交流,以及交流的结果—组织。
“因为左手不知道右手在做什么,从而进度灾难、功能的不合理和系统缺陷纷纷出现。
随着工作的进行,许多小组慢慢地修改自己程序的功能、规模和速度,他们明确或者隐含地更改了一些有效输入和输出结果用法上的约定,而因此给其他部分引发了BUG。
团队应该以尽可能多的方式进行相互之间的交流:非正式、常规项目会议,会上进行简要的技术陈述、共享的正式项目工作手册。举行常规项目会议,会议中,团队一个接一个地进行简要的技术陈述。这种方式非常有用,能澄清成百上千的细小误解
培养大局观
项目规模本身很大,缺乏管理和沟通,以至于每个团队成员认为自己是争取小红花的学生,而不是构建系统软件产品的人员
为了满足目标,每个人都在局部优 化自己的程序,很少会有人停下来,考虑一下对客户的整体影响。对大型项目而言,这种导向和缺乏沟通是最大的危险
在整个实现的过程期间,系统结构师必须保持持续的警觉,确保连贯的系统完整性。在这种监督机制之外,是实现人员自身的态度问题。培养开发人员从系统整体出发、面向用户的态度是软件编程管理人员最重要的职能。
确立需求和关键节点
如果要制造一台机器,哪些是关键的文档呢?
目标:定义待满足的目标和需要,定义迫切需要的资源、约束和优先级
首先,书面记录决策是必要的。只有记录下来,分歧才会明朗,矛盾才会突出。项目经理常常会不断发现,许多理应被普遍认同的策略,完全不为团队的一些成员所知。每个文档本身就可以作为检查列表或者数据库。
项目经理的基本职责是使每个人都向着相同的方向前进。项目经理的主要日常工作是沟通,而不是做出决定;文档使各项计划和决策在整个团队范围内得到交流。
通过周期性的回顾,他能清楚项目所处的状态,以及哪些需要重点进行更改和调整。
面对变化
变更的客观需要
对于大多数项目,第一个开发的系统并不合用。它可能太慢、太大,而且难以使用,或者三者兼而有之。
用户的实际需要和用户感觉会随着程序的构建、测试和使用而变化。
软件产品易于掌握的特性和不可见性,导致了它的构建人员(特别容易)面临着永恒的需求变更。
目标上(和开发策略上)的一些正常变化无可避免,事先为它们做准备总比假设它们不会出现要好得多。
为变更计划组织结构
当系统发生变化时,管理结构也需要进行调整。只要管理人员和技术人才的天赋允许,老板必须对他们的能力培养给予极大的关注,使管理人员和技术人才具有互换性。
为什么缺陷不能更彻底地被修复?
首先,看上去很轻微的错误,似乎仅仅是局部操作上的失败,实际上却是系统级别的问题,通常这不是很明显。
设计实现的人员越少、接口越少,产生的错误也就越少。
所有修改都倾向于破坏系统的架构,增加了系统的混乱程度。用在修复原有设计上瑕疵的工作量越来越少,而早期维护活动本身的漏洞所引起修复工作越来越多。
随着时间的推移,系统变得越来越无序,修复工作迟早会失去根基 ,尽管理论上系统一直可用,但实际上,整个系统已经面目全非,无法再成为下一步进展的基础。
机器在变化,配置在变化,用户的需求在变化,所以现实系统不可能永远可用。崭新的、对于原有系统的重新设计是完全必要的。
我们经常发现一个有趣的事情,那就是随着我们对系统的不断维护,早期的维护工作所引起的漏洞修复工作反而越来越多,系统变得越来越混乱与无序,我们的每一步前进都伴随着一步后退。实际上我们的系统越来越”窄”。
书中提到了一个结论很有意思:
系统软件开发是减少混乱度(减少熵)的过程,所以它本身是处于亚稳态的。软件维护是提高混乱度(增加熵)的过程,即使是最熟练的软件维护工作,也只是放缓了系统退化到非稳态的进程。
找到优秀的工具
编码效率
编码大约只占了问题的六分之一左右,编码估计或者比率的错误可能会导致不合理的荒谬结果
对常用编程语句而言。生产率似乎是固定的。这个固定的生产率包括了编程中需要注释,并可能存在错误的情况.
使用适当的高级语言,编程的生产率可以提高5倍
仓库管理
巧匠因为他的工具而出名。(A good workman is konwn by his tools)
每个团队配备一名工具管理人员。这个角色管理所有通用工具,能指导他的客户和老板如何使用工具,同时他还能编制老板需要的专业工具
机器支持可以有效地划分成目标机器和辅助机器
- 目标机器时软件所服务的对象,程序必须在该机器上进行最后测试
- 辅助及时在哪些在开发系统中提供服务的机器
精确产品设计
许许多多的失败完全源于那些产品未精确定义的地方。
“细致的功能定义、详细的规格说明、规范化的功能描述说明以及这些方法的实施,大大减少了系统中必须查找的bug数量。 注: 需求文档越详细,bug越少
在编写任何代码之前,规格说明必须提交给测试小组,以详细地检查说明的完整性和明确性 注: 需求文档给测试过一遍
他将程序开发划分成体系结构设计、设计实现和物理编码实现,每个步骤可以使用自顶向下的方法很好地实现。
好的自顶向下设计从几个方面避免了bug。
- 清晰的结构和表达方式更容易对需求和模块功能进行精确的描述。
- 模块分割和模块独立性避免了系统级的bug。
- 细节的隐藏使结构上的缺陷更加容易识别。
最后,设计在每个精化步骤的层次上是可以测试的,所以测试可以尽早开始,并且每个步骤的重点可以放在合适的级别上。
一些糟糕的系统往往就是试图挽救一个基础很差的设计,而对它添加了很多表面装饰般的补丁。自顶向下的方法减少了这样的企图。
什么样的文档才是好的文档?
- 目的。主要的功能是什么?开发程序的原因是什么?
- 环境。程序运行在什么样的机器、硬件配置和操作系统上?
- 范围。输入的有效范围是什么?允许显示的合法范围是什么?
- 实现功能和使用的算法。精确地阐述它做了什么。
- 输入-输出格式。必须是确切和完整的。
- 操作指令。包括控制台及输出内容中正常和异常结束的行为。
- 选项。用户的功能选项有哪些?如何在选项之间进行挑选?
- 运行时间。在指定的配置下,解决特定规模问题所需要的时间?
- 精度和校验。期望结果的精确程度?如何进行精度的检测?
项目管理
当人们听到某个项目的进度发生了灾难性偏离时,可能会认为项目一定是遭受了一系列重大灾难。然而,通常灾祸来自白蚁的肆虐,而不是龙卷风的侵袭。
对于项目组来说,一天天的进度落后即“白蚁侵蚀”往往是难发现、难防范、难处理的。而重大灾害反而容易针对性的解决。按照辩证法中提到的,这应该就是量变引起质变,每一天滞后的累积成就了灾难的爆发
Brooks建议制定进度表,进度表的每一件事被称为“里程碑”,他们都有一个日期。而且里程碑的选择只有一个原则,必须是具体、特定、可度量的事件,而且边界明显、没有歧义。如果里程碑定得非常明确,无法自欺欺人时,很少有人就里程碑的进展弄虚作假。
里程碑
里程碑的选择只有一个原则,那就是,里程碑必须是具体的、特定的、可度量的事件,能够进行清晰定义。
例如:”结构师和实现人员签字认可的规格说明”,”100%源代码编制完成,纸带打孔完成并输入到磁盘库”,”测试通过了所有的测试用例”。
如果里程碑很模糊,老板就常常会得到一份与实际情况不符的报告。
慢性进度偏离是士气杀手。[Microsoft的Jim McCarthy说:”如果你错过了一个最终期限(deadline),确保制订下一条deadline
如果在某项活动开始之前就着手估计,并且每两周进行一次仔细的修订,根据实际情况动态调整时间。当里程碑没有正确反映损失的时间,并对人们形成误导,以致事态无法挽回的时候,它会彻底碾碎小组的士气。
保持进度透明可见
一线经理的利益和老板的利益是内在冲突的。一线经理担心如果汇报了问题,老板会采取行动,这些行动会取代经理的作用,降低自己的威信,搞乱了其他计划。所以,只要项目经理认为自己可以独立解决问题,他就不会告诉老板。
有两种掀开毯子把污垢展现在老板面前的方法,它们必须都被采用。
- 一种是减少角色冲突和鼓励状态共享
减少角色的冲突。老板必须规范自己,不对项目经理可以解决的问题做出反应。当项目经理了解到老板收到项目报告之后不会惊慌,或者不会越俎代庖时,他就逐渐会提交真实的评估结果。 - 另一种是猛地拉开地毯。
猛地拉开地毯。不论协作与否,拥有能了解状态真相的评审机制是必要的。PERT图以及频繁的里程碑是这种评审的基础。大型项目中,可能需要每周对某些部分进行评审,大约一个月左右进行整体评审。 - 没有银弹软件工程中的根本和次要问题
没有任何技术或管理上的进展,能够独立地许诺十年内使生产率、可靠性或简洁性获得数量级上的进步。因为软件有无法规避的特性:复杂度、一致性、可变性、不可见性。产品复杂度
由于复杂度,团队成员之间的沟通非常困难,导致了产品瑕疵、成本超支和进度延迟;
由于复杂度,列举和理解所有可能的状态十分困难,影响了产品的可靠性;
由于函数的复杂度,函数调用变得困难,导致程序难以使用;
由于结构性复杂度,程序难以在不产生副作用的情况下用新函数扩充;由于结构性复杂度,造成很多安全机制状态上的不可见性。
复杂度不仅仅导致技术上的困难,还引发了很多管理上的问题。它使全面理解问题变得困难,从而妨碍了概念上的完整性;它使所有离散出口难以寻找和控制;它引起了大量学习和理解上的负担,使开发慢慢演变成了一场灾难。软件可变性
软件实体经常会遭受到持续的变更压力
现实工作中,经常发生两种情况。
当人们发现软件很有用时,会在原有应用范围的边界,或者在超越边界的情况下使用软件。功能扩展的压力主要来自那些喜欢基本功能,又对软件提出了很多新用法的用户们。
其次,软件一定是在某种计算机硬件平台上开发,成功软件的生命期通常比当初的计算机硬件平台要长。即使不是更换计算机,则有可能是换新型号的磁盘、显示器或者打印机。软件必须与各种新生事物保持一致。软件不可见性
软件是不可见的和无法可视化的。 其中的秘密就是逐步发育成长,而不是一次性搭建。
软件开发是一件棘手的事情,并不会有魔术般的解决方案,现在是从业者研究和分析革命性进展的时刻,而不是等待或希望它的出现。
现在有可能可以在软件生产率上取得逐步的进展,而不是等待不可能到来的大突破。
没有银弹
软件工程中的根本和次要问题
软件开发中困难的部分是规格说明、设计和测试这些概念上的结构,而不是对概念进行表达和对实现逼真程度进行验证。
现代软件系统中这些无法规避的内在特性:复杂度、一致性、可变性和不可见性
对于每一个特性,书中进行了详细的描述以及与其他传统行业及计算机硬件的对比,通过作者的描述,我能够清晰感觉这四种内在特性确实是软件的根本属性
作者后面描述了许多可能的银弹,但他们大部分解决的比较高级的次要问题,仍无法解决上面提到的四个根本属性。例如面向对象编程、人工智能等,这些方法有些解决了次要问题,有些的进展却大不如人意。
再论《没有银弹》
文中提到的且直至今日也发挥重大作用的可能的银弹:
- 定制软件包的开发,如今的开源社区已经这样做了很多年,这些公共的库给开发带来极大的便利,确实提高了开发效率。
- 软件重用。大多数有丰富经验的程序员拥有自己的私人开发库,可以使他们使用大约30%的重用代码来开发软件。公司级别的重用能提供70%的重用代码量,它需要特殊的开发库和管理支持。公司级别的重用代码也意味着需要对项目中的变更进行统计和度量,从而提高重用的可信程度。
重用是一件说起来容易,做起来难的事情。它同时需要良好的设计和文档。即使我们看到了并不十分常见的优秀设计,但如果没有好的文档,我们也不会看到能重用的构件。
软件工程的未来
总结:如何处理“人月神话”的困境?
首先,作者建议,以小团队的方式开展工作。
这里不得不说,作者在当时提出了一个类似于外科手术团队的组织结构来开展工作。外科手术团队的奥秘就在于,它是以主刀医生为核心,其他像负责助理医生、麻醉师、护士等人都是为主刀医生服务的,大家各司其职、齐心协力,从而保证手术顺利完成。那么,反映到软件工程上面,就是以架构师或者高级程序员充当主刀医生的角色,而团队管理者充当副手或者服务人员,其他团队成员则分别负责单元代码编写,功能单元测试,文档管理,工具开发及技术支持等等。即使整个项目团队的人数庞大,但只要根据工作边界,将大家划分到一个个类似于外科手术队伍那样的小团队当中去,就可以保障在一定程度上的效率提升。
其次,要进行行之有效的沟通。
定期召开项目进度例会,对数据结构进行监督和全员反馈等等,都是常见的增进沟通的手段。而近年来流行的敏捷开发模式,例如Scrum这种敏捷开发流派,就特别倡导小团队的高频率的沟通,每个迭代(大概2周一个迭代)都会完整经历计划会议、每日站立会议、项目评审会议、团队回顾会议等,特别是每日站立会议,虽然一般只有短短15分钟,但是确是增进沟通的主要行之有效的方式。
此外,作者还在特别强调了两个点:
- 使用产品文档
- “手把手带”的沟通方式
最后,要“防微杜渐”
关于“防微杜渐”,作者具体给出了几点建议:
- 在项目推进的过程中设立一些关键节点,作者称之为“里程碑事件” => 我所在的团队每天的站立会议都会设立“今日目标”,也就是一些里程碑,在每天下班时后看看这些里程碑事件完成了多少,如果完成100%那么久擦掉,如果没有就说明情况和问题,留到下一个工作日继续完成。
- 为项目设立一个专门的规划和控制小组
- 项目管理必须认清一个现实:“唯一不变的就是变化” => 我所在的团队经历过多次需求大改的情况,迫使我们每次修改都要面向未来考虑变化点和可扩展性
- 为了避免项目延迟和失败,要尽可能地提前集成测试 => 只有尽快集成测试,才能暴露前后端在对于backlog的理解上存在的问题,有没有完成AC(验收条件)
参考链接
https://blog.csdn.net/m0_37648645/article/details/101290748
https://blog.csdn.net/zxy5691419/article/details/106415800