软件开发经验与教训 ——《没有银弹》和《软件长期危机》读书笔记

软件开发不仅停留于理论,还需要实践来意识到理论的实用性。本文是一篇随笔,讲了读后感以及自己在实际管理项目的一些经验与教训。

创作背景

《没有银弹》创作于1986年,是都柏林IFIP研讨会的受邀论文。那个年代出现了多种高级语言,出现了面向对象编程,出现了诸多工具,但都很难解决软件的本质问题。没有银弹从软件本质工作于附属性工作出发,尝试寻找提高软件开发效率,解决软件危机的方法。

《软件长期危机》来自于1994年科学美国人杂志上的一篇文章,从多个案例出发,比如军方的卫星,比如丹佛机场,阐述了软件危机的一些实际体现。此时软件复杂度高速增长,带来了新的软件开发问题。

两篇文章都诞生于上世纪八九十年代,注意,这个时候是硬件高速发展的年代,Intel在1985年推出了革命性的80386芯片,IBM引领的个人PC浪潮也在这个时代到来,程序的规模达到了前所未有的高度,这导致软件复杂度剧增,传统的软件开发模式难以应对,八九十年代爆发的这种现象也被称为“第二次软件危机”。

软件危机 历史与现状

软件危机是指落后的软件生产方式无法满足迅速增长的计算机软件需求,从而导致软件开发与维护过程中出现一系列严重问题的现象。1968年,北约创造了软件危机一词,并提出软件工程的概念,渴望以此来解决软件危机。

软件危机有着诸多具体表现,比如:

  • 软件开发费用和进度失控,进度拖延,损害软件质量。
  • 软件可靠性差,耗费了大量人力物力,正确性难以保证,错误所造成的损失惊人。
  • 生产出来的软件难以维护,缺少文档,难以定位错误。

这是软件危机最开始,也就是六七十年代时候的表现,那时候刚刚从小作坊生产变成集约化生产,但效果却不佳,这些实践使得软件工程学的需求提上日程。

但软件危机并非一成不变,到了八九十年代,也就是第二次软件危机,出现了新的问题:

  • 硬件成本逐年下降,而软件成本占比却居高不下。软件规模增长很快。
  • 软件开发的生产率提升难以匹配硬件的生产率提高。

这个时候,高级语言诞生了,面向对象诞生了,设计模式诞生了,软件工程的各种方法也诞生了,程序员们终于不再用晦涩的底层语言来编写,但实际上,生产率并没有显著提高。

但硬件并没有停止发展,串行化时代要结束了,多核,并行化发展成为了新的趋势。不同的硬件需要不同的软件,与之对应的也要有不同的软件标准,这便意味着混乱。现代的软件开发依然有着上述问题。

文章观点

没有银弹提出的,在短期内不存在快速提高生产效率的方法。他将软件开发中所需要的工作分为两部分,必要的本质的工作,以及附属性工作。前者关心的是如何从抽象性问题发展出解决方案,后者则是将构思实现在电脑上所遇到的困难。本质性的问题有着以下的几个特性:

  • 复杂性:软件需要解决的问题需要牵扯到计算步骤,这是人为的,抽象的智能活动,多半是复杂的。
  • 隐匿性:尚未完成的软件是看不见的。
  • 配合性:大型软件环境中接口需要一致,但随着开发进行,这会变得十分困难。
  • 易变性:软件的环境会改变,硬件会改变,使用认权会改变,这些阻碍了软件开发。

在文章看来,工具的研发,比如高级语言,比如面向对象,比如专家系统,比如程序验证,这些东西都难以触及到软件开发的本质上的问题。

就软件的开发来看,第一步是需要理解需求,这意味着与人沟通,而需求本身,依赖于环境,人群,存在着变数。首先要解决的便是让客户与程序设计多打交道,使得需求能被合理地设计出来。

买软件,而非开发软件属于很好的方法,购买的软件通常具有良好的文档,不去开发往往更好。

快速原型工具也是提升效率的方法之一。

增量化开发,而非一次完成全部,能够提升士气。开发模式对于软件开发也有着显著的提升。

个人经验与观点

“没有银弹”提出的观点是具有先见性的,但在我个人看来,观点过于悲观。他的主要观点在于“10年内难以将软件开发效率提升一个数量级”,他所列举的样例很正确,“如果附属性工作占90,本质性工作占10%,那么需要将附属性工作全部减为0才能达到一个数量级的提高”。

本质性的工作确实难以触碰,但是十年过于短暂,而数量级的提高过于惊人。观点正确,但不够现实。软件开发在发展,软件工程化的理念同样在发展,就附属性工作而言,编写高级语言比起编写底层语言所需要的学习成本要降低了许多,高级语言的发展提供了抽象。现在无论是什么工具都相当丰富,降低了交流的成本,能够提升包括需求分析,概念图构建等诸多曾经被认为是“本质性工作”的效率。

