246 lines
46 KiB
TeX
246 lines
46 KiB
TeX
% !TEX root = main.tex
|
||
|
||
%\section{引言}
|
||
|
||
《计算机科学技术百科全书》中对软件给出了如下描述~\cite{张效祥2005计算机科学技术百科全书}:
|
||
\begin{center}
|
||
\begin{minipage}{.8\textwidth}
|
||
\kaishu 细言之,软件一词具有三层含义。一为个体含义,即指计算机系统中的单个程序及其文档;二为整体含义,即指在特定计算机系统中所有上述个体含义下的软件的总体。三为学科含义,即指在研究、开发、维护以及使用前述含义下的软件所涉及的理论、原则、方法、技术所构成的学科。在这种含义下,软件宜称为软件学,但一般仍称作软件。
|
||
\end{minipage}
|
||
\end{center}
|
||
|
||
上述描述主要是从计算机系统中与硬件相对应的角度,给出了软件的一种存在形式的描述。而从软件历史渊源看,它本质上是刻画完成给定应用目标的\index{可计算函数}可计算函数~\cite{Turing:1937:ComputableNumbers},这构成了软件的实质内容。在本书中,我们将软件\index{软件}视作是\emph{以计算为核心手段实现应用目标的解决方案}。软件属于人工制品,以适应其所处环境的方式完成应用目标;更进一步,它是一种计算的逻辑制品,既有图灵可计算性~\cite{Turing:1937:ComputableNumbers, Cooper:2002:CT:961908}和计算复杂性~\cite{Cook:1983:OCC:358141.358144}的刚性约束,同时又有通用图灵机模型给予的无与伦比的计算解空间。这也造就了软件成为人类认识世界、改造世界的文明发展的承载。
|
||
|
||
软件科学与工程学科(以下简称软件学科)是以软件为基本研究对象的人工科学(或曰“人工制品科学”,Science of Artificial~\cite{Simon:1996:SA:237774}),包括研究和分析、开发和运行、使用和演化软件等活动所涉及的理论、原则、方法、技术、工具和系统。回顾计算机科学技术的发展历史,从1966年首届图灵奖至2018年的53次颁奖中,属于软件领域的有37次(69.8\%),其中以程序设计语言、编译和操作系统为主获奖的有22次获奖,还有4次数据库获奖。 因此,在方法论的意义上,软件学科构成整个计算机科学技术学科的相当大的部分,并与系统科学、控制科学以及经济学、社会学等相关学科交叉融合,具有高度综合性。作为本书第一部分的开篇,本章将简要回顾软件和软件技术的发展历程,通过梳理软件发展脉络,总结软件学科的基本内涵、关键问题、研究方法和发展规律,为第一部分软件学科历史回顾的展开进行铺垫,同时为第二部分学科发展战略提供基础。
|
||
|
||
\section{软件发展简史}
|
||
本节我们试图从 “编程”表达解决方案和 “抽象”实现复杂性控制两个基本视角简要回顾软件发展历史,为下节讨论软件学科发展基本规律提供背景。
|
||
|
||
\subsection{人力/机械计算时代}
|
||
程序化是人类思维的基本形式之一。如果我们广义地理解“计算”,“软件"的历史可以追溯到千年之前。人类历史上最早的计算设备是算盘,其算法口诀可视为一种程序化计算的规则。到东汉年代,提花机(参见图\ref{fig:1-1})的设计中蕴含了用程序方式编织特定图案的思想。类似的设备晚至1805年才在欧洲出现,即所谓Jacquard's Loom(参见图\ref{fig:1-2})。1842年人类的第一位程序员Ada Lavelace为Babagge的分析机写了第一个程序,功能是计算Bernoulli数(参见图\ref{fig:1-3}和图\ref{fig:1-4})。可见早在机械计算时代,可编程的思想已经产生了萌芽。
|
||
|
||
\begin{figure}[htbp]
|
||
\centering
|
||
\begin{minipage}[t]{0.48\textwidth}
|
||
\centering
|
||
\includegraphics[width=5cm]{fig1-1/1-1.png}
|
||
\caption{提花机}
|
||
\label{fig:1-1}
|
||
\end{minipage}
|
||
\begin{minipage}[t]{0.48\textwidth}
|
||
\centering
|
||
\includegraphics[width=5cm]{fig1-1/1-2.png}
|
||
\caption{Jacquard's Loom}
|
||
\label{fig:1-2}
|
||
\end{minipage}
|
||
\end{figure}
|
||
|
||
\begin{figure}[htbp]
|
||
\centering
|
||
\begin{minipage}[t]{0.48\textwidth}
|
||
\includegraphics[width=5cm]{fig1-1/1-3.jpg}
|
||
\caption{Babagge分析机}
|
||
\label{fig:1-3}
|
||
\end{minipage}
|
||
\begin{minipage}[t]{0.48\textwidth}
|
||
\centering
|
||
\includegraphics[width=5cm]{fig1-1/1-4.jpg}
|
||
\caption{Babagge分析机的第一个程序}
|
||
\label{fig:1-4}
|
||
\end{minipage}
|
||
\end{figure}
|
||
|
||
Computer一词历史上出现在1613年,用来指完成演算或计算的人员。这种说法一直持续到19世纪末后第二次工业革命时期产生了用来演算的机器为止\footnote{https://www.computerhope.com/issues/ch000984.htm}。著名的哈佛大学天文台在1877年至1919年期间雇佣了一批妇女作为处理天文数据的技术工人。在电子计算机出现之前的人力和机械计算时代,Mathematic Tables项目是当时最大最复杂的计算项目,该项目的关键思想就是利用编程的完成特定函数的计算。Gertrude Blanch女士作为“数学的导演”和“计算的经理”,设计了人力计算团队执行的“算法”,其算法设计成为此后数十年超越函数的标准计算思路。逐渐地,人们发明了表达编程的记号和方法,例如1921年Lillian和Frank Gilbreth的过程图(Process Charts,参见图1-5),后来的程序流图与之形式十分类似;又如1940年IBM的W.J. Eckert提出的打孔卡(参见图1-6)。我们可以看到,计算和编程是紧密相关的,而编程的结果事实上是给出了一种计算应用(数学计算)的解决方案,它可以由人力计算或机械计算完成。然而,在人力/机械计算时代,还未形成通用计算和编程的思想。
|
||
|
||
|
||
\subsection{电子计算时代}
|
||
上世纪四十年代出现了电子计算机。计算机先驱们相继研制了Colossus(1943)、ENIAC(1946)、EDSAC(1949)和Mark I(1949)等计算机~\cite{Aspray:1986:IDC:1435661.1436778}。EDSAC作为第一台存储程序结构的电子计算机开启了通用计算的时代。此时的程序通过一种微开关的形式加载到机器硬件上。五十年代后,出现了用户和计算机之间的简单交互。Grace Hopper在1951年和1952年为UNIVAC I编写了A-0系统,这是第一个电子计算机的编译器~\cite{Ridgway:1952:CR:800259.808980}。从今天的角度看,A-0更像现代编译器概念的Loader或Linker,可以认为是第一个系统软件。UNIVAC I的程序由一组子程序和参数序列组成。两年后,A-2系统成为了第一个开源软件。早期的驻留管理程序将程序从纸带或者穿孔卡上读入到计算机中进行加载,这种技术直接导致了历史上第一个商用操作系统,即1956年推出的IBM 704的操作系统。五十年代后,人们开始意识到1936年提出的图灵机模型的理论意义,图灵机由此成为计算机科学发展的理论基础。通用图灵机和通用计算使人们进一步认识到可编程是计算的基本属性,人们通过编写程序使得计算机完成指定的任务。
|
||
|
||
\subsection{软件和软件工程的出现}
|
||
“软件”一词最早出现在1953年兰德公司R.R. Carhart的报告中,用来说明讨论可靠性时与硬件相对应的“人因”。而人们现在通常理解中的“软件”这一术语来自John W. Tukey在1958年所发表的论文~\cite{Tukey:1958:Software},文中指出 “软件由精心编写的解释程序、编译器和自动编程等组成,它们至少像电容器、晶体管、电线和磁带等现代计算机硬件一样重要”。软件形成了独立形态。1968年,或许是巧合,出现了两个软件发展史上的重大事件。这两个事件的背景都与IBM著名的IBM S/360系统相关。
|
||
|
||
第一个事件是软件与硬件的解绑~\cite{Humphrey:2002:SUP:513126.513132}。早期的软件依附在硬件之上解决应用问题,此时的计算机系统中硬件和软件是相互捆绑的。所谓“捆绑”,是指计算机公司(如IBM)在收费上采取只考虑硬件价格而软件和系统服务免费的策略。这在当时对于用户是很有吸引的,也增强了公司的竞争力。到1964年时情况发生了变化,IBM发布了新的IBM S/360系统,其目标是用户能够升级硬件系统而不需要替换或改变它们的应用程序。这在事实上形成了一种把应用解决方案剥离出硬件系统的技术可行性。而稍后RCA也宣布了其新的Spectra 70系统与IBM S/360兼容。这使得IBM难以阻止RCA在市场上“免费”使用其软件。1968年,IBM宣布了其软件和硬件系统的解绑。此后,软件从计算机系统硬件中剥离出来,获得了可以独立发展的空间,有机会产生独立的商业和竞争模式。可以看到,除了商业上的反垄断和市场竞争因素外,软件本质上所具备的“解决方案”的独立性和计算平台抽象使得解绑具备了历史必然性和技术可行性。之后的发展以Bill Gates创立Microsoft和Larry Ellison创立Oracle为标志,软件成为独立产品并形成巨大产业,应用领域从以科学计算和商业计算不断扩大,逐渐从作为硬件附属品的软硬一体化阶段过渡到软件产品化、产业化阶段。人们逐步认识到软件是计算机系统的灵魂,其共性沉淀形成的系统软件向下管理计算机系统的各类资源,向上满足用户对计算机系统的应用需求。
|
||
|
||
第二个事件是软件工程\index{软件工程}的提出。计算机能力的快速提高和软件复杂性增加导致了所谓的“软件危机”现象。典型的案例是IBM S/360的操作系统OS/360的进度、开销和可靠性均不尽人意。北大西洋公约组织(NATO)在1968年举行了首次软件工程会议~\cite{Naur:1969:SER:1102020}。在这次会议上,专家们首次提出需要与其他领域的工程方法一样系统化地进行软件开发。正如Margaret Hamilton在开发阿波罗在轨飞行和导航系统项目中所明确指出的,“我努力使软件具有应有的地位,使得构造软件的活动受到应有的尊重,因而我开始用‘软件工程’将其与硬件和其他类型的工程区分开来,成为整个系统工程的一部分”~\cite{Cameron:2018:ComputingEdge}。软件工程的出现激活了软件发展的巨大活力。这一史实也提示了软件发展的外在驱动力,即不断增长的应用需求和计算能力。
|
||
|
||
\subsection{软件发展的主线}
|
||
|
||
软件通常可分为应用软件、系统软件和支撑软件。应用软件是指特定应用领域专用的软件,面向终端用户完成既定应用目标,例如办公软件、聊天软件、财务软件等;系统软件位于硬件层之上,为应用软件提供服务,如Windows或Linux操作系统、各种数据库系统、编译程序及软件中间件等;支撑软件是支撑各种软件的开发与维护的软件,如软件开发工具及环境等。系统软件和支撑软件又统称为基础软件。
|
||
|
||
追溯软件发展可以有多条线索,既可以考察计算机系统平台、应用形式的发展,也可以采用程序设计语言、系统软件、支撑软件等角度。
|
||
从计算平台看,软件运行平台从主机平台、微机平台、局域网平台、互联网平台到万物互联平台;系统软件从批处理式、交互式、网络化发展到云边端融合的软件形态。
|
||
从应用形式看,软件的应用目标从最初军事为主的科学计算起步,发展到商业计算、个人计算、网络计算、云计算、到如今泛在计算等林林总总各个领域的场景需求,应用软件极大丰富。
|
||
为更好地面向需求,满足各类质量、进度和成本约束,驾驭各类复杂性成为软件重要主题,软件语言从机器语言、汇编语言、高级语言、发展到领域语言,成为描述软件的基本方式。
|
||
在此之上形成所谓的软件方法学\index{软件方法学},主要涉及指导软件设计的原理和原则,以及基于这些原理、原则的方法和技术。狭义的也指某种特定的软件设计指导原则和方法体系。从ALGOL~\cite{Naur:1960:ALG:1061146.1061147}诞生至今,软件方法学从结构化方法~\cite{Dahl:1972:SP:1243380}、对象化方法~\cite{Booch:1986:OD:9794.9797, Meyer:1997:OSC:261119}、构件化方法~\cite{Heineman:2001:CSE:379381}、服务化方法~\cite{Huhns:2005:SCK:1053547.1053596},发展到网构化方法~\cite{Mei:2016:INS:3086926}。%,形成一系列的支撑软件。
|
||
|
||
\subsubsection{以抽象为主线的软件学科发展}
|
||
|
||
软件解决问题的过程是从应用目标需求的问题空间到计算平台给予的解空间的映射过程。软件可以看成是现实世界中的问题及其求解方案在计算机上的符号表示。如何将现实世界表示为人和计算机都能够理解的符号系统是软件学科最核心的问题之一,此即软件模型及其建模问题,其本质是抽象~\cite{Booch:2007:ooadwa, Kramer:2007:AKC:1232743.1232745}。一方面,软件模型是现实世界的抽象表示,另一方面,它又是现实世界问题及其求解方案在计算机上实现(即计算机软件)的抽象规约。换言之,软件模型是将现实世界问题空间映射到计算机世界解空间的“桥梁”。
|
||
|
||
因而,软件学科本质上一门方法论学科,其中的关键是软件的范型~\cite{Floyd:1979:PP:359138.359140, Lu:2009:ISS:1640206.1640213, Mei:2012:ISP:2311627.2311662, Kuhn:1970:StructureSciRev}。软件范型是从软件工程师(或程序员)视角看到的软件模型及其构造原理,而构造软件模型的语汇(也称基本元素)是各类软件抽象设施,构造模型的方法是各类抽象的分解、组合和变换。Sapir-Whorf语言相对论假设对语汇的重要性给出了一个表述~\cite{Lucy:1997:LinguisticRelativity}。其较弱的版本称为语言相对论,是指语言影响思维与决策;而较强的版本称为语言决定论,则是指语言决定思维与认知边界。认识软件的切入点是认识各种软件抽象。它们构成了软件的语汇,包括但不限于程序设计语言设施、软件构件、软件服务等。宏观地说,软件方法学的核心是建立(一般的)软件抽象。
|
||
%而系统软件的核心在于实现这些抽象,软件工程则使用这些抽象构造应用软件。不同层次的抽象、抽象的计算实现和使用组成了软件发展的脉络。我们试图以软件各种抽象为主线来梳理和汇聚软件发展的基本历程。
|
||
%例如,在典型的大数据处理系统(如Google搜索引擎)中,我们可以看到接口与服务、方法与设施、虚拟化与实现等不同层次组成的抽象栈,它们分别对应着Web服务、MapReduce、Dryad、Pregel、BigTable、集群调度、分布式文件、操作系统等抽象层。
|
||
|
||
高度灵活性使得软件不仅仅是系统中的信息处理工具,也是管理各类资源、融合人机物的“万能集成器”。这就使得整个人工系统的复杂性向软件集中。驾驭复杂性的能力体现了软件发展的水平。
|
||
%弥补着从计算平台形成的解空间到应用目标的问题空间语义鸿沟,软件驾驭复杂性的抽象能力不断提高。
|
||
从早期的“程序=数据结构+算法”的初级抽象,到“软件=程序+文档”,结构化程序设计关注在于管理程序结构复杂性。进入网络化时代后,交互复杂性和规模复杂性日益突出,体系结构加设计模式抽象、服务加流程组合抽象为管理这些类高层复杂性应运而生,直至今日,知识(数据驱动)复杂性、领域(社会技术)复杂性需要纳入软件需要驾驭的复杂性之中,建立、实现、使用抽象的循环迭代不断往复,推进着软件技术的发展。
|
||
|
||
软件抽象设施往往以软件语言,特别是以程序/模型设计语言和相应接口形式给出。抽象的设施形成了模型语言,与抽象模型的构建原理一同形成了构成了软件范型。软件抽象与数学抽象不同在于,它是可编程的单元并有计算之实现,以管理硬件平台、高效实现抽象为构成了软件运行支撑技术的主要内容,也即系统软件。面向应用目标,使用抽象建立模型并以系统化的方法获得解决方案则构成了软件开发方法;进一步通过不同层次抽象形成的软件制品及其过程进行质量度量和评估,便构成了软件质量度量和评估方法;软件开发方法、软件质量度量和评估方法则构成了软件工程的主要内容。
|
||
|
||
%围绕这些抽象软件学科的发展呈扇形展开,分化出以建立抽象为主要内容的软件方法学和程序设计语言;以实现抽象为主要内容的系统软件;以使用抽象为主的软件开发和工程。参见图\ref{fig:1-5}。
|
||
|
||
% word中未指明具体标题和图片序号??
|
||
%\begin{figure}[htbp]
|
||
% \centering
|
||
% \includegraphics[width=0.80\textwidth]{fig1-1/1-5.jpg}
|
||
% \caption{}
|
||
% \label{fig:1-5}
|
||
%\end{figure}
|
||
|
||
|
||
\subsubsection{程序设计语言与程序理论}
|
||
|
||
程序设计语言提供着计算平台直接实现的抽象和构建抽象的设施,是软件范型的表示载体和描述工具。程序设计语言总是力图以更一致、更准确的方式实现从问题域到解空间的映射,更方便地表达问题求解思路,从而使开发者可以用更少的代码完成更多的工作,用更优的结构来控制编程复杂性,用更加严格规范的语法来预防编程错误等。换言之,程序设计语言的设计总是以更具表达能力和提高软件开发效率和质量为主要追求目标。
|
||
|
||
军事领域的科学计算是计算应用的最初需求。面向科学计算建立的抽象成为软件发展的早期里程碑。为了满足数值计算的需求,John Backus于1953年发明了Fortran语言~\cite{Backus:1978:HFI:960118.808380},是历史上第一个正式推广的高级程序设计语言,于1957年在IBM 704计算机上实现。Fortran语言提供的抽象对用数学公式表达的问题求解提供了直接支持。经过多年的版本更替,Fortran语言至今仍在使用。Fortran的主要贡献者获得了图灵奖。
|
||
|
||
1960年,面向常规商业信息处理,COBOL语言发布,成为COBOL-60~\cite{Sammet:1978:EHC:800025.1198367}。COBOL提供了面向周期性循环处理和数据变换的抽象,适合于报表、情报、计划编制等商业数据处理,如今仍有应用。同一时间段,面向通用计算的算法语言ALGOL 60诞生,成为ACM当时算法描述的标准,它提供了数据结构、块结构、递归等设施~\cite{Perlis:1978:ASD:800025.1198352, Naur:1978:ESL:800025.1198353}。ALGOL语言的意义重大,一是它确立了结构化高级程序设计语言设计的基础,之后的Pascal~\cite{Wirth:1993:RDP:154766.155378}、C~\cite{Ritchie:1993:DCL:154766.155580}、Java等命令式程序设计语言的基础;二是它催生了试图严格或形式化定义语言和程序的一大批软件基础理论成果。ALGOL 60的主要贡献者Peter Naur获得了2006年图灵奖。
|
||
|
||
60年代末至80年代,历经Simula 67~\cite{Nygaard:1978:DSL:800025.1198392}、Smalltalk~\cite{Kay:1993:EHS:154766.155364}、C++~\cite{Stroustrup:1993:HC:154766.155375}等语言,面向对象程序设计范型形成,提供了类(对象)、方法(消息传递)、继承等设施,建立了封装和多态等机制。面向对象语言的创立者Ole-Johan Dahl、Kristen Nygaard和重要贡献者Alan Kay也分别于2001年和2003年获得了图灵奖。
|
||
|
||
与命令式程序设计语言不同,50年代末人们还探索了声明式程序设计语言,其代表是基于Lambda演算的函数式语言LISP~\cite{McCarthy:1978:HL:800025.1198360}、基于Horn Logic的Prolog~\cite{Colmerauer:1993:BP:154766.155362}、基于关系演算的SQL~\cite{Chamberlin:2012:EHS:2420618.2420665}等。以LISP为例,它提供了用于问题求解的函数抽象,首次在语言中支持递归函数定义。LISP的设计思想深刻地影响了ML~\cite{Gordon:1978:MIP:512760.512773}、Haskell~\cite{Hudak:2007:HHL:1238844.1238856}等函数式程序设计语言~\cite{Backus:1978:PLV:359576.359579}的发展。
|
||
|
||
随着人们对程序设计安全可靠、便捷有效等需求的提高,以及计算平台向并发、分布、异构发展,程序设计语言呈现了两方面走向:一是,程序设计范型的融合,例如面向对象语言和函数式语言的融合并支持并发、安全计算,出现了Scala、Rust等程序设计语言,展现了强劲的势头;另一方面是,面向特定领域的语言受到了重视,它们针对领域应用提供高效便捷的抽象,例如面向大数据处理的Map Reduce~\cite{Dean:2008:MSD:1327452.1327492}、面向区块链智能合约的Solidity。
|
||
|
||
程序设计语言向上要面向问题求解方法的表达,向下要在计算机系统上实现。围绕语言的语法、语义和语用等方面的程序理论和问题求解的计算理论成为了软件理论的重要部分。从ALGOL60开始,关于程序(构造)的理论研究就开始了,其基本内容是在计算理论的基础上建立程序的形式语义,并对程序及其性质进行推理,其本质是基于数学的方法来建立抽象及抽象之间的联系~\cite{floyd:1967:assigning, 陆汝钤:2017:计算系统的形式语义}。在60年代到70年代,人们建立了程序设计语言的操作语义学、公理语义学、指称语义学和代数语义学。程序语言与形式语义的研究紧密联系,例如,1974年Barbara Liskov提出了抽象数据类型的程序设计思想~\cite{Liskov:1974:PAD:800233.807045},建立了现代面向对象语言的核心特征,包括强类型检查和通用类型支持,支持了对象化方法语言中的类抽象。以形式语义学为基础,人们长时期探索程序的形式开发和形式验证等形式化方法和技术以提高软件生产率和软件质量,取得显著的进展,例如模型检验获~\cite{Clarke:2000:MC:332656}得了2005年图灵奖。与程序相关的问题的求解判定和算法复杂性也成为程序设计语言设计和形式化方法的重要内容。
|
||
|
||
\subsubsection{以实现抽象为目标的系统软件}
|
||
|
||
随着硬件能力快速提高,以操作系统和编译器为代表的系统软件成为建立抽象、使用抽象来实现更高级抽象的焦点。系统软件力图凝练应用软件中的共性并加以复用,以尽可能提高软件开发和运行的效率。
|
||
事实上,程序设计语言中许多重要概念来自于操作系统和编译器的设计。
|
||
%John Cocke在解决上下文无关语言的有效扫描中发明了动态规划,而
|
||
Robert Floyd为了构建层次化自顶向下的扫描器发明了递归协程序作为抽象结构。这些抽象是用来支持相对应的设计方法,也就是问题求解的方法。
|
||
|
||
追求充分发挥硬件的能力,利用软件技术统筹管理好硬件以形成灵活、高效、可信、统一的虚拟资源是系统软件的首要驱动力。六十年代,集成电路的兴起增强了计算机的能力,高效的管理硬件、发挥硬件效能成为操作系统重要驱动力。操作系统出现了不少新技术,并变得强大复杂。典型的技术有多道程序设计、分时、实时、多处理器技术等等。70年代,操作系统的设计进一步发展,形成了UNIX操作系统,成为当今主机操作系统的基础。80年代,商业计算和微处理器时代到来,出现了一批微机和工作站操作系统,代表的是MS-DOS,Linux、Solaris 和Windows等。90年代,在"网络就是计算机"的推动下,以主机和微机操作系统为基础,中间件或网络化操作系统成为系统软件的增长点。进入新世纪后,以iOS和Android代表的移动操作系统,与主机操作系统向数据中心扩展的云操作系统形成了云端计算的软件基础设施的基本格局。更好地满足用户对易用性的需求成为系统软件生态化发展的重要因素。
|
||
|
||
操作系统中的三个基本元素是抽象、机制和策略。而其抽象的基本设计原则是机制与策略的分离、共性的沉淀。例如,进程和进程管理、线程和并发、调度、内存管理、进程间通信、I/O管理、虚拟化、分布文件系统、分布共享内存、安全与隐私抽象-Ownership等等。在实现这些抽象的过程中,人们发现并设计了计算求解的复杂性应对的原理和法则,例如局部性原理、名字映射、分而治之、信息隐藏等等。Barbara Liskov讨论了操作系统、程序语言和抽象之间的关系,指出抽象对系统组织的作用,例如用多层次的软件栈来组织复杂系统。为了应对操作系统设计中可靠性、安全性、可配置、可扩展和多处理器程序设计等挑战,微软的Singularity OS的首要任务开发新的抽象,包括平台的抽象指令集、操作系统和应用统一可扩展的体系结构和一阶的应用抽象,特别是应用抽象可递归地应用到操作系统自身,包括内核和其他OS构件。Singularity OS的后继Midori OS支持了微软西海岸和亚洲的自然语言搜索服务。Midori表明了合理的抽象和软件栈能在内存、类型和并发安全之上构建系统和应用,性能和安全并不是对立的。
|
||
|
||
由于应用范围的迅速拓展,软件抽象中用于表述现实世界的数据抽象日益重要,数据量及其复杂性迅猛增长,关于数据抽象的表示和实现的数据管理渐渐分离出来成为系统软件相对独立的部分。
|
||
|
||
|
||
\subsubsection{基于抽象构建应用解决方案的软件工程}
|
||
|
||
可编程和抽象作为软件的基本形态,随着软件工程思想的出现,软件开发方法和技术体系逐渐发展起来。面向应用建立问题解决方案的抽象成为软件开发方法的共识。软件开发可以看作是利用抽象构建新抽象获得问题解的过程。分而治之的模块化和组合化是使用抽象和在使用中建立新抽象的基本思路,信息隐藏是其基本原则。软件开发方法中的诸多抽象大多来自于程序设计语言的思路。例如,70年代的结构化系统分析和设计方法、80年代的面向对象分析和设计等等。软件开发和程序设计在抽象上尽可能地保持了一致或相容,使得软件工程模型不同阶段、不同层次的抽象有着较好的对应。另一方面,在程序设计语言抽象的基础上,为了与人们应用问题求解思维过程的一致,在软件的需求和高层设计上也出现了高层的抽象设施,也称软件建模语言。例如,在面向对象方法学的统一建模语言UML~\cite{Booch:1999:UML:291167},用Use Case对需求进行抽象建模,用Message Sequence对设计中类交互序列进行抽象。
|
||
更进一步,随着软件抽象粒度和层次的提升,软件开发方法和软件语言的发展愈加紧密。例如,基于复用思想的软件构件化方法中提出了软件体系结构,构件和构件间的连接子成为其重要组成;服务化方法定义了服务和服务间的流程编排;以及网构化方法提供了自主实体和实体间的按需连接,等等。
|
||
|
||
在计算为手段的解空间中,人们一方面不断地建立抽象,一方面不断地在计算平台上高效能实现抽象,两者相辅相成,螺旋上升。例如,结构化程序设计开创了程序设计得到的程序具有良好的结构,在这个指导思想下,问题求解可以看作是一系列的分解过程,即从一个较高层的过程,逐步地加入细节得到较低层的抽象,从而完成整个程序。逐步精化和层次化的程序结构是结构化程序设计的基本原理。在结构化程序设计的基础上,当程序员在某个抽象层次上使用下一层次提供的抽象时并不需要考虑底层的实现细节。然而高级程序设计语言不可能以内嵌的方式提供问题求解需要的所有抽象,需要一种方式可以从内嵌类型构造不同层次抽象的能力。这些动机促使了抽象数据类型的出现~\cite{Liskov:1974:PAD:800233.807045}。\index{抽象数据类型}抽象数据类型用抽象对象上一组操作的方式定义了该类抽象对象,即用类型上的操作来定义新类型。它一方面封装了底层操作抽象的细节,又构造了一组新的类型抽象。迭代地,这些不同抽象之间的关系通过分解、组合封装的方式,形成低级抽象实现高级抽象、高级抽象精化为低级抽象的软件栈,呈现一个垂直方向的模型映射关系。这形成了模型驱动(Model-driven)的软件开发方法~\cite{Schmidt:2006:MDE}。模型作为了软件系统的抽象描述,逐渐基于模型(Model-based)这个说法就成为更能够表达其宽泛含义的术语,基于模型的软件开发得到了较大的发展,出现了基于模型的软件开发(Model-based Software Development)、基于模型的测试(Model-based Testing)、基于模型的规约(Model-based Specification)等技术。
|
||
|
||
%如图,结构化抽象与THE OS、C与UNIX、面向对象与CORBA和EJB、服务化与Docker虚拟机交相辉映,形成了以计算为手段的解平台提升,并与结构化、对象化、构件化、服务化等软件开发方法携手同行。
|
||
|
||
软件开发方法从制品的角度来认识、构造和演进软件。在另一方面,软件作为人类的智力产品,在工程化的角度,软件度量和质量保证,以及软件开发和演化的动态过程必不可少。软件开发方法必然延伸到了度量、质量和过程。例如,UML不仅支持面向对象的分析与设计,还支持从业务建模、需求获取、分析、设计、实现、测试到部署的不断迭代软件开发活动,在此基础上形成了所谓统一软件开发过程。软件过程模式从早期的作坊式生产组织方式、企业化生产组织方式发展到社会化生产方式。企业化生产组织方式主要有软件过程(1970)、CMM(1988)、SCRUM(1995)、RUP(2000)和外包(2001);社会化生产方式有开源(1997)、Git(2005)、Stack Overflow(2007)和DevOps(2008)。
|
||
|
||
|
||
\section{软件学科的内涵、发展规律和基本架构}
|
||
\subsection{内涵与学科特征}
|
||
软件实质是以计算为核心手段实现应用目标的解决方案,是最纯粹的人工制品\cite{Simon:1996:SA:237774},其内涵特征包括了三个方面:
|
||
\begin{description}
|
||
\item[功能性] 以何种结构和行为
|
||
\item[目的性] 达成什么应用目的
|
||
\item[适应性] 何种环境依赖之下
|
||
\end{description}
|
||
不同于一般物品,软件是一种人工制品,同时也是一种纯粹的逻辑制品。作为逻辑制品,其困难不在于物理限制而在于逻辑构造。因此,软件开发活动本质上不同于传统工程制造:后者在于“造物”,前者可谓“拟人”—即表达人脑思维形成的问题解决方案;后者可有规模效应,而对前者而言,每一个软件系统都是独一无二的创造。
|
||
|
||
软件学科是以软件为研究对象,研究以软件求解应用问题的理论、原则、方法和技术,以及相应的工具支持、运行平台和生态环境的学科。其核心内容是以计算为工具的问题求解方法论,目标是达成效能、效率和价值的统一。N. Wirth在“软件工程简史”一文中指出 “如果说我们能从过去学到什么,那就是计算机科学本质上是方法论学科。它开发并教育在广泛多样应用的共性受惠的知识和技术”~\cite{Wirth:2008:BHS:1449571.1449577}。我们认为,在这个意义上,软件学科实质上就是Wirth所说的计算机科学的主体。
|
||
|
||
软件的功能性、目的性和适应性,使得软件学科呈现出了艺术、科学和工程共存的学科特征。这源自于软件本身融合了人类活动、数学物理规律约束的计算模型和装置、以及面向应用价值的工程设计。软件之目的性是其工程属性的来源,而功能性的设计及设计的柔性孕育了艺术、方法和原创的结合,软件最终运行的计算平台的物理和图灵可计算内生了软件发展遵循的科学规律。艺术、科学和工程在软件发展的不同阶段和侧面会相互渗透乃至相互转换。归根到底,其目的性表征的价值、软硬平台与外部环境所形成的功能及界面适应性是其核心,这也成就了软件成为万能集成器和粘合剂的基础设施地位。
|
||
|
||
\subsection{学科发展的基本规律}
|
||
|
||
纵观软件学科发展历史,随着计算时代从数字化时代发展到网络化、信息化时代,再到目前人机物融合、智能化时代,软件和软件学科在继承中发展,同时变化成为常态,正所谓“变是不变的真理”。我们从两个方面来认识软件学科发展的规律:第一,本学科发展的驱动力是什么?第二,本学科的研究方法论是什么。
|
||
|
||
\subsubsection{发展的驱动力}
|
||
软件是兼具刚性约束和柔性适应的产物。平台和应用目的可计算、复杂性和正确性形成了软件需要遵循的刚性约束,而内在的各种方法学引导、功能和适应性设计则造就了软件的柔性多样,也给予了软件学科无穷的发展活力。与诸多人工制品类似,软件学科发展的外部驱动力来自于两个方面:外在驱动力来自于应用范围的扩张、计算平台的发展;内在驱动力来自于其核心问题的解决,追求更高效地发挥计算机硬件所提供的计算能力,不断凝练应用共性并沉淀计算平台资源,同时更好地满足用户对易用性的需求。此外,软件发展驱动力还来自人本属性,包括人的认知规律和人力资源管理的深化与提高。
|
||
|
||
\textbf{外在驱动力}
|
||
|
||
计算平台的发展和应用范围的扩张分别形成了软件学科发展的平台驱动力和应用驱动力。平台的变迁形成了软件灵活成长的平台空间;而应用的扩张形成软件所解决的问题空间。在平台空间和问题空间之间,形成了软件所需具有的功能、目的和适应形成的解空间。软件的发展是这三个空间变化、渗透和互动的产物。
|
||
|
||
应用拉动,平台提高,推动软件的发展。从应用驱动力的角度,软件的应用范围不断扩展,渗透力不断增强。不断增长的应用诉求拉动了软件技术从最初单纯的计算与数据处理拓展到各个行业的应用、乃至现在泛在的无所不在的应用,软件学科的无可比拟的渗透力变得空前的强大,软件的形态、开发方法和运行支撑等诸多方面发生了巨大的变化。从平台驱动力的角度,计算平台从von Neumann计算机到网络就是计算机,从云计算、端计算、边缘计算到全球泛在计算,形成了从封闭、静态环境(单机计算平台)到开放、动态环境(泛在计算平台)的态势,造就了软件发展的不竭动力,使得软件所能提供的解决方案的解空间更趋科学、高效。在应用驱动力和平台驱动力的联合作用下,软件正走向“定义一切”。
|
||
|
||
\textbf{内在驱动力}
|
||
|
||
从学科内在的技术角度看,软件的发展有四个基本驱动力,即,追求更具表达能力、更符合人类思维模式、易构造、易演化的软件模型;支持高效率和高质量的软件开发;充分发挥硬件资源的能力,支持高效能、高可靠和易管理的软件运行;桥接异构性,实现多个应用系统之间的互操作。基于抽象的复杂性控制成为学科发展的核心要素。围绕抽象和复杂性控制,软件技术从模式化走向形式化和自动化,软件也向超大规模、开放适应、持续成长方向发展。
|
||
|
||
\subsubsection{学科方法}
|
||
|
||
从研究的角度,软件学科需要建立在计算机上运行软件的科学和工程基础。从应用的角度,需要建立开发软件制品的方法和过程来高效和节约地构建软件系统。与计算学科类似~\cite{Denning:1989:CD:63238.63239},在软件学科中,基本方法可以归为三类,即理论方法、实验方法和设计方法。
|
||
|
||
\textbf{理论方法}
|
||
|
||
理论方法首先给出软件对象的定义描述,并假设它们之间可能的联系,通过证明来判断这些联系是否成立,并解释所得到的结果。源于以图灵机为代表的形式化计算模型的奠基性贡献,使得计算平台具有刚性的数学理论约束,使得数学一开始就进入了计算机理论研究。通过建立形式理论、推理获得结果并解释结果,形成了软件作为数学对象来研究和开发的方法学。这种方法提供了开发模型并理解模型边界的分析框架,在软件正确性方面发挥了重要作用。理论方法根植于数学,将计算视作数学对象开展研究。
|
||
|
||
\textbf{实验方法}
|
||
|
||
实验方法属于实验科学方法,其本质是建模。它首先基于假设构造一个模型,通过对实验成果的统计/量化度量和分析,来确认所获得的模型。例如,为评价一种软件开发的新方法或者工具,需要通过建立假设条件下的模型,开展度量和分析,以说明方法和工具较已有方法的先进性。实验方法源自于自然科学和社会科学方法。对于软件学科的研究,可以利用计算的手段开展软件的实验研究,亦即仿真,包括用软件模拟软件的模型方法或用数据科学方法来研究软件及其环境的现象和方法。
|
||
|
||
\textbf{设计方法}
|
||
|
||
设计方法是人工科学的特有方法。它着眼于为了解决一个问题来工程化地构造一个软件,其基本过程是表述需求、表述规约、设计和实现系统并测试系统。设计中不断对已有的软件解决方案观察,提出更好的解决方案,建立/开发、度量和分析,重复直到满足问题需求。这种模式是一种演化改进的方法,关键在于设计时符合人的思维模式,尽量减少问题求解的额外复杂度。设计方法属于工程方法,源于面向问题,通过系统的设计过程来构造解决方案。
|
||
|
||
上述三类方法各自具有不可替代的作用,理论方法用来描述和揭示软件模型及对象之间的联系,实验方法可以运用这些联系来预言软件行为并与现实世界比较,设计方法则是依据软件模型和计算对象的映射规律来设计完成解决方案。
|
||
|
||
以模型为数学对象,形成了软件学科的基础(数学)理论方面的内容,其基本方法是理论方法。从软件到软件模型,即从软件能否构造一个符合该软件系统的模型,并对软件进行断言或者预言,形成了软件学科的科学方面的内容,其基本方法是实验方法。从应用目标到设计软件模型再到软件,即面向问题获得求解模型并构造一个符合该模型的软件系统,形成了软件学科的工程方面的内容,其基本方法是设计方法。这三个方面在软件学科的研究中并不是正交的,往往会联合在一起共同解决学科问题,三者的紧密联系也使得软件学科区别于数学、自然科学和传统工程科学。
|
||
|
||
%\begin{itemize}
|
||
% \item \textbf{举例}:基于大代码的软件自动生成方法就综合软件科学中的理论、实验和设计方法。程序综合是计算机科学的明珠。其理论研究是长期以来的科学问题。演绎推理的理论方法是其重要途径,形式规约开始构造一个正确的程序,自动定理证明和归纳综合是其基本思路,并逐步发展到了归纳推理。近来随着海量代码的累积,实验统计的方法逐步兴起,以实验方法从代码数据中学习,建立程序综合和推理的启发式预言有效地提高了综合效率。以归纳推理和统计推理相结合的程序综合设计方法成为了当前软件自动化研究的重要趋势,在代码自动生成、代码修复、人机协同编程等方面取得了重要进展。
|
||
%\end{itemize}
|
||
|
||
\subsection{软件学科的基本架构}
|
||
%出于不同目的考虑,学科可有不同的划分。从目前我国人才培养一级学科划分看,软件学科横跨了计算机科学与技术,软件工程、网络空间安全等三个一级学科。特别是,与计算机软件与理论二级学科和软件工程一级学科关系密切。与本国际本科计算教育学科相比,软件学科横跨了ACM/IEEE计算教程等五个学科,即计算机科学、计算机工程、软件工程、信息技术、信息系统。它们的覆盖关系如图1-X所示。
|
||
|
||
%我们着眼于软件学科发展历程的回顾,重新梳理,就现状划分了三个子领域,即程序设计语言与理论、系统软件、软件工程。其中,程序设计语言与理论的核心内容是建立抽象;系统软件的核心内容是实现抽象;软件工程的核心内容是使用抽象。它们与我国目前一级学科、ACM/IEEE计算学科的关系如图1-X所示。
|
||
|
||
我们就软件学科的现状,将软件学科体系梳理为四个方面的内容(见图\ref{fig:1-6}):软件范型、软件开发(构造)方法、软件运行支撑及软件质量度量与评估。软件范型是软件学科的核心,每次软件范型的变迁(见图\ref{fig:1-7}),都会引发软件开发方法和运行支撑技术的相应变化,并导致新的软件质量度量和评估方法的出现。
|
||
|
||
\begin{figure}[htbp]
|
||
\centering
|
||
\begin{minipage}[t]{0.48\textwidth}
|
||
\centering
|
||
\includegraphics[width=5cm]{fig1-1/1-6.png}
|
||
\caption{软件学科基本架构}
|
||
\label{fig:1-6}
|
||
\end{minipage}
|
||
\begin{minipage}[t]{0.48\textwidth}
|
||
\centering
|
||
\includegraphics[width=5cm]{fig1-1/1-7.png}
|
||
\caption{软件范型的变迁}
|
||
\label{fig:1-7}
|
||
\end{minipage}
|
||
\end{figure}
|
||
|
||
软件范型重点解决软件是什么的问题,描述了软件的模型和模型构造、运行的基本理论,包括了计算理论、程序设计语言和程序理论。计算理论包括可计算性理论、算法理论等。可计算性理论回答什么能或不能在计算平台上求解,算法理论回答如何在计算平台上高效能行求解问题。程序设计语言和程序理论回答软件抽象是什么以及它们之间联系的问题。我们将软件范型的学科内容归入程序设计语言与理论。
|
||
|
||
软件开发方法重点解决如何面向应用目标开发软件的问题。其主要围绕相应的软件范型,研究大型软件系统高质量高效率开发的方法、技术和工具,属于软件工程的范畴。软件开发是一项困难的任务,而困难可区分为实质性(Essential)的和附属性(Accidental)的~\cite{Brooks:1987}。可以认为,前者来自于软件所要解决问题本身所固有的复杂性和多变性,而后者源自解决问题时所用技术手段和过程步骤方面的不妥。软件开发方法旨在消除附属性困难,并帮助开发者理解和驾驭问题本身的实质性困难。软件开发技术核心是有效控制问题求解的附属复杂性,是一个不断建立抽象、使用抽象来实现抽象的过程。
|
||
|
||
在运行支撑方面重点解决如何在计算平台上高效高可靠的运行软件的问题。其基本途径是逐层的虚拟化技术和系统优化技术,运行平台包括操作系统、数据库、中间件等。操作系统可视为构架在硬件资源上的软件虚拟机,以追求更高效地发挥各种硬件资源所提供的计算能力,提供友好的人机交互界面。而数据库、中间件等均可视为架构在下层资源上的一层虚拟机,充分发挥下层资源的计算能力,提供高效的资源管理和更自然的人机界面。我们将运行支撑方面的学科内容归入系统软件的范畴。
|
||
|
||
软件质量度量和评估重点解决软件如何度量和评估的问题。其主要关注系统质量,追求软件的正确性、功能性指标和性能指标等。随着软件广泛应用,人们越来越关心软件系统是否更好(更快捷、更安全、更可靠、更灵活)地解决了现实世界中的问题,如何判断或度量软件是否可信、是否符合应用价值取向、是否达到目的成为软件学科的重要内容,通常将其与软件开发方法一并归入软件工程的范畴。
|
||
|
||
|
||
软件强大的渗透性,使得软件和产业紧密相联,并产生了软件产业。软件的问题解决方案和人工制品特性、软件发展的外部驱动力决定了其形成产业的必然,而强大的产业需求不断地拉动软件的发展,软件学科与软件产业相互促进,共生共荣。
|
||
|
||
\section{结束语}
|
||
|
||
本章通过梳理软件发展的脉络,指出了软件是以计算为核心手段实现应用目标和价值的解决方案。可编程是软件的基本特征,建立抽象、实现抽象和使用抽象是软件发展的主线。软件作为最为复杂的人工制品,软件学科是以软件为研究对象,通过科学方法、实验方法和设计方法等途径,研究设计、运行、使用软件及其规律的学科。
|
||
|
||
第一篇的后续几章分别从程序设计语言与理论、系统软件、软件工程、软件产业等方面进一步阐述学科领域的内涵和外延,以及对应的发展历程、现状和存在的主要矛盾。目的是从各方面来阐述软件发展的学科特性,把握学科现状和发展规律,为展望学科的未来发展奠定理性思考的基础。
|
||
|
||
%\section{参考文献}
|
||
|
||
%\begin{itemize}
|
||
% \item \cite{Liskov:1974:PAD:800233.807045}. Liskov \& Zilles. Programming with Abstract Data Types, ACM SIGPLAN Notices, 1974
|
||
% \item \cite{Floyd:1979:PP:359138.359140}. Floyd. The paradigms of programming, CACM 1979
|
||
% \item \cite{Humphrey:2002:SUP:513126.513132}. Watts S. Humphrey. Software Unbundling: A Personal Perspective. IEEE Annals of the History of Computing. 2002
|
||
% \item \cite{Simon:1996:SA:237774}. H.A. Simon. The Science of the Artificial. 1968
|
||
%\end{itemize}
|