software-strategy-book/Ch1-4-SoftwareEngineering.tex

278 lines
53 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

% !TEX root = main.tex
\section{软件工程的诞生}
1968年在德国的一个叫做Garmisch的小镇上由北大西洋公约组织NATO科学委员会主导召开了一个小型研讨会有来自11个国家的50位代表参加。会议的议题是如何应对当时面临的所谓“软件危机”\index{软件危机}。在这个研讨会上诞生了“软件工程”这个学科领域~\cite{naur1968software}。这里软件危机是指在所需时间内编写出有用且高效的计算机程序存在很大困难导致软件开发出现许多问题。Dijkstra在其会议报告中提到~\cite{Dijkstra:1972}:软件危机的主要原因是因为机器变得越来越强大,强大了好几个数量级!如果没有计算机,就没有编程问题; 如果只有一些比较弱的计算机,编程就是解决简单的问题,当有了能力巨大的计算机,编程就需要解决同样巨大的问题。软件危机正是因为计算机能支持的计算能力和人对软件的预期,远远超出了程序员开发的软件能够有效利用的能力,以及程序员利用编程手段来驾驭现实问题的能力。
这个研讨会上提到的软件危机有很多种形式,比如软件开发效率低(如,项目超预算,项目时间过长,软件滞后交付),软件质量差(如,很多方面不符合要求),项目难以管理(如,代码难以维护),等等。所讨论的问题,涉及软件开发的方方面面,包括,软件与硬件的关系、软件的设计、软件的生产、软件的分发、以及软件的服务等。这次会议成为软件工程\index{软件工程}学科的奠基性会议所讨论的核心议题也成为软件工程学科经久不衰的开放性挑战问题比如1获取正确的软件需求2设计合适的系统架构3正确和有效地实现软件4验证软件的质量5长期维护具有目标功能和高代码质量的软件系统。
1986 年,布鲁克斯(Brooks) 给出了“软件开发没有银弹”的预言~\cite{Brooks:1987}即由于软件本质上的复杂性在未来10 年内不存在任何技术或方法能够使软件生产力提升10 倍以上。1995 年布鲁克斯在重新发行的《人月神话》纪念版中再次重申“软件开发没有银弹”的预言在下一个10 年仍然成立~\cite{brooks1995the}。布鲁克斯的观点得到了软件开发实践者和研究者的广泛关注和讨论。虽然有学者曾经宣称某项技术或方法有可能成为“银弹”,但实践表明这些技术或方法后来都没有能成为“银弹”。
随着信息技术的发展软件技术的应用范围不断扩大应用领域不断深入50年前的软件和现代软件已经不可同日而语在最初出现软件的时候没有人能预计到现在人们对软件的期望也没有人能想象出通过互联网\index{互联网}和物联网\index{物联网},未来人机物融合\index{人机物融合}系统将会在各类场合服务于广大民众。50年前的核心挑战仍然还是软件工程当前的核心挑战问题的表述几乎没有变化只是被赋予了不同的内涵。“软件开发没有银弹” 的预言仍是软件工程研究者和实践者不可逾越之“墙”。
\section{软件工程内涵和知识结构}
软件工程Software Engineering 是应用计算机科学理论和技术以及工程管理原则和方法,按预算和进度实现满足用户要求的软件产品的工程,或以此为研究对象的学科~\cite{张效祥2005计算机科学技术百科全书}。其主要强调的是,是用\textbf{工程化}\textbf{系统化}的方法进行\textbf{软件开发}~\cite{Laplante:2007}
软件工程关注软件生产各个方面~\cite{IanSommerville:1982},以下广泛流行的说法从不同的角度表述了软件工程的主要关注点,比如:
\hangafter=1
\setlength{\hangindent}{2.6em}
• 系统地将科学知识、方法和经验应用于软件的设计、实施和测试等~\cite{iso2010ieee}
\hangafter=1
\setlength{\hangindent}{2.6em}
• 应用系统的、规范的和可量化的方法开发、运行和维护软件~\cite{ieee1990ieee}
\hangafter=1
\setlength{\hangindent}{2.6em}
• 建立和使用合理的工程原理,以便经济地获得可靠的且在计算机上高效工作的软件。
\hangafter=1
\setlength{\hangindent}{2.6em}
• 软件工程是包含多种过程、以及一系列方法和工具的框架~\cite{pressman2005software}
\hangafter=1
\setlength{\hangindent}{2.6em}
• 软件工程是处理构建大型复杂软件系统的计算机科学领域,这些软件系统如此巨大和复杂,必须要有一组或多组工程师共同构建~\cite{ghezzi2002fundamentals}
\hangafter=1
\setlength{\hangindent}{2.6em}
• 软件工程关注大型程序的构造,协作是大型程序设计的主要机制,中心主题是控制复杂度,管理软件的进化~\cite{van2008software}
从问题求解的角度Dines Bj$\phi$rner对软件工程有独特的理解。他认为~\cite{Dines2010software}理解软件工程需要同时回答“how”如何进行和“what”要做什么。软件工程应该是艺术、规范、工艺、科学、逻辑、和实践的结合首先需要基于科学的洞察去综合即构建和构造软件其次需要分析即学习和研究现有软件技术以探清和发现可能的科学内容。他特别强调的几个与众不同的关注点包括第一软件工程是一门学科它把数学知识加以判断和优化成为数学理论的应用方式目的是1理解问题领域2解决现实问题3为这些通过计算来解决的问题开发计算系统建立软件解决方案第二软件工程应包含三个分支1领域工程\index{领域工程}理解问题领域2需求工程\index{需求工程}理解问题及其解决方案的框架3软件设计\index{软件设计}(实现想要的解决方案)。
综上所述,软件工程要解决的问题是\textbf{如何高效高质地开发出符合要求的产品}。其中包含三个方面的含义。第一,软件工程的产出是一类产品,其产品形态是\textbf{软件},这决定了软件工程学科的研究对象。第二,软件工程需要高效高质地开发出这类产品,工程化是使产品开发得以高效高质的手段,一般依赖于管理有序的\textbf{生产过程},其中要依据合适的\textbf{方法},以及可操作的\textbf{质量保障手段}。这构成了窄义软件工程学科的研究范畴。第三,软件产品要用于解决现实世界的\textbf{领域相关问题},它的使用要能为相关领域带来\textbf{价值},进一步地,对领域价值的评判超出狭义软件工程的范畴,其范畴扩展到了应用领域中,因此,\textbf{领域工程}进入广义软件工程学科范畴,同时,\textbf{需求工程}成为领域工程和狭义软件工程之间的桥梁。
软件工程的内涵可以用图\ref{fig:se1}展示。其核心内容包括领域工程、需求工程和软件系统设计与实现三部分它们形成广义上的软件工程的学科内涵。软件系统设计与实现是其中的主体内容也是软件工程50年来发展最快的部分。所针对的问题是如何高效高质地开发出能胜任的软件系统其知识和技术体系体现在软件工程的方法、过程、质量保障\index{质量保障}及其相应的支撑工具上。这部分内容将在第3节予以描述。
2014年《IEEE SWEBOK Guide》 V3.0提出一个软件工程学科的知识体系~\cite{Pierre2014SWEBOK}其中包括15个知识领域软件需求\index{软件需求}、软件设计\index{软件设计}、软件构造\index{软件构造}、软件测试\index{软件测试}、软件维护\index{软件维护}、软件配置管理\index{软件配置管理}、软件工程管理\index{软件工程管理}、软件工程过程\index{软件工程过程}、软件工程模型和方法、软件质量\index{软件质量}、软件工程职业实践、软件工程经济学\index{软件工程经济学}、计算基础、数学基础和工程基础。这个知识分类体系,除了基础性知识领域外,其它的大部分知识领域可以归属为上述软件系统设计和实现的内容。
值得一提的是相比于传统的工程学科软件工程最大的不同在于它的跨行业性领域工程和需求工程就是解决软件的跨行业性问题包括如何理解所面对的问题领域领域工程和如何理解需要用软件技术来解决的领域问题需求工程。在目前即将进入的人机物融合时代软件工程的跨行业性显得尤为突出这是软件能够渗透进各行各业并通过行业应用体现其价值性的关键。这两部分内容将在第4节中描述。
\begin{figure}[ht]
\centering
\includegraphics[scale=0.3]{fig1-4/fig1.png}
\caption{软件工程学科组成成分}
\label{fig:se1}
\end{figure}
\ref{fig:se1}还列举了与软件工程有适度交叉的学科领域,包括:计算机科学与技术是软件工程的技术支撑。数学提供了软件工程研究,特别是定量研究中所需的数学工具和理论支撑。管理科学和生态学为复杂软件系统的系统化和工程化管理,以及软件开发和应用生态的建立和可持续发展提供指导。系统科学\index{系统科学}是软件工程应对复杂领域问题的系统方法学。在成为信息社会的基础设施后,软件系统还需要遵循或受到各项法律法规的约束。
\section{软件工程设计和实现}
从研究布局角度看,软件系统设计和实现可以分为软件工程方法、软件工程过程、软件质量保障、以及软件工程工具等四个维度。本节分别从这几个维度进行介绍。
\subsection{软件工程方法}
\subsubsection{概述}
软件开发在早期基本上没有可遵循的方法程序员只是根据需要解决的问题按经验直接写代码。M. H. Hamilton是负责早期飞行控制软件Apollo软件的项目开发的根据她的回忆~\cite{hamilton2018errors},当时程序员主要关心的是硬件和软件的关系,以及如何利用这类关系来提升软件的性能。由于没有辅助工具,程序员最担心的是代码出错,需要不断地花时间进行手工调试。
总结早期飞行控制软件开发经验M. H. Hamilton设计了通用系统语言Universal System Language, USL~\cite{hamilton2008universal}其灵感来自她对Apollo软件开发过程中出现的错误模式/类别的认识。当时子系统间的接口错误占了软件错误的绝大部分而且这些错误通常是最难找到和调试正确的。USL给出了不同接口错误类别的定义通过这些系统定义来识别错误并在系统设计的时候预防它们。 USL定义的六个公理形成了控制逻辑的数学构造性理论的基础。
随着软件开发经验的不断积累人们越来越多地研究软件工程方法以指导软件设计和实现目的是使软件开发具有系统性并成为系统化可重复的过程从而提高软件开发的成功率。50年来随着软件解决的现实问题不断深化软件工程方法不断地出现并得以发展比如从系统的功能设计和实现角度出发的结构化方法从面向现实世界问题中实体关系角度出发的面向对象方法以及从面向现实世界问题求解角度出发的非功能性分析和设计方法等软件工程方法的蕴含面不断向现实世界发展。
如同本书第一章中阐述软件发展的核心是管理复杂性软件工程的目标则是控制复杂性。这在系统实现层表现为“模块化封装”在系统设计层表现为“结构化抽象”在问题分析层表现为“关注点分离”。这在早期的一些代表性工作中就有所体现比如1970年代末兴起的模块互联语言\index{模块互联语言}Module Interconnection Language简称MIL就是一种结构化系统设计语言~\cite{prieto1986module},它提倡软件系统由相互联结的模块组成,提供形式化手段刻画模块间的各种联接关系,形成系统规格说明,以支持系统完整性和模块间兼容性等的验证。还有各种体系结构描述语言\index{体系结构描述语言}Architecture Description Language简称ADL就是在接近系统设计者直观认识的抽象层次上描述软件系统的结构是软件系统高层结构的概念模型~\cite{Taylor2009SoftwareArchitecture}
软件开发的效率和质量一直是软件工程追求的目标,基于构件的方法尝试采用大规模复用\index{复用}的手段,提高软件的开发效率,以及提升所开发的软件的质量。面向服务的方法则将其它软件提供的服务作为可复用的构件,软件系统通过复用并无缝集成来自不同提供方的服务来获得。除此之外,还有其它软件开发和软件工程模式,比如开源软件\index{开源软件}开发以及敏捷开发\index{敏捷开发}等,它们都从不同的角度来应对软件开发问题,解决软件危机,尝试找到软件开发的“银弹”。
\subsubsection{结构化系统分析和设计方法}
结构化系统分析和设计方法\index{结构化系统分析和设计方法}起源于20世纪70-80年代是一种用于分析和设计信息系统的瀑布方法结构化分析以分层数据流图\index{数据流图}和控制流图\index{控制流图}为工具来开发系统的功能模型和数据模型。结构化设计包括软件体系结构设计、过程功能设计和数据设计。早期比较有代表性的包括P. Checkland和J. Scholes的软系统方法~\cite{peter1990soft}E. Yourdon和L. Constantine的结构化设计~\cite{yourdon1979structured}E. Yourdon的Yourdon结构化方法~\cite{yourdon1989modern}M. Jackson的Jackson结构化编程~\cite{jackson1975principle}和结构化设计~\cite{jackson1983system}以及Tom DeMarco的 结构化分析~\cite{demarco1979structure}等,结构化系统分析和设计方法由这些不同流派的方法综合而成。其中倡导的多种建模技术目前仍然是软件系统数据建模和分析的重要技术:
\hangafter=1
\setlength{\hangindent}{2.6em}
• 逻辑数据建模:识别和记录被设计系统的数据需求。包含实体(业务处理需要记录的信息),属性(与实体相关的事实)和关系(实体间的关联)。建模结果为实体关系模型。
\hangafter=1
\setlength{\hangindent}{2.6em}
• 数据流建模:识别和记录被设计系统中的数据流动。包括数据处理(即将一种形式的数据转换为另一种形式的活动),数据存储(数据存留点),外部实体(将数据发送到当前系统或从系统接收数据的外部系统)和数据流向(数据通过什么路由流动)。建模结果为数据流模型。
\hangafter=1
\setlength{\hangindent}{2.6em}
• 实体事件建模:包括实体行为建模和事件建模,实体建模识别和记录影响每个实体的事件以及事件发生的序列(形成实体生命周期);事件建模则针对每个事件记录其实体生命周期的作用。建模结果为实体生命周期和事件效果图。
\subsubsection{面向对象分析和设计方法}
面向对象分析和设计方法\index{面向对象分析和设计方法}起源于20世纪90年代早期也有不同的面向对象方法较有代表性的包括G. Booch等的Booch方法~\cite{booch1993object}J. Rumbaugh等的OMT方法~\cite{rumbaugh1991object,}I. Jacobson等的OOSE方法~\cite{jacobson1992object,}。由于这三种不同体系下形成的软件制品彼此间难以复用如何形成能够支撑从需求到实现的软件行业标准成为当时亟需解决的问题。1994年他们共同开发了统一建模语言UML\index{统一建模语言UML}~\cite{jacobson1998the}并由对象管理组织OMG\index{对象管理组织OMG}发布还集成其他相关见解和经验形成统一软件开发过程RUP\index{统一软件开发过程RUP}~\cite{krechten1998rational},是当时最流行的方法和参考模型,并成为全面迭代和增量过程的指南和框架,也是软件开发和项目管理的最佳实践。
面向对象分析和设计方法以对象和对象关系等来构造软件系统模型,其中,对象由封装的属性和操作组成。对象类是具有相似属性、操作和关系的一组对象的描述。因此,对象类成为系统建模、系统设计以及实现等活动可复用的基本单元。面向对象分析和设计方法强调“开闭原则”\index{开闭原则}(即对扩展开放、对修改封闭),其目的是希望软件尽量以扩展新的软件实体(如类、方法等)而非修改已有的软件实体的方式实现所需的变化,从而降低代码修改相关的风险并保证软件的可维护性。
可以看出,结构化系统分析和设计是将过程和数据分开考虑形成过程抽象,而面向对象分析和设计则关注从问题领域中识别出对象,并围绕这些对象来组织系统需求,通过对象集成系统行为(流程)和状态(数据),形成数据抽象。在设计阶段,面向对象分析和设计方法侧重于将实现约束作用在分析过程中得到的概念模型上,比如硬件和软件平台,性能要求,持久存储和事务,系统的可用性以及预算和时间所施加的限制等,分析模型中与技术无关的概念被映射到类和接口上,进而得到解决方案域的模型,强调利用架构模式\index{架构模式}和设计模式\index{设计模式}等指导软件体系结构的设计~\cite{gamma1994design}
\subsubsection{基于构件的方法}
早在1968年的NATO软件工程会议上Doug Mcllroy就在“大量生产的软件构件”一文中提出了大规模软件复用的思想~\cite{naur1968software}。在足够的软件资产形成之后,人们希望能充分利用这些可复用的软件资产,以提高软件生产率和软件质量~\cite{杨芙清1999软件复用与软件构件技术}。早期的软件复用对象主要是各种函数库,例如美国自然科学基金会组织构建的数学函数库。随后,面向对象分析和设计方法中所使用的类,由于其具有良好的封装性并与客观世界实体具有良好对应关系的特性,成为一种主流的软件复用对象。
特别是随着CORBA\index{CORBA}、EJB\index{EJB}、COM/DCOM\index{COM/DCOM}等软件构件标准的成熟和广泛应用,基于构件的方法成为系统化的基于复用的软件开发方法。这种方法以软件构件作为基本的复用对象,将软件构造从传统以软件编码工作为主的方式转换为以软件构件集成和组装为主的方式。这里,构件\index{构件}是指软件系统中具有相对独立功能、可以明确辨识、接口由契约指定、和语境有明显依赖关系、可独立部署、且多由第三方提供的可组装软件实体~\cite{张效祥2005计算机科学技术百科全书}
与函数和类等复用单元相比,软件构件由于其具有多个方面的特性,更适合作为一种系统化的软件复用对象。一方面,软件构件一般粒度较大,实现了相对完整的业务功能,按照某种构件标准进行了良好的封装并且可以独立部署。另一方面,软件构件具有明确的构件描述、环境依赖和接口规约,用户通过构件描述查找构件并理解其使用方式,根据环境依赖对其进行部署和配置,同时按照接口规约请求构件的服务。此外,为了实现良好的可复用性,软件构件还应具有较好的通用性和质量,易于组装并提供完善的文档和复用样例。
基于构件的方法包括构件的识别和开发、构件描述和管理、基于构件的应用开发三个方面。构件的识别和开发针对特定业务或技术领域的共性需求和技术问题进行分析,从中识别并抽象出可复用构件,并按照特定构件标准进行实现和封装。构件描述和管理对软件构件进行描述、分类、存储,并提供构件发布版本管理和检索机制,通过建立软件构件库对外提供统一的构件上传、更新、检索等服务。基于构件的应用开发根据应用软件的需求检索并获取可复用构件,对其进行定制和适配,然后从软件体系结构描述出发实现构件的组装,从而实现应用软件的需求。
构件技术的发展还催生了商用成品构件Commercial Off-The-Shelf简称COTS\index{商用成品构件COTS}的出现,例如在信息系统中有着广泛应用的报表构件、文档处理构件等。商用成品构件一般都符合特定的构件标准并具有良好的可组装性,由独立的构件开发厂商提供,应用开发厂商通过购买获得构件使用权,并通过黑盒的方法进行组装和复用。
\subsubsection{面向服务的软件开发方法}
随着基于Internet的应用的延伸面向服务的计算Service-Oriented ComputingSOC应运而生其目的是有效解决在开放、分布、动态和异构环境下数据、应用和系统集成的问题。面向服务的软件开发方法~\cite{Papazoglou2007SOC}通过组合可复用的服务实现软件系统的开发主要关注如何按需、动态地集成现有的服务从而快速开发出满足新需求的软件系统。服务提供者和服务使用者之间的交互关系具有动态特性服务公开性Exposure和反射性Reflection替代了传统的固定式系统集成开发软件系统时是根据系统的需求进行服务装配与组合。此外服务的松耦合改变了传统以APIs调用进行组件组装的紧耦合方式系统架构师可以通过动态描述组合服务集合来创建软件系统。
面向服务的开发方法包括以下内容1 面向服务的分析和设计以服务为中心根据业务需求识别服务、描述服务并设计服务的实现2 面向服务的开发过程结合现有开发过程规划以服务为中心的开发过程中的角色、职责、活动和工件3 面向服务架构的成熟度分析和迁移路线以服务为中心分析现有或目标系统的成熟度并设计从现有成熟度迁移到目标成熟度的路线以及4面向服务架构的监管设计组织和流程确保面向服务架构的设计原则在IT生命周期中得以贯彻管理服务生命周期中各种迁移的合理性等。
面向服务的开发方法并不是全新的方法学,它是已有方法学的继承和发展。一方面,已有的方法学不能解决服务概念引入带来的问题,如如何识别服务,如何定义服务等;另一方面,服务是一个水平而不是垂直概念。在服务分析和设计的过程中,需要处理面向服务的开发方法和现有方法学的关系,服务的分析和设计的主要职责在于识别服务、定义服务和实现服务,并指导如何和其他方法学相结合。对面向服务的开发方法而言,在原理层面很多已有的设计原则,如抽象、关注点分离等都被面向服务的方法继承和发扬,并应用于服务的定义和实现中;而在操作层面上,服务模型为面向对象的开发进行类和对象设计提供了业务蓝图和企业架构蓝图。
% \subsubsection{基于搜索的方法}
% 基于搜索的方法并不是一种系统性的软件工程方法只是一类软件工程任务可以建模为计算搜索、组合优化问题基于搜索的方法是专门用来解决这类软件工程任务的。这类工作最早出现在1976年Webb Miller 和 David Spooner尝试把优化算法用于浮点测试数据的生成~\cite{miller1976automatic}。1992年Xanthakis等将搜索算法用于解决软件测试问题~\cite{xanthakis1992application}。2001年Harman 和 Jones正式提出基于搜索的软件工程~\cite{harman2001search}。
% 一般意义上说,基于搜索的方法是从问题的解空间出发,将软件工程任务转换为计算搜索任务,使之能使用元启发式搜索优化算法来处理,其中涉及定义搜索空间或可能的解决方案,使用度量函数(即适应度函数)来测量潜在解决方案的质量,从而实现软件工程任务的自动化和智能化。基于搜索的方法适可用于软件开发和维护过程的很多阶段,其中在软件测试过程中应用最多,其他任务还包括,需求分析,软件设计,软件开发和维护等。
\subsection{软件工程过程和过程管理}
软件工程师开发和维护软件,需要完成一系列的活动,比如需求、设计、构造、测试、配置管理等。软件开发过程就是为了实现事先确定的目标而组织起来的一组活动,这组活动间有一定的先后顺序,作为一个整体来实现事先确定的目标。其目标包括软件项目管理要实现的目标,比如,完成开发任务、控制成本和工期、达到质量要求等。将软件的开发和维护分解成这样一组活动,是为了便于管理。软件过程管理的管理对象就是软件过程,管理的直接目的是为了让软件过程在开发任务的完成、完成的效率和质量等方面有更好的性能绩效。
\subsubsection{系统生命周期}
系统生命周期\index{系统生命周期}是系统存在的所有阶段的一个视图,软件系统也具有这样一个视图,包括概念设计阶段、设计和开发阶段、生产和构建阶段、部署和运行阶段、维护和支持阶段、退役和淘汰阶段等。
概念设计阶段确定系统需求,并定义潜在解决方案,评估潜在解决方案并开发系统规约,为系统设计提供技术要求和开发指导。设计和开发阶段,按照系统规范,进行所需系统功能的所有子系统的设计,定义子系统间的接口,以及系统整体测试和评估的要求,生成可操作的详细设计和开发规范。详细设计和开发阶段细化初始的系统规范,产生系统与其预计交互环境的接口规范,以及对系统维护和支持要求的综合评估。
生产和构建阶段,产品将按照系统规范中规定的要求开发或实现,并在目标环境中进行部署和测试,进行系统评估以纠正缺陷并使系统适应持续改进。完全部署后,系统将用于其预设的操作环境中,期间需要不断评估系统的有效性和效率,以确定产品已达到其最大有效生命周期。 考虑因素包括:持续存在的运营需求,运营要求与系统性能之间的匹配程度,系统淘汰与维护的可行性以及替代系统的可用性等。
对应系统的生命周期,有多种系统开发生命周期模型,几种典型的包括如瀑布模型(图\ref{fig:se2}(a))、迭代模型(图\ref{fig:se2}(c))、螺旋模型(图\ref{fig:se2}(b))以及基于构件复用的过程模型(图\ref{fig:se2}(d))等~\cite{张效祥2005计算机科学技术百科全书}
\begin{figure}[ht]
\centering
\includegraphics[scale=0.3]{fig1-4/fig2.png}
\caption{典型的过程模型}
\label{fig:se2}
\end{figure}
\subsubsection{软件过程管理}
软件过程是为实现事先定义的目标而建立起来的一组事件的集合。软件过程也有广义和狭义之分,狭义的软件过程只单纯涉及流程,就是一组有先后顺序的活动,即流程。广义的软件过程中,其事件涉及三个维度,技术、人员和流程,流程是其中最重要的一维,它是连接技术和人员的粘合剂。只有技术、人员及流程三者融为一体,软件过程才能在软件开发中真正起到指导作用。
软件过程与软件生命周期\index{软件生命周期}紧密相关,一个软件过程既可以覆盖从需求到交付的完整的软件生命周期,也可以仅包括其中某些特定开发阶段。例如,一个实现过程就只包括详细设计、编码、代码评审、编译以及单元测试\index{单元测试}等更为细小的开发步骤。为了确保代码评审工作的质量,也可以进一步定义、管理和改进代码评审过程。
软件过程管理就是对软件过程的管理包括软件过程的建立、执行、监控、评估以及改进等活动。其管理的依据是从众多软件开发活动的经验教训中总结而成的可供参考的模型。最著名的软件过程管理参考模型是能力成熟度模型CMM\index{能力成熟度模型CMM}以及其后续的能力成熟度集成模型CMMI\index{能力成熟度集成模型CMMI}~\cite{chrissis2003cmmi}
\subsubsection{敏捷软件开发}
1990年代有很多批评是针对一些僵化的对软件工程的过度监管、计划和微观管理等重量级方法许多轻量级方法得以发展其中包括快速应用开发RAD以及其它一些技术包括统一过程UP和动态系统开发方法DSDMScrum、Crystal Clear和极限编程XP特征驱动开发等。
2001年17位软件开发人员\footnote{Kent BeckWard CunninghamDave ThomasJeff SutherlandKen SchwaberJim HighsmithAlistair CockburnRobert C. MartinMike Beedle Arie van BennekumMartin FowlerJames GrenningAndrew HuntRon JeffriesJon KernBrian Marick和Steve Mellor。}讨论这些轻量级开发方法,随后发布了“敏捷软件开发宣言”,包含如下十二项原则\footnote{Principles behind the Agile Manifestohttp://agilemanifesto.org/principles.html}1通过尽早和持续交付有价值的软件来实现客户满意度2即使在项目后期也要拥抱不断变化的要求3经常性地按周而不是按月提供可工作的软件4业务人员和开发人员密切合作5项目围绕带有动机目的的人建立他们要得到信任6面对面交谈是最好的沟通方式7可工作的软件是项目进展的主要衡量标准8可持续地向前推进保持稳定的步伐9不断关注技术进展和良好设计10简单性 - 最大化未完成工作量的艺术 - 至关重要11最好的架构、要求和设计来自自我组织的团队12团队经常性反思如何变得更有效并据此进行相应地调整。
总之,敏捷软件开发通过自组织和跨职能团队及其客户/最终用户的协作努力使需求和解决方案不断演化发展的方法它倡导适应式规划、演化式发展、尽早交付和持续改进同时鼓励快速应变和灵活反应。实际上迭代增量开发可追溯到1957年~\cite{larman2003iterative},而演化式项目管理~\cite{gilb1981evolutionary}和自适应软件开发~\cite{edmonds1974process}也早在70年代就已经出现。他们都早于敏捷宣言并都被包含进敏捷软件开发方法。
\subsection{软件质量保障}
软件是一种人工制品需要有相应的质量保障Software Quality Assurance, SQA机制包括监控软件工程过程以确保质量。软件质量保障涵盖整个软件开发过程包括需求定义、软件设计、编码、源代码控制、代码审查、软件配置管理、测试、发布管理和产品集成等。
\subsubsection{软件质量体系}
软件质量是反映软件系统或产品满足明确或隐含需求能力的特性的总和。有四个方面的含义: 其一,能满足给定需要的特性的全体;其二,具有所期望的各种属性的组合的程度;其三,用户觉得能满足其综合期望的程度;其四,软件的组合特性,它确定软件在使用中将满足顾客预期要求的程度。软件质量常常用下列特性来评价:
\begin{itemize}
\item 功能性:当软件在指定条件下使用时,软件产品提供满足明确和隐含需求的功能的能力。
\item 可靠性:在指定条件下使用时,软件产品维持规定的性能级别的能力。
\item 易用性:在指定条件下使用时,软件产品被理解、学习、使用和吸引用户的能力。
\item 效率:在规定条件下,相对于所用资源的数量,软件产品可提供适当性能的能力。
\item 易维护性:软件产品可被修改的能力。修改可能包括修正、改进或软件对环境、需求和功能规格说明变化的适应。
\item 易移植性:软件产品从一种环境迁移到另外一种环境的能力。
\end{itemize}
软件质量度量是用于确定软件系统或产品特性的定量尺度Boehm等人于1976年提出了定量评价软件质量的概念提出了60个质量度量公式首次提出了软件质量度量的层次模型。1978年Walters和McCall提出了从软件质量要素、准则到度量的三层式软件质量度量模型将质量要素降到11个。
\subsubsection{软件质量标准}
国际标准化组织于1985年建议的质量度量模型分为三层高层——软件质量需求评价准则中层——软件质量设计评价准则低层——软件质量度量评价准则。在1991年国际标准化组织(ISO)和国际电工委员会(IEC)又共同提出了标准给出了6个特性和21个子特性于2001年再次修订标准建立了软件产品质量的两分模型1内部质量软件产品在特定条件下使用时软件产品的一组静态属性满足明确和隐含需要的能力和外部质量系统在特定条件下使用时软件产品使得系统的行为能满足明确和隐含需要的能力2使用质量在特定的使用场景中软件产品使得特定用户在达到有效性、生产率、安全性和满意度等方面的特定目标的能力
还有一系列标准用于监控和评估软件生产过程过程以支持软件质量的提升ISO/IEC 15504\footnote{https://www.iso.org/standard/38932.html}其第一个版本专注于软件开发过程后来扩展到涵盖软件业务中的所有相关流程例如项目管理配置管理质量保障等是成熟度模型的参考模型评估者可以根据模型在评估期间收集证据全面确定所开发产品软件系统和IT服务的能力。其更新版本是ISO/IEC 33000\footnote{https://www.iso.org/standard/54175.html}。其它质量标准还包括ISO/IEC 25000\footnote{https://www.iso.org/standard/64764.html}、ISO/IEC/IEEE 29119\footnote{https://www.iso.org/standard/45142.html}等。
\subsubsection{形式规约和验证}
除了采用工程方法来组织、管理软件的开发过程,并根据标准检验过程的正确性外。还有一类工作就是深入探讨程序和程序开发过程的规律,建立严密的理论,以其用来指导软件开发实践,这类工作推动了形式化方法的深入研究,其目标是以严格的数学推演为基础,通过对系统的形式规约、验证和逐步精化来构造并实现软件,从而提高软件设计的可靠性和鲁棒性。其中,形式规约是使用形式语言构建所开发的软件系统的规约,对应软件生命周期不同阶段的制品,刻画系统不同抽象层次的模型和性质。形式化开发就是构造并证明形式规约和形式模型之间的等价转换和精化关系,以系统的形式模型为指导,通过逐步精化,最后开发出满足需要的系统,也称为保证正确性的构造(Correctness by Construction)。
\subsubsection{软件分析和软件测试}
软件分析和软件测试是软件开发实践中常用的质量保障手段,被广泛用于发现软件需求、设计、实现代码等制品中的缺陷或验证相关性质。
软件分析是指对软件制品进行人工或者自动分析,以验证、确认或发现软件性质(或者规约、约束)的过程或活动~\cite{梅宏2009软件分析技术进展}。软件分析的对象覆盖了文档、代码(源代码或二进制代码)、运行中的系统、开发历史等不同形态,相应的分析技术也包括静态分析、动态分析和开发历史分析等。其中,静态分析在不运行程序的情况下,对文档和代码进行分析,抽取各种性质及抽象表示并对各种问题进行检查;动态分析通过程序插装等手段获取程序的运行时信息,在此基础上对程序的行为进行分析;开发历史分析对软件版本库等开发库中所记录的开发历史进行分析,获得与软件演化历史相关的各种信息。软件分析可以直接发现各种软件制品中的缺陷和问题,例如不一致的需求描述、被违反的设计原则、代码坏味道、潜在漏洞和缺陷等。其中,针对代码的静态分析是主要的软件分析手段,涉及语法分析、类型分析、数据流/控制流分析等基本分析技术,符号执行、切片分析等辅助分析技术,以及克隆分析、规范检查、漏洞扫描等针对特定目的的分析技术。
软件测试通过人工或自动的方式运行被测试的软件,检验其运行结果或行为是否与预期相符,其目的是发现软件中潜在的错误和问题。测试应当经过设计,并在测试用例的驱动下进行。测试用例一般包括输入、环境配置、测试步骤和期望输出。软件测试可以在不同层次上进行,包括单元测试\index{单元测试}、集成测试\index{集成测试}、系统测试\index{系统测试}和验收测试\index{验收测试}。此外,在软件进行修改后为确认修改未引入新的错误还需要重新运行相关的测试用例,即进行回归测试\index{回归测试}。软件测试的基本过程包括测试计划、测试用例设计、测试执行、测试结果分析等步骤。其中,测试用例设计是关键,一方面要确保对软件运行过程中的各种可能性有较高的覆盖度,另一方面要限制测试用例数量以节省测试时间和成本。相应的测试用例设计方法主要包括白盒测试\index{白盒测试}和黑盒测试\index{黑盒测试}两类,同时与各种测试用例选取和排序等辅助技术相结合。为了缩短测试时间、节省测试成本,自动化测试技术受到了很大关注,包括自动化的测试用例生成、执行和结果分析。
\subsection{软件工程工具}
软件工程工具,或软件工具,是用来辅助计算机软件的开发、运行、维护、管理、支持等过程中活动或任务的一类软件。早期的软件开发所用到的引导程序、装入程序、编辑程序等都可以看作是最早的软件工具。在汇编语言和高级程序设计语言出现以后,汇编程序、解释程序、编译程序、连接程序和排错程序构成了早期的软件工具集。在软件工程出现后,支持软件需求分析、设计、编码、测试、维护和管理等活动的软件工具逐渐发展起来,从各个阶段支持着软件开发过程,并且自然而然出现了工具集成的需要,使得各个工具能够协同操作。
软件开发环境由软件工具和环境集成机制构成,是支持软件产品开发的软件系统~\cite{张效祥2005计算机科学技术百科全书}。软件开发环境在工具集成的需求中开始萌芽上世纪70年代中后期出现了软件工具箱Toolkit的思想在软件开发过程中使用成套的多个软件工具。80年代起出现了支持图形设计方式的第二代软件工具和集成这些工具为一体的软件开发环境采用环境信息库支持软件开发模型和开发方法并且集成机制有了较大发展。90年代开始出现支持面向对象方法和技术的软件开发环境。我国“七五”“八五”“九五”科技攻关中研制的青鸟软件开发环境\index{青鸟软件开发环境},是当时先进的软件开发环境,具有较为完善的集成化软件开发支撑能力。
21世纪以来随着互联网和移动通信的普及软件工具和软件开发环境的用途和种类进一步拓展出现了支持软件国际化、软件开发协同工作、开源软件库和开源社区环境以及支持互联网、物联网和云计算的基础软件和应用测试支撑工具。软件开发环境不仅支持时间上的松耦合开发还支持空间上的分布开发并且开始以协同开发思想为基础更强调多相关方、多工具、多活动的协同开发支撑使得软件产品相关的所有利益相关方能在互动的软件开发协作过程中实现包括需求管理、项目管理、软件部署和运行监控等活动在内的完整的软件生存周期过程支撑。
随着软件形态的演化和软件开发方法的发展,软件工具和软件开发环境正在功能智能化、网络化、服务化方向发展,并且对软件开发过程的可视化管理和定量分析优化提供支持。
\subsubsection{软件开发工具}
早期的软件开发工具仅限于汇编器和编译器。20世纪五六十年代随着Fortran、Basic等高级语言的出现计算机程序逐步脱离了面向特定硬件系统的束缚更加接近于自然语言而易于开发人员书写。开发人员使用文本编辑工具编写代码后使用代码解释或编译工具将源代码转换为操作系统可以识别的代码进而实现预期的程序行为。广义上来说文本编辑器、汇编器、编译器都可以看作最原始的软件开发工具。
随着软件开发过程的成熟以及软件开发技术的发展,软件开发工具开始在基本的代码编辑和编译功能基础上提供代码元素高亮、即时语法检查和提示、调试等辅助功能,同时针对编码之外的软件开发活动的支持工具也不断涌现,主要包括以下几种类型。
\begin{itemize}
\item 分析和设计建模工具在规范化的建模语言基础上通过图形化的建模工具支持软件的需求分析和设计建模例如广泛使用的ER模型和UML建模工具等
\item 测试工具:针对单元测试、集成测试、性能测试等不同种类的测试所提供的测试用例生成、测试环境模拟、测试执行与测试结果分析等方面的工具支持;
\item 分析和验证工具:针对软件代码、模型等软件开发制品进行自动化分析和验证,发现潜在的质量问题或确认所期望的属性,例如各种代码缺陷检查工具、形式化验证工具等;
\item 逆向分析和度量工具:针对源代码或二进制代码进行逆向分析以恢复软件的高层视图从而辅助理解,或者度量代码的各种属性以获得关于代码质量的信息。
\end{itemize}
\subsubsection{软件运维工具}
软件的运行和维护是软件交付后的必要环节。在以桌面应用为主的上世纪90年代以前软件产品要么以商业成品Commercial-off-the-shelf形式提供给最终用户要么以商用服务项目的形式在客户现场On-site提供支持。此时软件的运维主要是软件日志的收集与分析。通常只能通过现场日志的分析获知软件的可能问题进而在开发环境中进一步测试、验证、修改软件以修复相关问题。在这种模式下软件运维工具往往并不受重视并且通常是融合在软件开发工具中的即需要通过软件开发过程中写入必要的日志信息才能实现必要的运行维护工作。随着互联网应用和应用的服务化进程的开启21世纪以来服务化和云化的软件使得软件运维从客户端现场支持逐步转向后端、云端。此时的软件运行具有在线动态地特性不仅需要运行时的日志记录与分析还需要能快速响应特定的运行问题并快速给出维护方案、上线修复的软件产品。软件运维从简单的运行日志分析和调错逐步向实时监控、快速响应的反向发展这也带来了开发运维一体化DevOps\index{开发运维一体化DevOps}的兴起。由此软件运维工具范围迅速扩大形成了涵盖开发、构建、测试、集成及交付、容器平台等个子领域的工具集。例如自动化构建是持续集成的重要支撑支持持续集成的工具包括开源工具Jenkins、商用工具Bamboo以及商用开源版本并存的Travis等。这些工具的特性分别适应特定的应用群体或用户运维人员可实现多种运维工具的按需选择。
\subsubsection{软件管理工具}
软件管理工具特指在软件开发过程中使用的不直接产出软件中间制品或最终制品的辅助工具。软件管理工具主要面向软件开发管理人员同时也服务于软件开发活动所有参与者。这些辅助工具包括项目进度管理工具如MS Project、软件版本管理工具如SVN、Git、ClearCase、在线细粒度任务安排和看板工具等对软件开发过程、制品进行。从软件工程概念提出依赖采用工程化的管理手段使得软件的开发过程变得可见、可控、可度量、可预测是这些工具的终极目标之一。这些工具随着软件工程学科发展和研究内容的变化而不断改进新的工具不断涌现体现了软件工程学科的活力。例如随着敏捷方法被软件工程实践逐步接受以软件工具形式出现的看板软件也发展起来开始作为传统的物理看板的补充在异地分布式团队等场景中广泛地使用。尽管目前此类软件仍然存在诸如易用性、可配置性等缺陷但作为新兴的软件工程工具若能通过触摸交互式高分辨率显示等技术改进实现随时随地的交互那么对精准高效地管理团队内部人员的开发进度、协调团队交互沟通都会具有非常重要的价值应用前景非常广阔。
\section{需求工程和领域工程}
当软件变得复杂,需要对软件的需求进行分析,以此构造综合性的问题求解方案,当软件系统变得更加复杂,则需要有一整套的过程和相应技术,指导和帮助软件开发人员系统化地进行用户的需求识别和分析,确定软件能力需求,从而构造问题场景的整体的解决方案。从而出现独立的研究方向:需求工程~\cite{pohl2010requirements}。需求工程有三个关注点:环境(可改进点)、期望需求(关注的改进方面)和软件系统需求(可实现性)。
简单说,需求工程就是:现实世界中存在需要解决的问题、可改进的地方、或者可能蕴含的机会等,然后在圈定的范围内认知并明确刻画出想要解决的问题,最后依据当前可行的信息技术手段,设计出问题求解的方案,并认证该解决方案的可行性和有效性。因此需求工程的主要任务就是观察现实世界机会、识别和定位现实需求、分析和建模软件需求、验证和管理软件需求等。
由于需求工程的出发点是观察现实世界并进行问题识别,根据现实世界问题识别的不同角度,出现了不同的需求工程方法,主要的需求工程方法包括:面向目标的方法~\cite{van2009requirements}、面向主体和意图的方法 ~\cite{yu20101}、面向情景的方法~\cite{sutcliffe2003scenario}、问题框架方法~\cite{jackson2001problem}等。这些方法的特点和需求工程技术见表~\ref{table:chapter4-1}所列。
\begin{table}
\centering
\scriptsize
\caption{代表性需求工程方法}
\label{table:chapter4-1}
\begin{tabular}{|p{0.07\textwidth}<{\left}|p{0.2\textwidth}<{\left}|p{0.3\textwidth}<{\centering}|p{0.3\textwidth}<{\centering}|}%
\hline
方法& 问题视角& 需求建模原则& 软件需求获取手段\\
\hline
面向目标的方法& 现实世界中存在新的需要达成的业务目标& \makecell[l]{ • 识别高层目标\\
• 自顶向下,按照业务目标\\ \protect\quad 实现策略进行目标分解,\\ \protect\quad 直到获得可操作目标}
& \makecell[l]{• 可操作目标的可实现性分析\\
• 自底向上的逐层目标可满足\\ \protect\quad 性分析\\
• 目标冲突的检测和协商}
\\
\hline
面向主体和意图的方法& 现实世界存在需要维系的自治个体/组织的关系& \makecell[l]{• 个体/组织间依赖关系识别\\
• 个体/组织策略的目标建模\\
• 个体/组织的反依赖关系以\\ \protect\quad 及反依赖关系应对策略
}& \makecell[l]{• 依赖关系的可满足性和鲁棒\\ \protect\quad 性分析\\
• 依赖路径的脆弱性分析\\
• 反依赖关系的防御
}\\
\hline
面向情景的方法& 现实世界中的业务流程需要自动化支撑& \makecell[l]{• 现实场景抽象和模。\\
• 现实场景模型脆弱点分析\\ \protect\quad 和改进点确定,如活动改\\ \protect\quad 进和流程改进。\\
• 改进策略确定
}& \makecell[l]{• 场景流合理性分析\\
• 场景流可行性分析\\
• 场景流资源/环境依赖性\\ \protect\quad 分析\\
• 场景流最优化分析
}\\
\hline
问题框架方法& 软件处于环境中,软件的能力需求由需要和环境进行的交互决定& \makecell[l]{• 识别软件上下文(环境)\\
• 抽象环境实体的特征\\
• 在环境实体上确定用户\\ \protect\quad 需求,以此确定软件与环\\ \protect\quad 境实体的交互\\
• 根据交互特征识别问题\\ \protect\quad 框架
}& \makecell[l]{• 构建上下文图。环境实体\\ \protect\quad 识别\\
• 构建问题图。基环境实体于\\ \protect\quad 确定用户需求,系统/环境\\ \protect\quad 交互识别\\
• 进行问题投影。子问题识\\ \protect\quad 别,基本问题框架匹配
}\\
\hline
\end{tabular}
\end{table}
领域工程是支持软件开发中全面系统化复用领域知识的过程。其出发点是,大多数软件系统都不是全新的系统,领域工程可以通过使用同领域相似系统的模型和代码,提高新软件的开发效率和质量,从而降低成本。领域工程面向特定领域捕获和收集可复用的软件制品,以便在与之相似的应用工程中复用。
领域工程可以分为分析、设计和实现三个阶段。领域分析侧重于识别和定义领域,并生成领域模型。领域分析的来源是某领域过去产生的制品,包括现有系统及其如设计文档,需求文档和用户手册等制品。领域分析的目标是将根据已知的领域知识进行扩展,通过领域特征建模,识别领域的公共特征,以及存在的差异性,从而支持领域需求的可配置性。领域设计根据领域分析阶段生成的领域模型,产生领域中所有系统都能符合的通用系统架构模式,并确定模式的范围以及与模式相关的上下文,以适当限定架构适用的范围。最后领域实现是创建为能有效生成本领域客户化软件使用的过程和工具。
软件产品线\index{软件产品线}工程是具有代表性的领域工程以产品特征建模为基础又称面向特征的复用。例如FORM~\cite{kang1998form}是具有代表性的领域工程方法,它首先分析特定领域中应用程序在服务、操作环境、领域技术和实现技术等方面共性的或者差异性的功能特征。这个分析过程构建出来的模型被称为特征模型\index{特征模型}。该模型则可用于定义参数化参考体系结构和在实际应用程序开发时可实例化的适当的可复用构件。支持开发可复用的体系结构和构件,并支持使用领域工程生成的领域制品开发应用程序。
\section{结束语}
综观软件工程的起源和发展,可以发现,软件成为独立存在的人工制品,因此需要一种系统化的方法以及相应的技术,第一使得这种人工制品的功能能满足应用需求,第二使得其开发和生产能高效地完成,第三能提供手段以保证其质量。因此软件工程的发展总是围绕需求、软件方法学和软件开发技术、以及软件质量体系和保障等几个方面展开,这形成了软件工程学科的内涵。
但是,软件又和其它人工制品不同,它在需求和表现形式上具有极大变化性,它承载在看上去非常容易修改的代码上,随着软件和物理设备以及人的越来越深度的融合,通过软件作为核心支撑来解决的问题也越来越复杂。这也使得软件工程方法和技术不断面临新的挑战,面对的问题(需求)越来越复杂、软件操作的交互对象越来越多样,人们寄予越来越高的可靠性等等,这些是软件工程方法和技术发展的不竭动力。