软件工程概述(上)
1、软件的概念、特点和分类
要了解软件工程,首先让我们重新认识一下软件。如今可以说是一个软件定义一切的时代,虽然人工智能发展的如火如荼,但究其本质,核心还是软件。那么,如何给软件下一个定义呢?软件又具有哪些特点?如何对软件进行分类?我们一起来了解一下。
(1)软件的概念
软件的定义:软件是计算机系统中与硬件相互依存的另一部分,它是包括程序,数据及其相关文档的完整集合。
一直以来,人们对软件的认识都存在误区,一种比较典型的误解是:软件就是程序,开发软件就是编程序。从上面的定义可以看出,软件是由程序、数据和文档三部分组成的。
- 程序:计算机可以接受的一系列指令,运行时可以提供所要求的功能和性能。
- 数据:使得程序能够适当地操作信息的数据结构。
- 文档:描述程序的研制过程、方法和使用的图文资料。
当然,对软件的定义还有其他一些具有代表性的说法:
- IEEE定义(1983年):计算机程序、方法、规则、相关的文档资料以及在计算机上运行程序时所必需的数据。
- 计算机软件是由专业人员开发并长期维护的软件产品。
注:IEEE是电气与电子工程师协会(Institute of Electrical and Electronics Engineers)的简称, 总部位于美国纽约,是一个国际性的电子技术与信息科学工程师的协会,也是全球最大的非营利性专业技术学会。在本栏目的文章中还会多次提到它,有关其详细介绍可参见百度百科。
思考题:当前火遍全球的ChatGPT是不是软件?
(2)软件的特点
由上面的定义可以得知,软件是计算机系统不可缺少的组成部分,那么与硬件相比,它具有哪些特殊性呢?下面我们来一起认识一下。
- 软件形态的逻辑性
我们对事物的认识,一般都是首先从其外形入手的。不过,软件却让你失望了,因为它是一个逻辑实体,是抽象的、不可见的。这样导致其开发过程中进度难以衡量、质量难以评价、管理和控制相当困难。
- 生产过程的非制造性
软件的生产过程就是软件的开发过程,不过,与一般产品的生产过程不同,它的开发过程中没有明显的制造过程。正如前面的定义所提到的,软件是由程序、数据和文档组成的,软件并不是传统意义上的制造产生的,软件一旦开发完成,只需经过简单的拷贝就可以完成其大规模的发布。在互联网时代,其发布更为简单,用户只需在网站上完成注册,即可轻松使用,你并不需要关心它是如何生产出来的。软件成本集中于开发上,这意味着软件项目不能象硬件制造项目那样来管理。
- 使用方式的无磨损性
在软件的运行和使用期间,没有硬件那样的机械磨损和老化问题。软件不会被“用坏”,但是会存在“不好用”的问题,为了让其好用,软件开发者就需要对其进行维护,维护意味着改正或修改原来的设计。当一个硬件构件磨损时,可以用另外一个备用零件替换它,但对于软件则不然。每一个软件故障都表明了设计/编程中存在错误。因此,软件维护更复杂。
- 开发和运行对环境的依赖性
正如定义中所提到的,软件的开发和运行常受到计算机系统的限制,对计算机系统有着不同程度的依赖性。
- 软件的复杂性
软件可以说是人类能够创造的最复杂的产物,其复杂性体现在实际问题的复杂性、程序逻辑结构的复杂性和其他领域专门知识的复杂性。
- 开发方式的手工化
正是由于软件具有的复杂性,软件的开发至今尚未完全摆脱手工的开发方式。大多数软件是定制的,而不是通过已有的构件组装而来的。 当前正处于人工智能时代,涌现出一批包括ChatGPT在内的“编程机器人”,但它们仅仅能处理一些通用的情况,对于特殊情况的软件开发,仍然需要开发人员手工来完成。
- 成本的昂贵性
由于软件多为“纯手工打造”,所以软件的成本相当昂贵。在软件开发过程中,会投入大量的、复杂的、高强度的脑力劳动,投入的研发和管理成本相对比较高。
- 社会因素
软件之所以能够得到推广,就是由于它能够让人们借助计算机大大提高了工作的效率。也正因为如此,软件的使用必然会引起劳动力的释放、机构的重组,由此带来一系列的社会问题。这与人们一直以来讨论的“人工智能是否会替代人类”是一个道理。
(3)软件的分类
我们可以从不同的角度对软件进行分类,最直接的就是按照软件实现的功能来对其分类。包括:
- 系统软件:用于管理和控制计算机硬件资源,并提供用户界面和其他系统服务。
- 应用软件:包括办公软件、图形设计软件、音视频播放软件、游戏软件、网络通信软件、实用工具软件等,用于满足用户实际需求的各种软件。
- 支撑软件:介于系统软件和应用软件之间,用于为应用软件的开发和运行提供支撑。包括开发工具软件、数据库管理软件等。
思考题:针对上面各类软件,你能举出一些具体的例子吗?其中哪些是国产的软件,与国外的软件相比,我们有哪些优势和劣势?
除了按照功能分类以外,下图还给出了一些其他的软件分类方式。

