软件工程

软件工程（software engineering），是软件开发领域里对工程方法的系统应用。

1968年秋季，NATO（北约）的科技委员会召集了近50名一流的编程人员、计算机科学家和工业界巨头，讨论和制定摆脱“软件危机”的对策。在那次会议上第一次提出了软件工程（software engineering）这个概念，研究和应用如何以系统性的、规范化的、可定量的过程化方法去开发和维护软件，以及如何把经过时间考验而证明正确的管理技术和当前能够得到的最好的技术方法结合起来的学科。它涉及到程序设计语言、数据库、软件开发工具、系统平台、标准、设计模式等方面。其后的几十年里，各种有关软件工程的技术、思想、方法和概念不断被提出，软件工程逐步发展为一门独立的科学。

1993年，电气电子工程师学会（IEEE）给出了一个更加综合的定义："将系统化的、规范的、可度量的方法用于软件的开发、运行和维护的过程，即将工程化应用于软件开发中"。此后，IEEE多次给出软件工程的定义。

在现代社会中，软件应用于多个方面。典型的软件比如有电子邮件、嵌入式系统、人机界面、办公套件、操作系统、网页、编译器、数据库、游戏等。同时，各个行业几乎都有计算机软件的应用，比如工业、农业、银行、航空、政府部门等。这些应用促进了经济和社会的发展，提高人们的工作效率，同时提升了生活质量。

软件工程师是对应用软件创造软件的人们的统称，软件工程师按照所处的领域不同可以分为系统分析师、系统架构师、前端和后端工程师、程序员、测试工程师、用户界面设计师等等。各种软件工程师人们俗称程序员。

## 名称由来与定义

软件工程包括两种构面：软件开发技术和软件专案管理。

- 软件开发技术：软件开发方法学、软件工具和软件工程环境。
- 软件专案管理：软件度量、项目估算、进度控制、人员组织、配置管理、项目计划等。

### 软件危机

1970年代和1980年代的软件危机。在那个时代，许多软件最后都得到了一个悲惨的结局，软件项目开发时间大大超出了规划的时间表。一些项目导致了财产的流失，甚至某些软件导致了人员伤亡。同时软件开发人员也发现软件开发的难度越来越大。在软件工程界被大量引用的案例是Therac-25的意外：在1985年六月到1987年一月之间，六个已知的医疗事故来自于Therac-25错误地超过剂量，导致患者死亡或严重辐射灼伤。

### 由来

鉴于软件开发时所遭遇困境，北大西洋公约组织（NATO）在1968年举办了首次软件工程学术会议，并于会中提出“软件工程”来界定软件开发所需相关知识，并建议“软件开发应该是类似工程的活动”。软件工程自1968年正式提出至今，这段时间累积了大量的研究成果，广泛地进行大量的技术实践，借由学术界和产业界的共同努力，软件工程正逐渐发展成为一门专业学科。

### 定义

关于软件工程的定义，在GB/T11457-2006《讯息技术 软件工程术语》中将其定义为"应用计算机科学理论和技术以及工程管理原则和方法，按预算和进度，实现满足用户要求的软件产品的定义、开发、和维护的工程或进行研究的学科"。包括：

- 创立与使用健全的工程原则，以便经济地获得可靠且高效率的软件。
- 应用系统化，遵从原则，可被计量的方法来发展、操作及维护软件；也就是把工程应用到软件上。
- 与开发、管理及更新软件产品有关的理论、方法及工具。
- 一种知识或学科，目标是生产品质良好、准时交货、符合预算，并满足用户所需的软件。
- 实际应用科学知识在设计、建构计算机程序，与相伴而来所产生的文件，以及后续的操作和维护上。
- 使用与系统化生产和维护软件产品有关之技术与管理的知识，使软件开发与修改可在有限的时间与费用下进行。
- 建造由工程师团队所开发之大型软件系统有关的知识学科。
- 对软件分析、设计、实施及维护的一种系统化方法。
- 系统化地应用工具和技术于开发以计算机为主的应用。
- 软件工程是关于设计和开发优质软件。

