优秀的软件工程师应该深刻理解的几个基础概念

前言

最近跟同事聊起编程这个事儿,发现很多同事即使写程序写了近十几年了,也没去考虑过到底编程是什么,也不能对编程这个事儿做一个完成的理解和阐述,总是沉迷于个别的技术点上,如此的结果就是只能定义他们为专项技术熟手,而非真正的技术工程师。

这里我想简单的说一下我对编程这个事儿的理解,通过简述一些编程领域最核心的概念,来跟大家说一下编程到底是在做什么,希望对于那些刚开始学习编程的同学有所启发。

抽象与封装

首先说一下抽象这个概念,假如给你一台裸机,想让它能够为你工作。你该如何处理呢?

电脑裸机我们知道它就是一个通电能够运行的集成电路系统,它能够理解的只有电流。通过电流能够表现出的状态只有两种。

就是二极管能够表现的两种基础状态,高电压或者低电压,通电状态和断电状态而已。

为此,我们必须把我们所有的意图都通过这两个态来表现出来,显然就两个态肯定是不够的,如此我们需要引入多个以及二元态,然后用它们的不同排列组合来表示不同的内容。

我们可以将能够表示不同状态的元器件组合排列进行设计,从而将其转变为电路板设计。

进而为该电路板抽象出不同的符 指令,然后将这些指令通过基础的汇编及C/C++编写成能够跟这些硬件交互的接口类库等。

而对于高级语言来说,一般会通过定义对内存空间长度的定义来定义数据类型以及封装一些控制指令而生存的逻辑控制命令,从而为我们开发人员编写程序提供可以直接调用的功能模块或方法接口。

同时由于二元态的形式只有两个基本元素,所以其运算规则只能采用二进制来进行。

如此我们手里只有一连串不定长度的0和1的排列组合数字串,如此我们就需要对其按照一定的规则进行分拆,并规定拆分的单位长度,以及这些长度里按照某种顺序的位数意义规定。如此就形成了一套规则,这套规则是我们为一连串指定长度的0或1数字赋予了我们能够理解和表达的意义。

也就是我们常说的通过语法定义形式,并赋予其语义表达内容。

这个过程就是一种抽象,或者说是最初意义的内存空间的分组封装,让一堆没有实际意义的0或1组成的数字串,变的有意义,成为一个更加具体的符 或者象征。

从硬件的角度来说,我们的CPU是从0和1二元态的硅基晶体管的集成,因为每个晶体管能够处理的只有两个数位态,所以需要对多个晶体管的集成,当然都必须是以2而倍数的数位发展,从最初的16位集成,即一次运算16位的累加,到32位,在到64位。

然后通过内部寄存器的调度,我们可以将更多的二进制的数位预装到CPU的高级缓存中,让CPU可以不降速的对其数据进行存取计算。同时用一个时钟对CPU的运算时间进行分片控制,这就是我们在看一个CPU性能参数时需要看的频率和高级缓存大小,正是这两个参数直接标记着CPU的算力。

目前我们流行的处理为64位,意味着每次CPU能够读入64位长度的数据进行处理。CPU的高级缓存大小标记着一次能够从主内存中预装入多少数据到高速缓存中。

因为从主内存到CPU的数据传输也是至一个数据输入和输出过程,这个传输的速度跟CPU的运算速度还是有差距的,CPU设计时加入了一级缓存概念。

这里要说一个概念,由于CPU的位数是指代表了CPU一次操作的数据长度,由于我们编程的业务数据长度很多都长于这些位数,所以有些数据类型运算可能要读取多于一次,因为CPU是分时运算的,也就是说有可能一个数据的计算需要两个CPU的分时,而具体的分时调度是有操作系统按照一定的规则完成的,所以存在一个数据计算了一半时,CPU去处理其它数据了,即数据运算可能被分割成多次完成,每次长度都是CPU运算的位数。

也就是说在CPU单位位数长度以内的数据,是可以在一次CPU分时运算中完成的,当操作系统通过中断机制暂停某次CPU分时运算时,这类数据是不能被中断的,也就是最小运算单元,不可分割的数据,这类数据的操作被称为原子操作。

现代操作系统也开始提供对这样的操作处理句柄,于是在我们高级编程语言中会有一个基于原子操作的编程接口可用。

隔离与通讯

除了抽象以外的第二个概念就是隔离。

隔离的我们直观的理解就是独立分开,不关联。这从我们的计算机的核心设备CPU和内存设计上就体现了这一思想。

首先,我们的CPU每次读取并进行运算的数据量是有限的,也就是说我们必须在一个固定大小的空间中通过辗转腾挪来进行大量数据的运算。

如此,我们就需要对大批量的数据进行分割和打包,将它们隔离开来。这里的设计思想就是将存储的空间分成固定大小连续的块,并为每一个块标注编 或者地址,然后通过地址来标注某个块的数据。从而做到将大批量的数据隔离成我们能够通过地址操作的多个块。

从更宏观的角度上讲,我们的计算机的每一部分包括操作系统都必须先做到隔离,能够独立的被调入到CPU和内存进行处理。