2、软件危机
对软件有了基本的认识之后,我们就需要了解一下与软件工程发展有着密切关系的另一个基本概念,那便是“软件危机”。
(1)什么是软件危机?
软件危机的定义: 软件危机是在计算机软件开发、维护过程中所遇到的一系列严重问题,导致软件的开发、维护出现风险。
由定义可以看出, 软件危机通常包含两方面的问题:
- 如何开发软件,以满足对软件日益增长的需求。
- 如何维护数量不断膨胀的已有软件。
不管是开发还是维护,一旦出现问题,都将带来不可预估的风险和损失,我们先来看几个例子:
软件危机示例1:1996年6月4日,Ariane5火箭在发射37秒之后偏离其飞行路径并突然发生爆炸, 当时火箭上载有价值数亿美元的通信卫星。
事故原因:
- 程序中试图将64位浮点数转换成16位整数时产生溢出
- 缺少对数据溢出的错误处理程序
- 备份软件通过复制而成
在这个例子中,正是由于软件开发过程中出现的疏忽,导致了数亿美元的损失,想象一下,如果这样的事故发生在载人航天领域,其后果将更为惨痛。
软件危机示例2:Windows Vista是微软公司于2007年1月30日发布的操作系统,虽然具备了一些新功能和改进,但它被普遍认为是一次失败的操作系统发布。
• 该系统从2001年开始研发,整个过程历时5年半,先后有9000位开发人员投入其中,耗资60亿美元,代码规模超过5000万行。
• 按照微软公司最初的计划,该系统面世时间应该在2003年,之后推迟到2004年下半年再到2005年初,最终在取消一些高级功能 后于2006年11月正式发布。
• 由于整个系统过于庞杂,其开发管理相当混乱,以致于很多时间用在互相沟通和重新决定上。
• 从Vista Beta1进入公开测试以来,程序错误总数已经超过2万个,这其中还不包括微软内部未公开的一些错误。
(2)为什么会产生软件危机?
由前面的2个例子可以看出,软件危机严重威胁着软件行业的发展。那么,为什么会产生软件危机呢?
首先,需要从软件自身的特点说起。我们前面总结了软件的几个特点,正是由于软件作为逻辑产品所具有的独特性决定了软件开发与维护的复杂性,导致软件的开发和维护比硬件更难。正如弗雷德里克·布鲁克斯[美]在《人月神话》中提到的,软件所具有的复杂性、一致性、可变性、不可见性等特性,使得软件开发过程变得难以控制,开发团队如同在“焦油坑中挣扎的巨兽”。
- 复杂性
软件是人类思维和智能的一种延伸,它比任何一种人类的创造物都要复杂得多,是人类创造出的最复杂的物体。

- 一致性
由于软件不能独立存在,需要依附于一定的环境,因此软件必须遵从人为的惯例并适应已有的技术和系统且需要随接口不同而改变、随时间推移而变化,而这些变化是不同人设计的结果。

如上图所示,软件的运行需要依赖若干硬件系统,如何保持其一致性,是软件开发和维护人员面临的挑战之一。
- 可变性
由于软件没有明显的生产过程,因此人们总是认为软件是容易修改的,但忽视了修改所带来的副作用。不断的修改最终导致软件的退化,从而结束其生命周期。

