附录B 编程的本质
编程的本质
N
尼古拉斯·沃斯(Niklaus Wirth,1934年2月15日—),生於于瑞士温特图尔,是瑞士计算机科学家。Pascal语言之父。
让我们暂时撇开平台、框架、技术、设计模式、对象思想、敏捷开发论等。 追问程序本质。
2.0 什么是编程/h2>
编程的本质是创造世界。
编程的本质是创造世界。
从本质上来说, 程序就是一系列有序执行的指令集合。 如何将指令集合组织成可靠可用可信赖的软件(美妙的逻辑之塔), 这是个问题。
N有一句在计算机领域人尽皆知的名言:
算法+数据结构=程序(Algorithm+Data Structures=Programs)
所有编程语言的最终目的都是提供一种“抽象”方法。这里的抽象,就是思维的对问题空间的映射。语言,只是为了表达我们的思想。
每一次“抽象”都抛弃了一些非本质特征而提炼出更普适的精髓特征,因而每一次抽象都是在透过现象看本质,每一次提炼都是一次质的飞跃和升华,从而使由此得到的新理论更具普遍性与包容性。例如量子力学不仅能解释经典力学的各种现象,还能解释微观世界里特有的(不能被经典力学或经典电动力学解释的)现象,如AB效应。
从硬件电路上的高低电平,到机器代码的01组合,再到汇编指令的mov、add,再到,中高级语言中的for、print, 编程语言的从底层到高层的发展,在做一层一层抽象的,正是编译器。
就好比是在数学中,无论多么复杂的问题,最终都可以拆分化归到最基本的运算和公理上一样;对于编程来说,每一个程序最终都可以被分解成一个一个最基本的指令以及这些指令的组合。
人类对这些问题的分析和理解,对问题的拆分,并用算法和代码来描述的过程,就是“编程”,这样的人,我们称之为“程序员”。
诗人用优美的意象,构建一个美的情感世界。作家用个性鲜明的人物,曲折离奇的情节,创造一个理想王国。音乐家用音符,创造一个悠远优雅的声音世界。数学家,通过最基本的公理推导出定理,数学规律,构建一个庞大的宇宙空间形式的逻辑世界……程序员,通过最基本的算法,数据结构,构建庞大的互联 云端的“虚拟世界”。是的,他们都是在创造一个世界。
从这个角度看,无论哪个学科,哪个领域,都是这样的一个过程。所以,人类的所有知识体系、学科类别,都是相通的。毕竟,都是人类大脑思维的结果。人类的大脑就像是JVM , 计算机编程、数学证明、物理公式、音乐、艺术设计、诗歌小说……等等就像是java,scala,kotlin,groovy,clojure,jython……等等,通过不同的思想与语言表现出不同的形式,但是通过人类大脑(jvm)
连通。
2.1 结构化程序设计
1971年4月份的 Communications of ACM上,N发表了论文“通过逐步求精方式开发程序’(Program Development by Stepwise Refinement),首次提出“结构化程序设计”(structure programming)的概念。
不要求一步就编制成可执行的程序,而是分若干步进行,逐步求精。
第一步编出的程序抽象度最高,第二步编出的程序抽象度有所降低…… 最后一步编出的程序即为可执行的程序。
用这种方法编程,似乎复杂,实际上优点很多,可使程序易读、易写、易调试、易维护、易保证其正确性及验证其正确性。
结构化程序设计方法又称为“自顶向下”或“逐步求精”法,在程序设计领域引发了一场革命,成为程序开发的一个标准方法,尤其是在后来发展起来的软件工程中获得广泛应用。有人评价说沃思的结构化程序设计概念“完全改变了人们对程序设计的思维方式”,这是一点也不夸张的。
从编程角度来说, 开发者应对的就是逻辑, 逻辑的表达、组织和维护。 逻辑是事物自此及彼的合乎事物发展规律的序列。指令是逻辑的具体实现形式。
软件的复杂性表现在如何表达和维护交互复杂的大型逻辑上。但无论软件发展到多么复杂的程度, 总有一群人(我们可称之为“计算机科学家”), 在试图从程序的本质中探究软件开发的基本问题, 他们试图论证和确保程序的正确性、提炼软件的基本属性并进行衡量; 程序的正确性本质是逻辑学来保证的。 没有逻辑学, 程序根本就无法立足, 更不可能有今天的大规模应用。
2.2 怎样解决问题/h2>
工欲善其事必先利其器
工欲善其事必先利其器
在编程中,我们的武器装备通常有(不限于)如下的几个方面:
1.开发工具,让我们更有效率地创造逻辑、 远离语法错误的困扰(IDE);
2.公共库,将常用的通用逻辑块封装成可反复使用的组件, 避免不必要的重复劳动(SDK);
3.设计模式,体现的是如何可扩展地解决常见的逻辑交互问题;
4.应用框架,解决的是应用的通用逻辑流的控制的问题,让开发者更多地聚焦具体业务逻辑上(我们本书讲的Spring Boot,就是这样的一个优秀的应用框架);
5.问题领域建模,在具体的应用情境下按照既定总体思路去探究具体问题解决的方法。
我们在软件工程中,通常采用的自顶向下的架构设计思想,即先着手系统架构设计,然后逐层分解,进入业务模块,最后进入细粒度功能模块的详细设计开发。
而所谓自底向上,就是先从一行代码,一个Bug,一个模块做起,然后再做一个流程,一个业务模块,最后构建出一个庞大的系统架构。
自顶向下与自底向上这两个过程,不是彼此孤立的,而是互相融合的。
2.3 层次化分解与复合
我们经常说一些代码片段是优雅的或美观的,实际上意味着它们更容易被人类有限的思维所处理。
对于程序的复合而言,好的代码是它的表面积要比体积增长的慢。
代码块的“表面积”是是我们复合代码块时所需要的信息(接口API协议定义)。代码块的“体积”就是接口内部的实现逻辑(API背后的实现代码)。
在面向对象编程中,一个理想的对象应该是只暴露它的抽象接口(纯表面, 无体积),其方法则扮演箭头的角色。如果为了理解一个对象如何与其他对象进行复合,当你发现不得不深入挖掘对象的实现之时,此时你所用的编程范式的原本优势就荡然无存了。
2.4 面向对象编程(OOP)
面向对象编程是一种自顶向下的程序设计方法.万事万物都是对象,对象有其行为(方法),状态(成员变量,属性).
所谓“面向对象语言”,其实就是经典的“过程式语言”(比如Pascal,C),加上一点抽象能力。所谓“类”和“对象”,基本是过程式语言里面的记录(record,或者叫结构,structure),本质是一个“映射表”(map)(一切皆是映射)。
2.5 函数式编程(FP)
函数式编程方法通过组合和应用函数来构造逻辑系统.函数式编程倾向于把软件分解为其需要执行的行为或操作,而且通常采用自底向上的方法.同时,函数式编程也提供了非常强大的对事物进行抽象和组合的能力.
在函数式语言里面,函数是“一类公民”(first-class)。它们可以像1, 2, “hello”,true,对象…… 之类的“值”一样,在任意位置诞生,通过变量,参数和数据结构传递到其它地方,可以在任何位置被调用。
很多所谓“面向对象设计模式”(design pattern),都是因为面向对象语言没有first-class function,所以导致了每个函数必须被包在一个对象里面才能传递到其它地方。
2.6 混合式编程(HP)
深刻理解了“数据流”的本质(CPU的存储,寻址,中断等)。不管是OOP、FP,其实本质上都是把你的“思想”放进一个“管道”,让其流动运行起来。只是在不同的语言范式里,放置的形式有一点不同而已!
对编程各种范式运用,游刃有余。
庖丁释刀对曰:“臣之所好者,道也,进乎技矣。始臣之解牛之时,所见无非牛者。三年之后,未尝见全牛也。方今之时,臣以神遇而不以目视,官知止而神欲行。依乎天理,批大郤,导大窾,因其固然,技经肯綮之未尝,而况大軱乎!
这里的“牛”,可以理解为我们所说的各种编程思想,编程范式,编程方法,编程技巧等等。最后,达到“运用之妙,存乎一心”之境也。
小结
编程的本质就是创造世界。
编程简史
1940之前
Fortran ,1954
名称取自”FORmula TRANslator”(公式翻译器),约翰·贝克斯(John Backus)针对汇编语言的缺点而研究开发的语言。
LISP,1958
名称取自”LISt Processor”(枚举处理器),约翰·麦卡锡(John McCarthy)在1958年基于λ演算所创造,采用抽象数据列表与递归作符 演算来衍生人工智能。LISP为函数式程序设计语言,所有运算都能以函数作用于参数的方式来实现。LISP核心的操作符只有7个:quote、atom、eq、car、cdr、cons、cond。前三者quote、atom、eq用于符 的推断;car、cdr、cons操纵表格;cond负责分支判断。这种简洁定义,非常接近图灵机原型的纯函数式语言,是现代语言完全无法比拟的。
ALGOL 60,1960
名称取自”ALGOrithmic Language”(算法语言)。ALGOL 60是程序设计语言由技艺转向科学的重要标志,其特点是局部性、动态性、递归性和严谨性,发明于1960年。ALGOL 60强化了当时许多关于计算的想法,并提出了两个语言上的创新功能:
(1)嵌套区块结构(Nested block structure):可以将有意义的代码片段组群成一个区块(block),而非转成分散且特定命名的程序。
(2)词汇范围(lexical scoping):区块可以有区块外部无法通过名称访问,属于区块本身的变量、程序以及函数。
另一个创新则是关于语言的描述方式:
一种名为巴科斯-诺尔范式 (BNF)的数学化精确符 被用于描述语言的语法。之后的编程语言几乎全部都采用类似BNF的方式来描述程序语法中上下文无关的部分。
Pascal、Ada、Simula、C等都借鉴了ALGOL。
COBOL,1961
名称取自”COmmon Business Oriented Language”(通用商业导向语言),由格雷斯·霍波(G.Hopper)所开发。COBOL语言以代码极其冗长和通篇大写字母的书写风格而闻名。据称用COBOL书写的程序超过了2000亿行。另有调查发现世界上目前使用的商业应用软件之中的百分之七十是用COBOL代码编写的。
BASIC,1964
BASIC (初学者通用符 指令代码,Beginners’ All-purpose Symbolic Instruction Code),匈牙利人约翰·凯梅尼(John G. Kemeny)与数学教师托马斯·卡茨(Thomas E. Kurtz)认为像FORTRAN那样的语言都是为专业人员设计,没有办法普及。于是,他们在简化FORTRAN的基础上由共同研制出来的。1964年BASIC语言正式发布。第一个BASIC程序在1964年5月1日早上4时,由BASIC编译程序进行编译后成功运行 。1975年,比尔·盖茨把它移植到PC上。
1967-1978:确立基础范式
在1960年代以及1970年代中,结构化程序设计的优点也带来许多的争议,特别是在程序开发的过程中完全不使用GOTO。
在这段期间被开发出来的重要语言有:
1960年代晚期至1970年代晚期的期间中,编程语言的发展也有了重大的成果。大多数现在所使用的主要语言范式都是在这段期间中发明的。
Simula,1967
第一个面向对象编程语言。由挪威科学家Ole-Johan Dahl和Kristen Nygaard,以Algol 60超集的方式设计开发。
Pascal,1970
Niklaus Wirth(就是那位说:“算法+数据结构=程序” 的人)创造了Pascal,一个过程式的语言。Pascal语言语法严谨,层次分明,程序易写,具有很强的可读性,是第一个结构化的编程语言。Pascal的名称是为了纪念十七世纪法国著名哲学家和数学家Blaise Pascal。
C,1972
源自Ken Thompson发明的B语言,而 B语言则源自BCPL语言。1967年,剑桥大学的Martin Richards对CPL语言进行了简化,于是产生了BCPL(Basic Combined Programming Language)语言。1970年,美国贝尔实验室的 Ken Thompson,以BCPL语言为基础,设计出很简单且很接近硬件的B语言(取BCPL的首字母)。并且他用B语言写了第一个UNIX操作系统。
1971年,Dennis M.Ritchie伙同Thompson一起,合作开发UNIX。1972年, D.M.Ritchie 在B语言的基础上设计出C语言。Thompson和Ritchie就用C完全重写了UNIX。在开发中,他们还考虑把UNIX移植到其他类型的计算机上使用。C语言强大的移植性(Portability)在此显现。机器语言和汇编语言都不具有移植性,为x86开发的程序,不能在Alpha,SPARC和ARM等机器上运行。而C语言程序则可以使用在任意架构的处理器上,只要那种架构的处理器具有对应的C语言编译器和库,然后将C源代码编译、连接成目标二进制文件之后即可运行。
未来的JVM的“虚拟机”的思想,在某种程度上正是源自这里,通过对不同平台上JVM的实现,向上封装一层,从而使得基于JVM的编程语言可以更大限度的实现了跨平台(当然,对应需要实现各个平台上(比如说Windows,Linux,Mac OS)的JDK)。
Smalltalk,1975
由Alan Kay,Dan Ingalls,Ted Kaehler,Adele Goldberg等于70年代初在Xerox PARC开发的面向对象编程语言。
Alan Kay 总结了 Smalltalk 的五大基本特征。这是第一种成功的面向对象程序设计语言,也是Java 的基础 语言。通过这些特征,我们可理解“纯粹”的面向对象程序设计方法是什么样的:
(1) 所有东西都是对象。可将对象想象成一种新型变量;它保存着数据,但可要求它对自身进行操作。理论 上讲,可从要解决的问题身上提出所有概念性的组件,然后在程序中将其表达为一个对象。
(2) 程序是一大堆对象的组合;通过消息传递,各对象知道自己该做些什么。为了向对象发出请求,需向那 27
个对象“发送一条消息”。更具体地讲,可将消息想象为一个调用请求,它调用的是从属于目标对象的一个 子例程或函数。
(3) 每个对象都有自己的存储空间,可容纳其他对象。或者说,通过封装现有对象,可制作出新型对象。所 以,尽管对象的概念非常简单,但在程序中却可达到任意高的复杂程度。
(4) 每个对象都有一种类型。根据语法,每个对象都是某个“类”的一个“实例”。其中,“类”(Class) 是“类型”(Type)的同义词。一个类最重要的特征就是“能将什么消息发给它。
(5) 同一类所有对象都能接收相同的消息。[10]
Smalltalk对其它众多的程序设计语言的产生起到了极大的推动作用,例如:Objective-C,Actor, Java 和Ruby等。90年代的许多软件开发思想得利于Smalltalk,例如Design Patterns, Extreme Programming(XP)和Refactoring等。
Prolog,1972
Prolog语言最早由Aix-Marseille大学的Alain Colmerauer与Phillipe Roussel、Kowalski等人于60年代末研究开发。它建立在逻辑学的理论基础之上, 最初被运用于自然语言等研究领域。现已广泛的应用在人工智能的研究中,可以用来建造专家系统、自然语言理解、智能知识库等。
ML,1973
ML(Meta Language)是Robin Milner主管LCF项目时(1970),作为LCF项目的元语言(Meta Language)而设计的,这也是其名字的来历。LCF项目是受Dana Scott给出的一组逻辑原则启发而设立的,致力于开发一种“可计算函数逻辑”(Logic of Computable Functions)。目标是构造一个方便实用的系统,来自动的或者半自动的证明函数程序中一些有趣的性质。今天,大多数著名的推理系统都是用ML写的。目前ML有两个发展分支:Standard ML和Caml。
ML使用了Hindley-Milner类型推论算法来推测大多数值的类型,而不需要四处使用注解。ML一般被归为非纯函数式编程语言,因为它允许副作用和指令式编程。这一点和纯函数式编程语言例如Haskell很不一样。ML特性有惰性求值的求值策略,一阶类型函数, 带有垃圾收集的自动内存管理, 参数多态,静态数据类型,类型推断,代数数据类型,模式匹配和异常处理等。ML中的思想影响了众多的语言,例如Haskell,Cyclone和Nemerle。
这些语言都各自演展出自己的家族分支,现今多数现代编程语言的祖先都可以追溯他们其中至少一个以上。
1980年代:增强、模块、性能
1980年代的编程语言与之前相较显得更为强大。C++合并了面向对象以及系统程序设计。美国政府标准化一种名为Ada的系统编程语言并提供给国防承包商使用。日本以及其他地方运用了大量的资金对采用逻辑编程语言结构的第五代语言进行研究。函数编程语言 区则把焦点转移到标准化ML及Lisp身上。这些活动都不是在开发新的范式,而是在将上个世代发明的构想进一步发扬光大。
然而,在语言设计上有个重大的新趋势,就是研究运用模块或大型组织化的程序单元来进行大型系统的开发。Modula、Ada,以及ML都在1980年代发展出值得注意的模块化系统。模块化系统常拘泥于采用泛型程序设计结构:泛型存在(generics being)、本质(essence),参数化模块(parameterized modules)。(参阅多态)
尽管没有出现新的主要编程语言范式,许多研究人员仍就扩充之前语言的构想并将它们运用到新的内容上。举例来说,Argus以及Emerald系统的语言配合面向对象语言运用到分布式系统上。
1980年代的编程语言实现情况也有所进展。计算机系统结构中RISC的进展假定硬件应当为编译器设计,而非身为人类的汇编语言程序员。借由中央处理器速度增快的帮助,编译技术也越来越积极,RISC的进展对高级语言编译技术带来不小的关注。
语言技术持续这些发展并迈入了1990年代。
在这段期间被开发出来的重要语言包括有:
C++,1983
Bjarne Stroustrup,他使用过Simula和ALGOL,接触过C。他对Simula的类体系感受颇深,对ALGOL的结构也很有研究,深知运行效率的意义。既要编程简单、正确可靠,又要运行高效、可移植。于是Bjarne Stroustrup以C为背景,以Simula思想为基础,把他所听说过的一切都试图嫁接到C上,创造出了C++。它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。C++擅长面向对象程序设计的同时,还可以进行基于过程的程序设计,因而C++就适应的问题规模而论,大小由之。
1990年代:互联 时代
1990年代未见到有什么重大的创新,大多都是以前构想的重组或变化。这段期间主要在推动的哲学是提升程序员的生产力。
许多”快速应用程序开发” (RAD) 语言也应运而生,这些语言大多都有相应的集成开发环境、垃圾回收等机制,且大多是先前语言的派生语言。这类型的语言也大多是面向对象的编程语言,包含有Object Pascal、Visual Basic,以及C#。
Java,1995
1995年,互联 的蓬勃发展给了Oak(Java之前的名字)机会。Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。
我们将在下一章中介绍Java编程简史。另外,关于上面提到的“提升程序员的生产力”的哲学理念,本书介绍的SpringBoot框架,就是为了推动程序员的生产力而设计开发的。不管在编程语言设计领域,还是在编程框架的开发领域,很大一部分的目的,就是为了这一点。
在这段期间被开发出来的重要语言包括有:
当今的趋势
编程语言持续在学术及企业两个层面中发展进化,目前的一些趋势包含有:
-
在语言中增加安全性与可靠性验证机制:额外的堆栈检查、信息流(information flow)控制,以及静态线程安全。
-
提供模块化的替代机制:混入(mixin)、委派(delegates),以及观点导向。
-
组件导向(component-oriented)软件开发。
-
元编程、反射或是访问抽象语法树(Abstract syntax tree)
-
更重视分布式及移动式的应用。
-
与数据库的集成,包含XML及关系数据库。
-
支持使用Unicode编写程序,所以源代码不会受到ASCII字符集的限制,而可以使用像是非拉丁语系的脚本或延伸标点符 。
-
图形用户界面所使用的XML(XUL、XAML)。
等等。
在这段期间被开发出来的重要语言包括有:
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!