我们可以采用所有严苛的工程化方法去开发,但最后我们会发现人是最大的限制。实质上,工程化本身就是为了约束人。所有”工程“,但凡是有多人参与,都需要考虑一个问题:如何把这些会犯错的人的工作有效整合在一起,让最后得到的结果可行。我自己认为,这是工程化的基本思想。

我自己目前带了一个项目,开发学校的OnlineJudge系统。最初的版本采用PHP开发,但随着实际运行,我们发现PHP存在严重的性能问题,以及难以维护。我们将效率影响最为严重的部分,也就是交题的部分,迁移到了原来用go语言写的一个滚榜的模块中。之前采用了mq设计,后来采用了gRPC设计,性能够了就抛弃了mq。随着开发,这些模块耦合越来越严重,问题也越积越多。虽然这个系统最后可以运行,但写PHP的人越来越少,为了维护性我们决定重构,这份接力棒也交到了我的手上。

最开始我对重构拥有充足的信心,因为重构没有很多需要构造的复杂概念,只需要改动部分原先不合理的地方。逻辑问题不大。但事实上则超乎我的预料。

项目开发总共三四人,最开始确定的是寒假结束能够基本上线,但这面对着第一个问题:人。

寒假对于学生而言各回各家,也就是需要找人的时候根本找不到人,交流成本无限大,外加上过年,以及放假的效率问题,寒假的开发进度基本没有动。这也是给我的第一个教训:开发需要保持时刻的沟通,至少需要找到人。

寒假结束后情况并没有改善。这时候开发人员的性格问题得到了体现。有的人属于定好了ddl自己会找机会完成,有的人属于不催就写不动的人。人的问题需要用人的方法来解决,对症下药。我的后端属于后者,这也是我的第二个教训:当催促不管用的时候,需要用更为显著,更为实际的方法,或者说通过威胁来进行进度跟进。这里我采用的是定好ddl,进行验收,验收不过就要请客,造成实际的经济损失的方式会更加记忆深刻。

但还问题没有结束,这时候有了新的问题:技术性问题。我的后端在技术上不够过关,自己也不愿意交流,导致在实现上出现了相当多的错误。比如接口写错了,该用post时候用get导致get请求被缓存,从而无法正常登录。这个问题相当难以定位。第三个教训:需要正确评估开发人员的技术水平,避免出现超出开发人员的技术水平的问题的出现。

在总体大致测试无误的时候,开始进行对接,环境问题也是一个折磨。前端的依赖问题导致在实际机器上难以部署,但还好的是没有推翻重来,而是在基础上路由了一下从而解决了。在对接前前后端都说进度稳步推进,但实际上并非如此。这也是第四个教训:“永远不要相信开发人员关于进度的鬼话”。看起来很滑稽,但真正开发的时候,就会知道这是真正的教训了。

在对接完成后也出现了或大或小的问题,但与项目管理关系不是很大,纯粹是技术问题。到目前为止,oj还没开发完。对于oj,我们的初衷是为了使OJ系统“易于维护”从而进行的重构,但实际而言现在只实现了原来的有限的功能,还没有重构完全。而且,没有文档。这是我第五个教训:可维护性高首先要文档齐全。可维护性的基础基于文档,即使是良好的代码,学习成本依然很高。好的文档才是可维护性的基础。

实际的经验到此为止,虽然比不上什么大的项目,但确实是亲身经历。项目管理需要与真实的“人”所打交道,需要保持沟通,需要清楚实力,需要谨慎切分任务,需要制定合理的ddl,需要正确评估进度,以及应对各种各样的异常状况,可预见的比如节假日,不可预见的比如联系不到人。与人打交道还得运用传统的社交意义上的各种方法。这些是基础中的基础,但也是极为重要的一部分。

软件工程学我一直认为是一门需要实践的科学,有些理论上看起来很美好的东西,比如设计模式,实践起来非常难受,有些不严格按照理论而发展的比如说一些开发模型,反而能够很好地得到使用。这些在书本中存在的理论都需要实践。“软件工程”在本科阶段最大的问题,在我看来,就是没有能很好地实践。本科期间缺少的不是知识,而是能够应用这些知识的,足够多的且技术达标的团队。这些在我看来是本科教学软件工程课程时候的很大的阻碍,但这些是尤为重要的。

软件开发经验与教训 ——《没有银弹》和《软件长期危机》读书笔记

https://exgod22356.github.com/Science/软件开发经验与教训-——《没有银弹》和《软件长期危机》读书笔记/

Author

王钦砚

Posted on

2021-05-09

Licensed under

CC BY-NC-SA 4.0

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×