## 软件工程的核心知识（SWEBOK）

ACM与IEEE Computer Society联合修定的SWEBOK（Software Engineering Body of Knowledge）提到，软件工程领域中的核心知识包括：

- 软件需求（Software requirements）
- 软件设计（Software design）
- 软件建构（Software construction）
- 软件测试（Software test）
- 软件维护与更新（Software maintenance）
- 软件构型管理（Software Configuration Management, SCM）
- 软件工程管理（Software Engineering Management）
- 软件开发过程（Software Development Process）
- 软件工程工具与方法（Software Engineering Tools and methods）
- 软件品质（Software Quality）

## 软件工程与计算机科学

软件的开发到底是一门科学还是一门工程，这是一个被争论了很久的问题。实际上，软件开发兼有两者的特点。但是这并不意味着它们可以被互相混淆。很多人认为软件工程基于计算机科学和信息科学就如传统意义上的工程学之于物理和化学一样。在美国，大约40%的软件工程师具有计算机科学的学位。在世界其他地方，这个比例也差不多。他们并不一定会每天使用计算机科学方面的知识，但是他们每天都会使用软件工程方面的知识。

软件工程｜电脑科学

目标｜在时间、资源、人员这3个主要限制条件下构建满足用户需求的软件系统。｜探索正确的计算和建模方法，从而改进计算方法本身。

产品｜软件（比如办公套件和编译器）。｜算法（比如希尔排序法）和抽象的问题（比如哲学家进餐问题）。

进度与时间表｜软件专案都有特定的进度与时间表｜研究专案一般不具有设定的进度与时间表

关注点｜软件工程关注如何为用户实现价值。｜软件理论关注的是软件本身运行的原理，比如时间复杂度，空间复杂度，和算法的正确性。

变化程度｜随着技术和用户需求的不断变化，软件开发人员必须时刻调整自己的开发以适应当前的需求。同时软件工程本身也处于不断的发展中。｜对于某一种特定问题的正确解决方法将永远不会改变。

需要的其他知识｜相关领域的知识。｜数学。

著名的探索者和教育家｜巴里·勃姆，戴维·帕纳斯，佛瑞德·布鲁克斯。｜艾兹赫尔·戴克斯特拉，高德纳，罗伯特·塔扬，彼得·斯莱特，艾伦·图灵，姚期智。

著名的实践者｜约翰·巴科斯，丹·布里克林，蒂姆·伯纳斯-李，林纳斯·托瓦兹，理查德·马修·斯托曼。｜无。

例如彼得·麦克布林（Peter McBreen）认为，软件工程意味着更高程度的严谨性与经过验证的流程，并不适合现阶段各类型的软件开发。麦克布林在著作《Software Craftsmanship: The New Imperative》提出了所谓“craftsmanship”的说法，认为现阶段软件开发成功的关键因素，是开发者的技能，而不是“manufacturing”软件的流程。

## 软件工程的现况

Capers Jones曾对美国软件组织的绩效做过评估，所得到结论是：软件工程的专业分工不足，是造成品质低落、时程延误、预算超支的最关键因素。

2003年，The Standish Group年度报告指出，在他们调查的13522个专案中，有66％的软件专案失败、82％超出时程、48％推出时缺乏必需的功能，总计约550亿美元浪费在不良的计划、预算或软件估算上。

## 没有银弹与人月神话

在1986年，IBM大型电脑之父佛瑞德·布鲁克斯发表了他的著名论文《没有银弹》，在这篇著名的论文中他断言：“在10年内无法找到解决软件危机的灵丹妙药”。从软件危机被提出以来。人们一直在寻找解决它的方法。于是一系列的方法被提出并且加以应用。比如结构化程式设计，面向对象的开发，CMM，UML等等。佛瑞德·布鲁克斯著名作品还有《人月神话》。