从这个角度上讲,我们编写的每一个数据类型,一段代码还是一个应用程序都是被隔离在一个我们定义的空间中的。只不过由于我们应用的复杂性需要大量的空间相互组合排列或者嵌套。但是目标就是为了隔离。

让我们能够将一个数据放到特定的空间中,而我们知道这个空间跟其它空间的区别,能够读取它们。

当然,如果我们只有对数据的隔离肯定是没办法实现数据之间的关系和逻辑操作的。所以在隔离的基础上我们需要有限度的为隔离后的数据提供相互之间的联系通讯。

而这里的联系我们一般有两种,一种是组合关系,一种是传承关系,在面向对象编程思想里有”is a”和”has a”的区分,本质上就是将两个存储数据的空间隔离后,让他们之间发生一定的关联。

在这里插一点关于数据类型的定义,本质上就是定义空间大小,然后将不同大小的空间抽象成一个方便编写的符 ,比如我们最基础的抽象是bit,这是空间大小的基础单位。

以后所有的其倍数就是可以被定义为不同的数据类型,采用不同的符 表达语义,比如int,double,short等。而那些需要更多空间,空间之间关系更加复杂的数据表示,很多编程语言中不会预先定义,而是给一个自定义规则,比如我们的类,接口,枚举等等,它们本质上还是一对内存空间。

如果你熟悉Java,你就知道类的定义,其实就是给了我们一套规则来定义一个更多单元空间组合,更加复杂关系的一个更大的数据空间。

我们说在数据空间与数据空间之间的交互通讯,无非就是写入,清理,复制等操作。高级语言在设计时会设置相应的指令来完成这些基本的操作,有的是直接将数据写入到数据空间中,有的则是将数据的地址写入到空间中,而具体数据写入到其它空间,这就是我们很多初学者需要理解的值类型和引用类型。

前面文章中我们曾经说过,底层语言汇编语言,C/C++和高级语言Java,C#等它们有一个根本的区别在于底层语言可以直接去操作你定义的数据类型空间,而高级语言一般都是由一个第三方程序已经将这个空间圈定好并监控管理着其划分和清理,这就是托管语言的意义所在。

因为开发人员要自己去管理数据空间的划分隔离,联系操作,这需要对编程语言和要操作的数据非常了解才可以,一般的编程人员很难做好。

所以在高级的受托管语言,即由一个专门的应用程序管理数据空间的高级语言设计一套数据消除算法,根据监控到的数据使用情况来决定如何将数据拷贝销毁等。

关于调优

很多初学Java的同学一直不理解Java调优是怎么回事,其实很简单,我们编写的任何一个应用程序宏观上就是先要画个圈,这个圈圈定的内存空间就是我们应用程序可以运行的边界,而这个空间又是有JVM管理的,有一部分是固定大小的,有一部分是可变大小的,如果你将固定大小的部分设置太小,你的程序一启动装载的那些不变数据内容就沾满了该空间,你的程序就无法启动运行,所以你需要通过运行测试知道这部分固定数据区域需要多大,还有就是在程序运行过程中不断的动态创建的空间,这属于可变空间里的,JVM在管理这部分空间的时候,它会有一个阈值超过某个大小它就需要去清理空间,因为其管理的空间毕竟有限,而如果没有达到阈值的情况下,它会为不断增大的数据空间需求不断的增加空间,直到没有空间可以增加了。这些固定的空间一般都是我们定义的常量,应用程序类定义内容,固定的需要加载的资源内容等。

而可变的空间主要是我们程序中需要往内存添加的数据,可能只是某次运算使用,也可能是几次运算使用等,这些数据体现在我们的应用程序定义的需要驻留内存的数据类型,集合等。

还包括我们可能要自己程序控制的读入到程序空间内的外部资源数据等。

所以,我们编写的每个Java程序都需要根据它在运行过程中初始化加载数据量,动态增加的数据量,以及能够并发运行的峰值等这些指标来调整和设置管理我们应用程序数据空间的JVM的参数。找到一个适合我们应用程序顺畅运行的最佳参数配比方案,这个过程就是我们常见的调优。

隔离完成后需要建立关联和通讯,而通讯一般有两种方式,一种就是直接操作同一个空间数据,另外一种方式就是空间拷贝数据然后更新。

从这个角度我们可以理解Java内存模型的设计,就是定义一套规则来确定对同一数据空间的操作先后以及影响。从数据空间以及相互之间的关联操作角度来理解同步,并发,以及什么是原子操作,就很容易理解了。

总结

总结,最近很火的特斯拉老板埃隆马斯克很推崇第一性原理,认为是他创造出那么多成功企业的重要思维方式。我们这里也借用这一原理用到编程学习上。

也就是说编程最基本的命题或者假设是二元状态的机器,不管编程语言如何发展和变化,最终的都要回到这一原点上来。那就是如何在二元状态机器上定义数据存储空间来表达我们这个复杂的世界。

在第一性原理中,这个内容是不能被省略或删除,也不能被违背的,它是一切内容的原点。

所以,试着去理解固定空间管理科学逻辑吧,它能帮助你更好的理解编程。

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年1月13日
下一篇 2020年1月13日

相关推荐