- 不可见性
由于软件是一种“看不见、摸不着”的逻辑实体,不具有空间的形体特征。虽然开发人员可以直接看到程序代码,但源代码并不等于软件本身;软件是以机器代码的形式运行,人们无法看到源代码的执行过程。难怪《人月神话》中把软件开发人员比作“皇帝的新衣”中的裁缝。
其次,造成软件危机的另一个原因是在开发和维护过程中,采用了错误的方法和技术。
- 软件管理相对落后。由于缺乏软件开发的经验和相关数据的积累,使得开发工作的计划很难制定,以致经常超出经费预算,进度计划无法遵循,完成开发的期限一再拖延。实际成本比估计成本有可能高出一个数量级,实际进度比预期进度拖延几个月的现象并不罕见。
- 软件需求不够清晰。软件开发人员常常在对用户要求只有模糊的了解,甚至对所要解决的问题还没有确切认识的情况下,就匆忙着手编写程序,急于求成。开发工作开始后,软件人员和用户之间的沟通不够及时、充分,造成矛盾在开发后期集中暴露。
- 软件测试不够充分。未能在测试阶段充分做好检测工作,提交给用户的软件质量差,在运行中暴露出大量的问题,轻者影响系统的正常工作,重者发生事故,甚至造成生命财产的重大损失。软件质量保证技术还没有坚持不懈地应用到软件开发的全过程中。
- 软件开发方法相对陈旧。早期的个体化开发特点,开发过程没有统一的、公认的方法论和规范指导,加上不重视文字资料工作,资料很不完整。忽视每个人与其他人的接口部分,发现了问题修修补补,这样的软件很难维护。很多程序中的错误是非常难改正的。
- 没有软件生命周期概念。认为软件就是编程、运行,轻视软件维护这个重要环节。其实编程工作量只占总工作量的20%左右,软件维护的工作量占到50%以上。
- 忽视开发代价与时间的关系。软件开发过程中,在不同的时间段引入同一变动付出的代价具有明显的不同,引入变动的时间越晚付出的代价越高。
(3)如何解决软件危机?
我们研究软件危机,最终是为了通过解决软件危机来推动软件行业的健康发展。那么,如何解决软件危机呢?
首先,应该正确的认识计算机软件。
作为软件行业的从业者,绝不能把软件等同于编程序。作为一种特殊的产品,软件是由程序、数据和文档组成的,这也就要求我们在开发软件时,要重视数据接口和相关文档,避免软件自身特点引起的各种副作用。
其次,按工程化的原则和方法组织项目开发。
50年代到60年代时,程序设计曾经被看做是一种任人发挥创造才能的技术领域。写出的程序通篇充满了程序技巧,这些程序很难被别人看懂。随着计算机技术的发展和广泛使用,逐渐抛弃了这种观点。人们要求这些程序容易看懂、容易使用,并且容易修改和扩充。多个软件人员分工合作、共同完成。只有在项目的总体要求和技术规范的约束下充分发挥和施展自己的才能。
最后,通过技术和管理的方法手段提升软件的质量。
软件具有自己的生命周期。大型软件系统的开发与其他工程项目如建造桥梁、制造飞机、轮船等的开发是同理的。必须采用工程化思想,运用先进的技术方法和管理手段,来提升软件的开发质量和效率。软件工程也由此诞生。
思考题:你是如何认识软件危机的?作为一名软件行业的从业者,在当前我们国家面临的卡脖子问题上应该肩负怎样的责任?
3、软件工程的发展历程
如下图所示,随着计算机技术的快速发展,软件的开发和维护面临着各种挑战。

为了应对这些挑战,解决软件危机给软件行业发展带来的种种威胁。人们开始尝试将工程化的方法应用到软件领域,软件工程由此诞生。
软件工程的发展经历了以下几个阶段:
-
原始阶段(1940年代-1960年代):在这个阶段,计算机编程主要是由个人完成的,没有完整的软件开发生命周期,也没有专门的软件开发方法论。
-
结构化编程阶段(1960年代-1970年代):在这个阶段,人们开始意识到软件开发需要遵循一定的规范和结构,提出了结构化编程的概念,主要通过模块化、顺序、选择和循环结构来组织代码。
-
软件危机阶段(1970年代-1980年代):随着软件规模的增大和复杂性的提高,软件开发面临了许多挑战和问题,如进度延迟、质量低下等,这被称为软件危机。为了解决这些问题,出现了不同的方法和模型,如结构化方法、面向对象方法等。
-
软件工程阶段(1980年代-现在):在这个阶段,软件开发逐渐形成了一门专业化的学科,并建立了一套完整的软件开发生命周期,包括需求分析、设计、编码、测试、部署和维护等环节。同时,还出现了一系列的软件开发方法和模型,如瀑布模型、迭代模型、敏捷开发等,以提高软件开发的效率和质量。
-
现代软件工程阶段(2000年代-现在):随着互联网和移动互联网的发展,软件工程也面临了新的挑战和需求,如大规模分布式系统、云计算、DevOps等。为了应对这些挑战,出现了一系列新的软件开发方法和技术,如微服务架构、容器化、持续集成和持续交付等。这些新技术和方法在改进软件开发的同时,也提升了软件工程的发展水平。
需要注意的是,软件工程的发展是一个不断演化和迭代的过程,各个阶段的变化并不是绝对的划分,而是相互渗透和影响的。同时,随着技术和需求的不断变化,软件工程的进一步发展还将继续。
软件工程的提出。软件工程是一种以工程化的方法来开发和维护软件系统的学科和实践。它的提出源于对软件开发中问题的深刻认识和需求的增长。
在1968年,由于软件项目的失败率和成本的快速增长,美国计算机科学家在NATO(北大西洋公约组织)的软件工程会议上,首次提出了软件工程的概念。软件工程的目标是将工程学的原则和方法应用于软件开发过程,以提高软件的质量、可靠性和可维护性。
软件工程的提出主要是由于传统的软件开发方法无法满足市场对软件的需求。传统的方法主要是基于个人经验和直觉来开发软件,缺乏明确的开发过程和规范,容易导致软件项目的失败和延期。
软件工程的提出也是为了应对软件系统规模的增长和复杂性的增加。随着计算机技术的发展,软件系统的规模越来越大,功能越来越复杂,开发人员需要更加系统化的方法来管理软件开发过程,确保软件系统的质量和可维护性。
软件工程的提出还受到了其他工程学科的启发,例如电气工程和机械工程。这些工程学科有着明确的开发过程和规范,软件工程借鉴了这些经验,并将其应用于软件开发过程中。
总而言之,软件工程的提出是为了应对软件开发中的问题和需求,以提高软件的质量、可靠性和可维护性。它借鉴了其他工程学科的方法,将工程学的原则和方法应用于软件开发过程中。