布鲁克斯在《人月神话：软件专案管理之道（The Mythical Man-Month）》提到，将没有灵丹妙药（silver bullet）可以一蹴而就，开发软件的困难是内生的，只能渐进式的改善。整体环境没有改变以前，唯一可能的解，是依靠人的素质，培养优秀的工程师。

## 软件工程与计算机程序设计

软件工程存在于各种应用中，存在于软件开发的各个方面。而程序设计通常包含了程序设计和编码的反复迭代的过程，它是软件开发的一个阶段。

软件工程力图对软件项目的各个方面作出指导，从软件的可行性分析直到软件完成以后的维护工作。软件工程认为软件开发与各种市场活动密切相关。比如软件的销售，用户培训，与之相关的软件和硬件安装等。软件工程的方法学认为一个独立的程序员不应当脱离团队而进行开发，同时程序的编写不能够脱离软件的需求，设计，以及客户的利益。

软件工程的发展是计算机程序设计工业化的体现。

## 软件开发过程

软件开发过程随着技术进步而持续演进。从早期的瀑布式（Waterfall）开发模型到后来出现的螺旋式迭代（Spiral）开发，以致最近开始兴起的敏捷软件开发（Agile），这些方法论反映了不同时代背景下，软件行业对开发流程的认知深化以及对项目类型的差异化理解。

注意区分软件开发过程和软件过程改进之间的重要区别。诸如像ISO 15504, ISO 9000, CMM, CMMI这样的名词阐述的是一些软件过程改进框架，他们提供了一系列的标准和策略来指导软件组织如何提升软件开发过程的质量、软件组织的能力，而不是给出具体的开发过程的定义。

## 方法学

软件工程的方法有很多方面的意义。包括项目管理，分析，设计，程序的编写，测试和质量控制。

软件设计方法可以区别为重量级的方法和轻量级的方法。重量级的方法中产生大量的正式文档。

著名的重量级开发方法包括ISO 9000，CMM，和统一软件开发过程（RUP）。

轻量级的开发过程没有对大量正式文档的要求。著名的轻量级开发方法包括极限编程（XP）和敏捷过程（Agile Processes）。

根据《新方法学》这篇文章的说法，重量级方法呈现的是一种“防御型”的姿态。在应用“重量级方法”的软件组织中，由于软件项目经理不参与或者很少参与程序设计，无法从细节上把握项目进度，因而会对项目产生“恐惧感”，不得不要求程序员不断撰写很多“软件开发文档”。而轻量级方法则呈现“进攻型”的姿态，这一点从XP方法特别强调的四个准则—“沟通、简单、反馈和勇气”上有所体现。目前有一些人认为，“重量级方法”适合于大型的软件团队（数十人以上）使用，而“轻量级方法”适合小型的软件团队（几人、十几人）使用。当然，关于重量级方法和轻量级方法的优劣存在很多争论，而各种方法也在不断进化中。

一些方法论者认为人们在开发中应当严格遵循并且实施这些方法。但是一些人并不具有实施这些方法的条件。实际上，采用何种方法开发软件取决于很多因素，同时受到环境的制约。

## 软件工程的发展方向

“敏捷开发”（Agile Development）被认为是软件工程的一个重要的发展。它强调软件开发应当是能够对未来可能出现的变化和不确定性作出全面反应的。

敏捷开发被认为是一种“轻量级”的方法。在轻量级方法中最负盛名的应该是“极限编程”（Extreme Programming，简称为XP）。而与轻量级方法相对应的是“重量级方法”的存在。重量级方法强调以开发过程为中心，而不是以人为中心。重量级方法的例子比如CMM/PSP/TSP。

面向方面的程序设计（Aspect Oriented Programming，简称AOP）被认为是近年来软件工程的另外一个重要发展。这里的方面指的是完成一个功能的对象和函数的集合。在这一方面相关的内容有泛型编程（Generic Programming）和模板。

## 相关学科

### 系统工程

系统工程师主要处理系统的整体需求和设计，包括硬件与人力问题。