software-strategy-book/Ch1-1-History.tex

303 lines
52 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{引言}
《计算机科学技术百科全书》中对软件给出了如下描述~\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年首届图灵奖至2019年的54次颁奖中属于软件领域的有37次68.5\%其中以程序设计语言、编译和操作系统为主获奖的有22次还有4次数据库获奖。
在方法论的意义上,软件学科构成整个计算机科学技术学科的相当大的部分,并与系统科学、控制科学以及经济学、社会学等相关学科交叉融合,具有高度综合性。
作为本书第一部分的开篇,本章将简要回顾软件和软件技术的发展历程,通过梳理软件发展脉络,总结软件学科的基本内涵、主要线索、研究方法和发展规律,为第一部分软件学科历史回顾的展开进行铺垫,同时为第二部分学科发展战略研究提供背景。
\section{软件发展简史}
本节我们试图从 “编程”表达解决方案和 “抽象”实现复杂性控制两个基本视角简要回顾软件发展历史,为下节讨论软件学科发展基本规律提供背景。
\subsection{人力/机械计算时代}
程序化是人类思维的基本形式之一。如果我们广义地理解“计算”,“软件"的历史可以追溯到千年之前。人类历史上最早的计算设备是算盘,其算法口诀可视为一种程序化计算的规则。到东汉年代,提花机(参见图\ref{fig:提花机}\footnote{南宋《耕织图》}的设计中蕴含了用程序方式编织特定图案的思想。类似的设备晚至1805年才在欧洲出现即所谓Jacquard's Loom参见图\ref{fig:JacquardsLoom}\footnote{http://www.columbia.edu/cu/computinghistory/jacquard.html}。1842年人类的第一位程序员Ada Lavelace为Babagge的分析机写了第一个程序功能是计算Bernoulli数参见图\ref{fig:Babagge分析机}\footnote{https://en.wikipedia.org/wiki/Analytical\_Engine}和图\ref{fig:Babagge分析机程序}\footnote{https://computerhistory.org/blog/ada-lovelace-day/})。可见早在机械计算时代,可编程的思想已经产生了萌芽。
\begin{figure}[htbp]
\centering
\begin{minipage}[t]{0.48\textwidth}
\centering
\includegraphics[width=5cm]{fig1-1/1-1.png}
\caption{提花机}
\label{fig:提花机}
\end{minipage}
\begin{minipage}[t]{0.48\textwidth}
\centering
\includegraphics[width=5cm]{fig1-1/1-2.png}
\caption{Jacquard's Loom}
\label{fig:JacquardsLoom}
\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:Babagge分析机}
\end{minipage}
\begin{minipage}[t]{0.48\textwidth}
\centering
\includegraphics[width=5cm]{fig1-1/1-4.jpg}
\caption{Babagge分析机的第一个程序}
\label{fig:Babagge分析机程序}
\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后来的程序流图与之形式十分类似又如1940年IBM的W.J. Eckert提出的打孔卡。我们可以看到计算和编程是紧密相关的而编程的结果事实上是给出了一种计算应用数学计算的解决方案它可以由人力计算或机械计算完成。然而在人力/机械计算时代,还未形成通用计算设备编程的思想。
\subsection{电子计算时代}
1936年Alan Turing在他的著名论文《On computable numbers, with an application to the Entscheidungs problem》中提出了图灵机和通用图灵机模型~\cite{Turing:1937:ComputableNumbers}
建立了现代计算机和软件的理论模型。
上世纪四十年代计算机先驱们相继研制了Colossus1943、ENIAC1946、EDSAC1949和Mark I1949等电子计算机~\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的程序由一组子程序和参数序列组成。两年后-2系统成为了第一个开放源码的软件。早期的驻留管理程序将程序从纸带或者穿孔卡上读入到计算机中进行加载这种技术直接导致了历史上第一个商用操作系统即1956年推出的IBM 704操作系统。
\subsection{软件和软件工程的出现}
自von Neumann计算机诞生之初存储程序原理即表明了程序在计算中的核心位置。程序被作为研究对象促进了计算机学科的发展。早期最重要的系统成果有两个方面一是随着机器语言到汇编语言到高级语言及解释和编译技术的出现开发程序的生产率得到了迅速提高二是为了发挥硬件性能、改善人机交互、有效管理资源而产生了操作系统显著提高了程序运行的可靠性、降低了计算机使用成本。围绕程序是什么、怎么写、怎样运行的研究随着计算机的发展形成了计算机学科的重要分支数据结构、算法理论和程序理论形成了学科的重要基础计算机应用领域开始拓展。计算机学科在世界范围内受到了重视一些高校先后设置了计算机系。
“软件”一词最早出现在1953年兰德公司R.R. Carhart的报告中~\cite{Carhart1953Rand}用来说明讨论可靠性时与硬件相对应的“人因”。而人们现在通常理解中的“软件”这一术语来自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{以抽象为主线的软件学科发展}
软件抽象是理解软件学科及其发展的关键。
一方面,软件抽象是软件开发者认识问题、表达并实现解决方案的语汇,是软件学科的核心研究对象和软件工程的主要工具。软件抽象影响乃至决定了软件认知和表达的边界。
另一方面,作为一门方法论学科,帮助开发者驾驭软件开发的复杂性始终是中心问题,而抽象是驾驭复杂性的主要手段。
软件抽象是软件学科知识沉淀的载体和发展进步的标志;无论是系统软件还是工程方法,均以其支撑或使用的软件抽象为主要特征。
细言之,以计算手段解决问题的过程是从应用需求的问题空间到计算平台约束的解空间的映射过程,包括从解空间到平台空间上的计算实现\footnote{本质上,平台空间属于解空间中可直接计算执行的部分,其中计算平台形成了对解空间的约束。}。软件可以看成是现实世界中的问题及其求解方案在计算机上的一系列的符号表示。如何将现实世界表示为人和计算机都能够理解的符号系统是软件学科最核心的问题之一,此即软件模型及其建模问题~\cite{Booch:2007:ooadwa, Kramer:2007:AKC:1232743.1232745}。软件模型是解决方案(现实世界描述、问题描述及其求解方案)的抽象表示。
软件模型组成了解空间,是将现实世界问题空间映射到计算机世界平台空间的“桥梁”;从人工科学的角度看,软件模型的集合构成问题空间到平台空间的界面。
构造软件模型的语汇(也称基本元素)是各类软件抽象设施,构造模型的方法是各类抽象的分解、组合和变换,建立抽象和抽象之间的关系。
Sapir-Whorf语言相对论假设对语汇的重要性给出了一个表述~\cite{Lucy:1997:LinguisticRelativity}
其较弱的版本称为语言相对论,是指语言影响思维与决策;而较强的版本称为语言决定论,则是指语言决定思维与认知边界。
这一原理也突出地表现在软件学科。认识软件的切入点是认识各种软件抽象,宏观地说,软件方法学的核心是探讨如何建立、实现和使用抽象。
软件抽象设施集中体现在各种软件语言,特别是以程序设计语言和建模语言,也包括程序框架、编程接口等。
从结构上看,基于认知程度的不同,高层抽象可以分解为低层抽象,底层抽象可以组合或聚集为高层抽象,抽象之间还有不同语义保持度的转换。
在问题空间、解空间和平台空间表述时,都可以建立或者定义所需的抽象,也可以使用已定义的抽象表述对象或者实现一个新定义的抽象。
软件范型为软件工程师(或程序员)提供 一套具有内在一致性的软件抽象体系,具化为一系列软件模型及其构造原理~\cite{Floyd:1979:PP:359138.359140, Lu:2009:ISS:1640206.1640213, Mei:2012:ISP:2311627.2311662, Kuhn:1970:StructureSciRev}
换个角度看,软件抽象的重要性也体现在它是驾驭软件复杂性的基本手段。可以说软件是人类制造的最复杂的一类制品。
%而系统软件的核心在于实现这些抽象,软件工程则使用这些抽象构造应用软件。不同层次的抽象、抽象的计算实现和使用组成了软件发展的脉络。我们试图以软件各种抽象为主线来梳理和汇聚软件发展的基本历程。
%例如在典型的大数据处理系统如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的主要贡献者John Backus于1977年获得了图灵奖。%\footnote{https://amturing.acm.org/award\_winners/backus\_0703524.cfm}。
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~\cite{AGH2000Java}等命令式程序设计语言都是在此基础上发展出来的二是它催生了试图严格或形式化地定义语言和程序的一大批软件基础理论成果。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}等语言,面向对象程序设计形成,提供了类(对象)、方法(消息传递)、继承等设施,引入了封装和多态等机制。
与命令式程序设计语言不同50年代末人们还探索了声明式程序设计语言其代表是基于$\lambda$~演算的函数式语言LISP~\cite{McCarthy:1978:HL:800025.1198360}、基于Horn子句的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~\cite{SolidityDoc2020}等。
程序设计语言向上要表达问题求解方法向下要在计算机系统上实现。围绕语言的语法、语义和语用等方面的程序理论和围绕问题求解的计算理论成为了软件理论的重要部分。从ALGOL 60开始关于程序构造的理论研究就开始了其基本内容是在计算理论的基础上建立程序的形式语义并对程序及其性质进行推理其本质是基于数学的方法来建立抽象及抽象之间的联系~\cite{floyd:1967:assigning, 陆汝钤:2017:计算系统的形式语义}。在上世纪60年代到70年代人们建立了程序设计语言的操作语义、公理语义、指称语义和代数语义。
%程序语言与形式语义的研究紧密联系例如1974年Barbara Liskov提出了抽象数据类型的程序设计思想~\cite{Liskov:1974:PAD:800233.807045},建立了现代面向对象语言的核心特征,包括强类型检查和通用类型支持,支持了对象化方法语言中的类抽象。
以形式语义为基础人们长期探索程序的形式开发和形式验证等形式化方法和技术以提高软件生产率和软件质量取得显著的进展。例如模型检验基于判定理论、利用高效的数据结构和算法能快速自动地验证一大类计算机硬件和软件系统的关键性质。Edmund Melson Clarke、E. Allen Emerson和Joseph Sifakis因此获得了2007年图灵奖~\cite{Clarke:2000:MC:332656}。与程序相关的问题的求解判定和算法复杂性也成为程序设计语言设计和形式化方法的重要内容。
%\subsubsection{以实现抽象为目标的系统软件}
\subsubsection{系统软件}
随着硬件能力快速提高,以操作系统和编译器为代表的系统软件成为在平台空间中建立抽象、使用抽象来实现更高级抽象的焦点。系统软件着力提高平台空间抽象的执行效率,并提升解空间的抽象层次,向问题空间抽象接近,拉近问题与解之间的间隔。具体说,一方面,系统软件通过建立、使用并实现有效的平台空间抽象对各类资源进行有效的管理;另一方面,系统软件力图在计算平台之上凝练建立、沉淀实现应用软件中的共性解空间抽象并加以复用,以尽可能提高软件开发效率。
操作系统抽象的三个基本要素是抽象表示、管理机制和策略。其基本思路是抽象表示沉淀共性模型管理机制和策略分离。例如进程是程序执行的抽象进程调度是进程抽象和计算资源的管理机制调度算法是管理进程的控制策略。进程抽象的实现中使用了进程控制块调度机制和算法分而治之地完成进程管理。操作系统中各类资源管理大多采取了这样的设计思路包括内存管理页面、换页、换页策略、I/O管理和安全管理等等。在编译器中从高级语言源程序到机器目标代码之间历经了抽象语法树、中间语言代码、四元式等多层级的抽象目标代码生成过程是这些层级抽象的映射。在系统软件发展过程中人们发现并设计了不同粒度的抽象、抽象使用和实现的原理与方法。
%John Cocke在解决上下文无关语言的有效扫描中发明了动态规划而例如Robert Floyd为了构建层次化自顶向下的扫描器发明了递归协程序作为抽象结构。其他例子还包括
例如换页策略使用局部性原理、抽象的信息隐藏和分而治之原理等等。程序设计语言和软件工程中许多重要概念来自于操作系统和编译器的设计例如管程、递归协程序等等。Barbara Liskov在操作系统发展50周年研讨会上讨论了操作系统、程序语言和抽象之间的关系指出抽象对构建系统软件的作用~\cite{10.1145/2830903.2830906}
%例如用多层次的软件栈来定义复杂系统。
%为了应对操作系统设计中可靠性、安全性、可配置、可扩展和多处理器程序设计等挑战微软的Singularity OS的首要任务开发新的抽象包括平台的抽象指令集、操作系统和应用统一可扩展的体系结构和一阶的应用抽象特别是应用抽象可递归地应用到操作系统自身包括内核和其他OS构件。Singularity OS的后继Midori OS支持了微软西海岸和亚洲的自然语言搜索服务。Midori表明了合理的抽象和软件栈能在内存、类型和并发安全之上构建系统和应用性能和安全并不是对立的。
20世纪50-60年代操作系统出现之初主要是解决在计算机上加载和运行程序、以及设备驱动、输入输出控制等工作。随着
集成电路的兴起增强了计算机的能力CPU和外设的性能差异突出高效地共享和管理硬件、发挥硬件效能成为操作系统重要驱动力。为此先后产生了多道程序设计、分时、实时等操作系统技术系统设计变得复杂能力也变得强大。著名的系统有IBM S/360的操作系统。以操作系统设计为矛盾焦点之一人们意识到了“软件危机”。软件的复杂性驾驭成为了一个至今仍在的挑战。70年代UNIX操作系统及其家族的发展和成熟成为当今主机操作系统的基础。80年代随着商业计算和微处理器时代到来出现了一批微型计算机和工作站操作系统其代表是MS-DOS、Linux、Solaris和Windows等。90年代在``网络就是计算机"的理念推动下以主机和微机操作系统为基础以桥接异构的互联互通互操作为主要目标的中间件和网络化操作系统成为系统软件的增长点。进入新世纪后以iOS和Android代表的移动操作系统与主机操作系统向数据中心扩展所形成的云操作系统一同构建了云端计算系统软件的基本格局。更好地满足用户对易用性的需求成为系统软件生态化发展的重要因素。可见追求充分发挥硬件的能力利用软件抽象技术统筹管理好硬件以形成灵活、高效、可信、统一的虚拟资源是驱动着系统软件发展的动力。
由于应用范围的迅速拓展,数据量及其复杂性迅猛增长,数据资源成为了重要管理对象。用于数据资源的抽象、操作和管理的数据库管理系统渐渐分离出来成为系统软件相对独立的部分。
%\subsubsection{基于抽象构建应用解决方案的软件工程}
\subsubsection{软件工程}
软件工程把工程化的思想应用于团队化的复杂软件系统构造活动,促进了软件开发方法与软件开发过程的发展。
%随着软件工程思想的出现,逐渐发展起来。
%面向应用建立问题解决方案的抽象成为软件开发方法的共识。
软件开发可以看作是使用各种抽象构建并实现新抽象获得问题解的过程。
分而治之的模块化和组合化是使用抽象和在使用中建立新抽象的基本思路。%,信息隐藏是其基本原则。
程序设计语言提供了基本的抽象在其基础上软件开发试图在问题空间中建立有更强表达能力、并易于向平台空间抽象高效映射的一系列抽象。因而软件开发的诸多基本抽象往往力求与程序设计语言的抽象尽可能相容或一致使得软件工程模型不同阶段、不同层次的抽象有着较好的对应保持较好的可跟踪性和平滑的实现映射。例如70年代的结构化分析和设计方法对应于结构化程序设计、80年代的面向对象分析和设计对应于面向对象程序设计等等。另一方面在程序设计语言抽象的基础上为了与人们应用问题求解思维过程的一致在软件的需求和设计上也出现了含有高层的抽象设施的软件语言也称软件建模语言。它们具有面向问题空间描述的抽象形式例如在面向对象方法学中的统一建模语言UML~\cite{Booch:1999:UML:291167}用Use Case对需求进行抽象建模用Message对需求和设计中类交互进行抽象。
更进一步,随着软件抽象粒度和层次的提升,软件开发方法和软件语言的发展愈加紧密。例如,基于复用思想的软件构件化方法中提出了软件体系结构,构件和构件间的连接子成为其重要组成;服务化方法定义了服务和服务间的流程编排;以及网构化方法提供了自主实体和实体间的按需连接,等等。
软件生命期不同阶段有不同抽象,由抽象间的(使用/实现)关系复合构建映射成为软件开发的重要任务。
%例如,结构化程序设计使得程序具有良好的结构,在这个指导思想下,问题求解可以看作是一系列的分解过程,即从一个较高层的过程,逐步地加入细节得到较低层的抽象,从而通过不同阶段抽象的映射和转换完成整个程序。逐步精化和层次化的程序结构是结构化程序设计的基本原理。在结构化程序设计的基础上,当程序员在某个抽象层次上使用下一层次提供的抽象时并不需要考虑底层的实现细节。
然而高级程序设计语言不可能以内嵌的方式提供问题求解需要的所有抽象,需要具有从内嵌类型构造不同层次抽象的能力。同时,不同层次抽象之间内嵌信息隐藏能力。这些动机促使了抽象数据类型的出现~\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软件工程不仅支持面向对象的分析与设计还支持从业务建模、需求获取、分析、设计、实现、测试到部署的迭代化软件开发活动在此基础上形成了所谓统一软件开发过程Unified Process。软件过程模式从早期的手工作坊式生产组织方式、企业化生产组织方式发展到社会化生产方式。企业化生产组织方式方面的里程碑主要有软件过程的提出1970、能力成熟度模型CMM1988、SCRUM过程框架1995、统一软件开发过程RUP2000、外包2001、敏捷和极限编程2001、个人软件过程PSP2005而社会化生产方式的重要模式和工具有开源软件运动1997、分布式版本管理工具与开源代码托管平台如Git2005与Github等以及相应的开发社交平台Stack Overflow2007等。
%DevOps2008放到学科构架里面去说。
\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{外在驱动力}
计算平台的发展和应用范围的扩张分别构成了软件学科发展的平台驱动力和应用驱动力。不断变迁的平台构成了软件灵活成长的平台空间;而不断扩张的应用构成软件所解决的问题空间。在平台空间和问题空间之间,构成了由软件填补的解空间。软件的发展是这三个空间变化、渗透和互动的产物。
应用拉动,平台变化,推动软件的发展。从应用驱动力的角度,软件的应用范围不断扩展,渗透力不断增强。不断增长的应用诉求拉动了软件技术从最初单纯的计算与数据处理拓展到各个行业的应用、乃至现在无所不在的应用,软件学科的无可比拟的渗透力变得空前的强大,软件的形态、开发方法和运行支撑等诸多方面发生了巨大的变化。从平台驱动力的角度,计算平台从单机发展到局域网、互联网、物联网,从云计算、端计算、边缘计算到泛在计算,形成了从封闭、静态环境(单机计算平台)到开放、动态环境(泛在计算平台)的态势,造就了软件发展的不竭动力,使得软件所能提供的解决方案的解空间空前强大。在应用驱动力和平台驱动力的联合作用下,软件正走向“定义一切”。
\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}):软件语言与理论、软件构造方法、软件运行支撑及软件度量与质量评估。
贯穿四者之间的是软件范型。
每一个范型为软件工程师(或程序员)提供一套具有内在一致性的软件抽象体系,具化为一系列软件模型及其构造原理,并外化为相应的软件语言、构造方法、运行支撑和度量评估技术,从而可以系统化地回答软件应该“如何表示”、“怎样构造”、“如何运行”以及“质量如何”的问题~\cite{Mei:2016:INS:3086926,}。软件范型是软件学科的核心,每次软件范型的变迁(见图\ref{fig:1-7}),都会引发软件语言、软件开发方法和运行支撑技术的相应变化,并导致新的软件质量度量和评估方法的出现。
\begin{figure}[htbp]
\centering
\begin{minipage}[t]{0.48\textwidth}
\centering
% \includegraphics[width=5cm]{fig1-1/1-6.png}
\includegraphics[width=5cm]{figs/framework.pdf}
\caption{软件学科基本架构}
\label{fig:1-6}
\end{minipage}
\begin{minipage}[t]{0.48\textwidth}
\centering
\includegraphics[width=5cm]{figs/progress.pdf}%{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}