附录2 编程的本质
===
N
尼古拉斯·沃斯(Niklaus Wirth,1934年2月15日—),生於于瑞士温特图尔,是瑞士计算机科学家。Pascal语言之父。
让我们暂时撇开平台、框架、技术、设计模式、对象思想、敏捷开发论等。 追问程序本质。
2.0 什么是编程?
编程的本质是创造世界。
从本质上来说, 程序就是一系列有序执行的指令集合。 如何将指令集合组织成可靠可用可信赖的软件(美妙的逻辑之塔), 这是个问题。
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 怎样解决问题?
工欲善其事必先利其器
在编程中,我们的武器装备通常有(不限于)如下的几个方面:
1.开发工具,让我们更有效率地创造逻辑、 远离语法错误的困扰(IDE);
2.公共库,将常用的通用逻辑块封装成可反复使用的组件, 避免不必要的重复劳动(SDK);
3.设计模式,体现的是如何可扩展地解决常见的逻辑交互问题;
4.应用框架,解决的是应用的通用逻辑流的控制的问题,让开发者更多地聚焦具体业务逻辑上(我们本书讲的Spring Boot,就是这样的一个优秀的应用框架);
5.问题领域建模,在具体的应用情境下按照既定总体思路去探究具体问题解决的方法。
我们在软件工程中,通常采用的自顶向下的架构设计思想,即先着手系统架构设计,然后逐层分解,进入业务模块,最后进入细粒度功能模块的详细设计开发。
而所谓自底向上,就是先从一行代码,一个Bug,一个模块做起,然后再做一个流程,一个业务模块,最后构建出一个庞大的系统架构。
自顶向下与自底向上这两个过程,不是彼此孤立的,而是互相融合的。
2.3 层次化分解与复合
我们经常说一些代码片段是优雅的或美观的,实际上意味着它们更容易被人类有限的思维所处理。
对于程序的复合而言,好的代码是它的表面积要比体积增长的慢。
代码块的“表面积”是是我们复合代码块时所需要的信息(接口API协议定义)。代码块的“体积”就是接口内部的实现逻辑(API背后的实现代码)。
在面向对象编程中,一个理想的对象应该是只暴露它的抽象接口(纯表面, 无体积),其方法则扮演箭头的角色。如果为了理解一个对象如何与其他对象进行复合,当你发现不得不深入挖掘对象的实现之时,此时你所用的编程范式的原本优势就荡然无存了。
2.4 面向对象编程(OOP)
面向对象编程是一种自顶向下的程序设计方法.万事万物都是对象,对象有其行为(方法),状态(成员变量,属性).
所谓“面向对象语言”,其实就是经典的“过程式语言”(比如Pascal、C),加上抽象数据类型(ADT)。比如说带类的C语言C++, 改善C++语言的Java。
所谓“类”和“对象”,对应过程式语言(例如,C语言)里面的结构体(struct),本质是一个逻辑抽象的代码“映射”(map)(一切皆是映射)。
2.5 函数式编程(FP)
函数式编程方法通过组合和应用函数来构造逻辑系统.函数式编程倾向于把软件分解为其需要执行的行为或操作,而且通常采用自底向上的方法.同时,函数式编程也提供了非常强大的对事物进行抽象和组合的能力.
在函数式语言里面,函数是“一类公民”(first-class)。它们可以像1, 2, “hello”,true,对象…… 之类的“值”一样,在任意位置诞生,通过变量,参数和数据结构传递到其它地方,可以在任何位置被调用。
很多所谓“面向对象设计模式”(design pattern),都是因为面向对象语言没有first-class function,所以导致了每个函数必须被包在一个对象里面才能传递到其它地方。
2.6 混合式编程(HP)
深刻理解了“数据流”的本质(CPU的存储,寻址,中断等)。不管是OOP、FP,其实本质上都是把你的“思想”放进一个“管道”,让其流动运行起来。只是在不同的语言范式里,放置的形式有一点不同而已!
对编程各种范式运用,游刃有余。
庖丁释刀对曰:“臣之所好者,道也,进乎技矣。始臣之解牛之时,所见无非牛者。三年之后,未尝见全牛也。方今之时,臣以神遇而不以目视,官知止而神欲行。依乎天理,批大郤,导大窾,因其固然,技经肯綮之未尝,而况大軱乎!
这里的“牛”,可以理解为我们所说的各种编程思想,编程范式,编程方法,编程技巧等等。最后,达到“运用之妙,存乎一心”之境也。
小结
编程的本质就是创造世界。