Mayx's Home Page
by mayx
正在生成中……
大家好,我是mayx,今天由我来带领大家了解计算机编程的本质和程序设计。
当提到电脑时,大家首先想到的什么呢?打游戏?聊天?……没有问题。你们享用了电脑所带来的便利,有考虑过它的原理吗?当然,有些东西是不需要知道原理的,毕竟即使你不知道互联网传输协议也可以上网,不知道焦耳定律也可以做饭嘛……但是,我希望今天大家听了我的讲座后,能知道了解其原因后能更好的利用它们。
首先,今天我要讲的东西有以下三大类:一、计算机简介;二、编程;三、设计。
对于计算机,我想大家已经了解很多了吧,在这里我不做过多的介绍,只讲一下比较少见的知识。
大家都知道IT(信息技术)对吧,我们有一门课就是信息技术,不过你们知道CS吗?我要讲的CS可不是反恐精英,而是计算机科学(Computer Science)。CS只是和IT有交集吧,IT研究的不只是计算机,包括发邮件等通信方式,不过想来主要还是应用了计算机科学。有很多人总会把它们误用,就好像动画和动漫不是一种东西一样。
接下来我要讲的是计算机科学中的硬件部分。不过我的物理不是很好,所以硬件部分我不会讲太多,我想大家也都应该知道计算机大概都是由什么组成吧,从微观上来说就是由硅做半导体部分,铜银金等导电金属作为主要的电能以及信号传导等等的电路……往大了讲,就是CPU(中央处理器Central Processing Unit)、内存、外存、主板、I/O(输入输出 Input/Output)等作为主要部分的机器。而更细的东西我也不了解,逻辑电路什么的,如果有会在Minecraft上做红石电路的人,也许还能讲讲CPU的运行原理吧……
硬件的组成,也就是计算机组成体系,关于这一方面,大家应该都知道冯·诺依曼结构的计算机吧,我们平时用的电脑就是这个架构的,我相信只要了解一些计算机的人应该都知道这些。不过我觉得应该很少有人知道哈佛结构吧,它和冯氏很相似,只不过它的并行处理能力更好一些,因为冯氏结构不能同时读取指令和数据,而哈氏结构可以。手机一般就用的是这个结构的。
硬件部分我就讲到这里吧,想要了解更多有关硬件方面的信息,问物理老师都比我靠谱。
接下来就是软件部分了,程序是软件的子集。那么接下来我就来讲讲如何写程序吧。
首先,什么是编程?编程就是编写程序的简称,编写程序是为了解决一些需要运算而得出结果的东西。毕竟是计算机嘛,本质上就是为了运算而产生的。但是,并不是说程序只能在电脑上运行,人脑也可以,甚至是用多米诺骨牌之类的东西都可以执行程序。只是计算机的运算速度比它们都快,所以一般的程序都是在电脑上运行的。只有一些丧心病狂的面试官和考官才会让人脑去想计算结果呢。而让非计算机的东西执行程序,不是为了研究计算机的组成就是一些极客了吧……
现在写程序比以前简单多了,以前写程序不知道计算机的运行过程根本写不了程序,打孔纸带不说,就光机器码都几乎没人能看得懂。不过为了让机器看懂,人们也只能这样做了。后来为了让人能更好的写程序,发明了汇编语言。不过汇编语言本质上还是将机器码用一些其他的方式简化了,本质上仍需了解计算机的运行过程。以上所说的语言都算是低级语言,因为必须了解计算机的本质,太过复杂,而且跨平台性也很差。再后来,人们发明了FORTRAN(公式翻译 Formula Translation),这是人们发明的第一个高级语言。直到现在,已经有上千种高级编程语言了,它们的目的几乎都是将人能看懂的语言,而计算机看不懂的语言转换为计算机可以看懂的语言,即为机器码。能被直接转化为机器码的编程语言叫做编译型语言,编译它们的东西叫做编译器,它的特点是编程语言被编译生成机器码后,只能在编译它的这类机器上执行,在其他种类的机器无法执行。这种语言的优点是执行速度快,毕竟计算机可以直接使用机器码执行,只用翻译一次,没有第二次。而缺点则是编译后将无法再编辑,除非你会机器码或汇编,或将它反编译,否则就看不到它编译前的代码。除此之外,它也不能在不是编译它的计算机或同种计算机上执行。编译型语言以C语言为代表。为了解决无法编辑和跨平台的问题,人们造出了另外一种语言,即为解释型语言。
解释性语言是将程序源代码一句话一句话解释为机器码,所以它可以不用将源代码转换为机器码,这样的好处就是可编辑,而且因为是一句话一句话的解释,所以在所有机器上均可执行。但也正是因为它是一句话一句话的解释,所以执行效率低,速度也慢。解释型语言的代表是Python语言。工程师是有创造力的人,也是无法容忍问题的人。为了解决速度慢的问题,他们又创造了一种新的语言,它既有编译的高速,又有解释的跨平台性。这种语言可以在写好后先编译为一种中间语言,它已经有很多接近于机器码的部分,但是为了跨平台性,它把那些需要在不同种类的机器上语句不同的地方用其他的方式标记出来,然后发布时只发布这个由中间语言构成的的程序,在其他电脑上执行时,它会把那些特别的句子再解释执行。这样的话不就又有很好的执行效率,又有很好的跨平台性了吗?以此类为代表的语言是Java语言。
刚刚介绍的仅仅是人们让电脑如何理解人们的语言,而接下来要讲的是让人们理解人们的语言了。我说过,编程语言到现在为止已经有上千种了。如果仅仅是为了让电脑理解人类的语言,有那么几种不就够了吗,为什么还要发明那么多种语言呢?人们不了解电脑,电脑也不了解人,而且人与人之间也是互相不了解的。有些人说话的方式是这样的,有些人说话的方式是那样的,他们可能互相都无法理解对方。编程语言不仅仅是给电脑看的,也同样是给人看的。毕竟是人在写程序。编程语言也是人发明的。所以有些人可能觉得这种编程语言写起来不舒服,就会发明新的语言来让自己和与自己相似的人舒服。工程师不只有强迫症,还是完美主义者。
虽然编程语言各不相同,但是电脑就那么几样东西嘛,再多也多不出来个什么。所以编程语言也有很多相似之处。正是因为它们有很多相似之处,所以说你只要会其中一种编程语言,基本上其他编程语言只要学学语法就能直接上手。编程也不仅仅是写出程序而已,它是为了表达自己想法的一种工具。在之后的设计里我会讲一讲设计程序的一些思想。
那么编程语言有哪些最基础的东西呢?首先是它的表达,计算机,或者说任何事物,与人的交互不就是两种吗,也就是输入和输出,五感来接收外部信息,身体活动来改变外界。程序里面获取数据的方式也有两种,一是人们输入的东西,键盘、相机等等都算,二是硬盘中文件的内容;输出也一样,一是输出到如同屏幕或扬声器等地方,将其转换为物理方式,然后被人接收。二是输出到文件,这样既可以让别的程序再利用,也可以等到人们想看时再输出到输出设备。那么除了表达之外就是程序内部的计算了。
这也就是编程与数学的联系,编程除了输入输出,就是算法了,组成算法的除了循环结构之外,还有计算、变量与函数。计算和变量与数学的概念差不多,但是函数不太一样。虽然说计算机中的函数也是通过计算来将带入的值转换为一个结果,但是大多数时候,它的主要作用不是计算出一个值,而是执行一段指令,最终得到的值通常都是0,甚至有的时候是空的(NULL),也就是没有结果。虽然没有得出值,但是只要执行了指令,就可以得到真正想得到的东西。
但也不是说一个程序一定需要函数,那只是为了更方便理解,而且编程语言并不一定是给电脑使用的。我之前也说过,程序也不一定非得在电脑上执行。为了更好的理解编程语言的执行过程,我给大家介绍一种特别的编程语言:BrainF**k。BrainF**k是一种极小化的计算机语言,它是由厄本·穆勒在1993年创造的,它的语法十分简单,只有8种符号。分别是加号,减号,大于号,小于号,左中括号,右中括号,逗号和句号组成。整个程序里没有一个英文字母,如果在程序中遇到英文字母,解释器会将其忽略掉。在执行的过程中,它会创建一个很长的数组,可存储30000个数字,我们可以把它看做是30000个格子,每一个格子可以存储的最大数字为255。在程序开始之前,会有一个让你处理格子里面内容的指针,在执行程序时,如果一个符号要想操纵对应的格子,必须想办法让指针先移动到那个格子里。这8种符号的作用如下:大于号:指针向右移动一格;小于号:指针向左移动一格;加号:指针所指向的格子中的数字加一;减号:指针所指向的格子中的数字减一;句号:将所指的格子里的数字转换为ASCII表格里的对应字符并输出;逗号:将输入的内容按照ASCII表格里的内容转换为对应的数字并输入到所指的格子里;中括号:如果程序执行到右中括号时指针所指的数字是0,则执行前一个左中括号之后的指令,否则忽略这个中括号。听起来是不是很复杂?没关系,让我来演示一下你就明白了https://fatiherikli.github.io/brainfuck-visualizer/(演示)
这个语言是为了帮助理解编程语言的运行过程,想来这也就是图灵机的基本思想了,有兴趣你们回去可以再研究研究。但是BrainF**k本身并不适合用于给人们用来编写计算机程序,如果想要学习真正的编程,我建议学习Python语言,它的语言功能强大,语法简单,初学者以及程序员均可使用的语言,而且对应的中文教程也很多。所以如果有想学习编程语言的同学,我推荐学Python。
当然作为编程语言有很多选择,Python有着简单的语法,强大的功能,很高的兼容性。但是如果要是做一个网站,用世界上最好的语言——PHP(超文本预处理器Hypertext Preprocessor)语言则是一个更好的选择。如果你打算做在单片机上的程序,那么C语言似乎更好。如果你想要做手机软件,就不得不了解一下Java语言……
编程语言仅仅是一个工具,如果想要写出程序,还要学习如何设计它。接下来我们就进入第三个模块:设计。
在说设计之前,我先说说我自己。我有一个特别的能力,是什么呢?我在使用任何一款现代的电子产品或现代设计的机械,我基本上在10分钟之内搞清楚它的使用方法。当然太过古老的比如ENIAC那种不是学过电路的就完全看不懂的那种东西除外。为什么我可以做到这一点呢?首先,我见过的电子产品本来就很多,所以有一些经验。除此之外,就是我可以了解那款产品在被设计时到底是为了什么。这也是我为什么想为大家准备这个讲座的原因:想让大家明白如何了解一个陌生的产品的用法,当然如果能做出来那就更好了。
人们设计产品是为了什么,设计的初衷是什么?当然是为了让人们的生活更方便,使用更舒适。如果你心中突然有一个想要做的东西,会让它令人感觉使用起来很不适吗?我觉得一般的人都不会这样做的吧。所以说设计师在设计产品时也会想客户到底是如何使用他生产的产品,有的时候觉得自己可能想的太过片面,会弄出调查问卷或反馈之类的功能来帮助他们改善他们的产品。
但是设计一个产品很简单,造出来又是另外一回事。有时候设计这个功能有可能可以做到的,可是最终实现它又有可能花费的东西与得到的东西之间算下来不划算。出现这个问题有可能是设计的不好,也有可能是按照当前的科技水平做不到更加合理。
我们今天讲的内容既然是有关计算机的,当然要讲程序的设计,不可能讲现实世界中的设计。那么,接下来,让我来讲讲UI设计吧!
什么是UI?UI即User Interface(用户界面)的简称,在设计UI时,不仅要让用户看起来很美观,更重要的是要让用户用起来感到舒适、简单、自由。这里我要讲界面设计中比较好理解的两部分:1.外观设计,也就是让这个UI看起来更加美观;2.功能设计,这个说明了这个UI从整体看起来的实际功能。那么首先来考虑一下美观吧,毕竟大家都喜欢第一眼看上去很酷的东西。外观设计的风格有很多,比如现在很流行的扁平化风格,以及大家很常见的Windows 7 Aero风格等等。扁平化的设计很好啊,不仅界面简洁、美观,而且设计起来简单,在实际使用时也比较省资源。所以现在很多软件设计界面时都开始使用扁平化设计了。比如Windows 8到Windows 10,以及Android 5.0和iOS 9以上的系统,几乎都使用了扁平化设计。而刚刚所述的系统,几乎都是在移动端设备,或者说包含移动端设备的操作系统。所以说,这也是它的缺点,在非移动端设备上使用扁平化设计,可能甚至会令人感到反感。而且扁平化的设计虽然似乎有那么一些科技风格,但也正是因为这样,它让人感受不到亲切的感觉。在此之前,我们有另外一种方法来解决这个问题,那就是拟物化设计。我觉得Windows 7的毛玻璃应该也算拟物化。拟物化的好处是什么呢?当然是让人感觉更加亲切,因为贴近于日常生活,所以说对于用户来说也更容易学习。坏处当然也很明显,就是设计成本太高,有些东西设计师要想很长时间才能想出来如何才能让它更贴近生活。除了设计成本太高外,消耗的资源也很多,看起来也会让人可能感觉起来太花哨。以此为代表的产品是锤子手机,锤子手机上用的系统经过高度定制,每一个设计都似乎使用了身边的东西。我用过锤子手机,说实话,那个似乎很贴近人生活的设计并没有引起我的注意,而这个设计所带来的比一般手机增加的将近一倍的内存消耗,令我恨不得将这个锤子手机扔掉。可惜我现在还没有可以换的手机,所以只能先用它了。
怎么设计外观?刚刚说到的也只是一些概念,在实际设计时,如果是程序设计,我们可以使用PhotoShop等工具来设计,而对于网站设计,用CSS(层叠样式表Cascading Style Sheets)来设计可以保证它的通用性。
外表设计的再漂亮也只是第一眼看上去很漂亮,等新鲜感过去之后,基本上也就没什么用了。于是接下来就要看实际的功能如何。这里我用某些设置的设计来作为例子:Windows的系统要想设置某些东西,都要找控制面板,当然有些基础的功能在任务栏上也能用。但是Windows系统的设置通常藏得很深,没有一点基础的人很难找出来,当然也有可能是他语文学的不好,理解不来。而Android系统的设置就不一样了,它相比Windows系统就更加人性化了。不过想来也是,以前电脑都是给懂的人用的,虽然现在的电脑相比以前已经人性化很多了,但还是有些地方让人应付不来。手机出来的晚,生产出来时就已经有了为全世界人们使用的觉悟了,所以用起来也比较简单。总结下来就是:好的功能设计要为每一种人设计,无论他有多专业,还是说从来没有接触过这一切,要让人第一眼看上去就明白它有什么基本功能,而更高级一些的功能可以先隐藏起来,等用户需要使用时再显现出来,免得吓坏一些不会用电脑的人。烂的功能设计有两种:1.想要找的功能没有,可能根本没提供。2.想要找的功能找不到,可能藏得太深了。
你们以为UI都是有图像的吗?错了!有图像的UI叫做GUI(图形用户界面Graphical User Interface),但不是所有人用的电脑都是可以显示图像的,只是大多数人都用的是图形界面,图形界面看起来比较清晰,使用起来也比较方便。但是图形界面的效率低,无论是电脑的执行效率还是用户使用时的工作效率。不知有没有人听过DOS(磁盘操作系统Disk Operating System)?你们如果没听说过可以回去问问你的父母。在以前图形化的操作系统还没出来时,人们用的都是CLI(命令行界面Command Line Interface)。大家在看那些有着黑客入侵的电影时,黑客们是不是都看起来都在胡乱拍键盘,其实那真的是在胡乱拍键盘(演示:http://geektyper.com/),而电脑屏幕上有一堆看不懂的类似于英文单词的东西从屏幕滚过?虽然那是艺术的表现形式,有点太夸张,但是艺术源于生活,现实中真的有人使用那种看起来似乎很酷炫的东西。但是他们不是为了耍帅而使用CLI的,而是由于各种原因不得不使用他们。这样的例子有服务器操作系统,以及IRC(互联网中继聊天 Internet Relay Chat),用这个聊天比QQ什么的聊天软件更快,更省流量,效率高。
我之前也说过,电脑中很多设计由于经费等原因,不得不让它从界面上看起来不太人性化。但是这并不是没有办法解决了。人之间的交流不止有图像,更重要的是文字。电脑也一样,电脑与人的交流在术语上叫做HCI(人机交互 Human-Computer Interaction)。来看一个实例:如果我想设计一个网站,但是我审美观不行,这个网站怎么样才能让人感到亲切呢?既然从整体没办法做到更好,那就在细节上加倍努力吧!一般的网站上都有登录系统吧,那么我们可以这样设计:对于初次访问的人,我们可以在网站上显示:欢迎来到我的网站。当然只显示一次,之后不再显示。在登录之后,刚登录完可以显示:欢迎回来,某某某。或者是根据时间显示:下午好,某某某。这样和“某某网站 用户:某某某”这样的方式更容易让人接受吧。这样用户就能在潜意识里把这个网站看作一个人,而不仅仅是网站。这样即使外表看起来不怎么样,但是用户体验总还是不错的吧。没错,这一块的设计就叫做UED(用户体验设计User Experience Design),为了提高用户满意度,我们就通过这样的方式来让程序更易用。
除了以上所讲的部分,界面设计还有许多部分。由于篇幅原因,这里我将不再过多说明
以上是关于用户体验设计方面的,接下来让我说说程序设计吧!我之前也说过,编程语言只是工具,实际使用时还需要考虑程序的逻辑、架构、界面等等东西。在以前,程序设计中算法是非常重要的,但那也是以前,多亏很多计算机大神的帮助,现在的编程那是越来越简单了,一个几岁的小孩子就能写出来比以前的程序更漂亮、更复杂的程序。所以,现在算法在计算机编程的重要性越来越低了……但是并不是说算法就没有用了,如果没有人去研究算法,那么人们在遇到新的问题就没人能解决了。尽管以我们这个级别的人研究算法可能没法做出新的东西,但是我还是觉得,让更多的人了解程序背后的原理,可以帮助理解程序如何使用。所以接下来,让我说说关于算法与逻辑吧!
仍然是举个例子:大家都听过音乐吧,在播放音乐时有一个选项:随机播放,对吧?随机播放的实现方式有很多,让我们深层次的来研究一下它吧。首先,随机播放中,有个很重要东西,那就是随机。说到随机就不得不说随机数了,随机数也分为两种:真随机数与伪随机数,真随机数的生成在现实中很简单,在计算机中生成起来就很麻烦了,所以首先抛弃。伪随机数的算法很多,这里我们用最简单、最通用的伪随机数的算法:线性同余取随机数,看过离散数学的人可能有听说过这个。为什么我们选这种算法?因为其他算法我看不懂,比如什么梅森旋转算法啦,一听名字就能感觉它有多难了吧,反正我看了半天是没有理解。什么是线性同余?就是算一个一次函数的余数,相当简单,它的递推公式是:X0=seed,Xn+1≡(aXn+b)modM。seed表示随机数的种子,通常取当前时间,a,b,M都是常数,通常会取质数。在seed与n都相同时,这个随机数就能被反推出来,所以很不安全。但是想来做随机播放也不担心别人会不会推出随机数,所以我们就用这个就能得到一个随机数。具体原理我也不太清楚,有兴趣的可以问问数学老师。接下来,我们要创造一张表,那张表上有着你要播放的播放列表,但是这时候它还没有被打乱。首先我们要知道整张表上有多少首音乐,假如我们用a来代表当前所有音乐的数量,然后我们再为所有的音乐编上号,看起来就是1、2、3……。这时候每一首音乐都有了一个属于自己的编号。再然后,我们对用随机数公式得出的数字求余,即Xmod(a+1),这样做就可以得到一个不超过所有音乐数量的随机数了。当然前提是随机数本身的最大值大于所有的音乐数量,所以在随机数公式中的M要尽可能取大一些。得到最后需要的随机数后,命令播放器播放编号等于随机数的那个对应的音乐。当需要播放下一首或切歌时,为了避免又播到这一首歌,我们可以将那张表上的那首音乐删除,当然是在表里删,不可能删这个文件。然后重复之前的操作。在最后一个音乐播放完成之后,表里已经没有东西了。这时有两个选择,如果用户打开了全部重复播放,那么重新建表,重新开始。如果没有,则停止。看起来是不是很完美的方案?错了!用户总是喜欢做反设计师的操作,万一用户点了上一首,怎么样才能回到上一首?那么我们就需要修改一下方案,我们要建两张表,把从表里删除的那个操作换成将它移动到第二张表里。这样如果用户需要听上一首歌,就可以读上一张表的内容。难道说这样就完美了吗?不完全,但是这个BUG我现在不说出来,大家自己思考思考吧。
除了逻辑设计,还有算法设计。我们再举一个例子:如果说我们在设计程序时需要用到质数,比如需要列出1到1000之内的所有质数。那么我们用什么方法更好呢?首先根据质数的定义,质数是一个不会被除了1和它本身的数所整除的数字,而且质数不包括1。那么接下来设计起来就很简单了,只要让当前数字不停的除以除它和1之外的在1到这个数字之间的所有数字就可以了。这很好,但是速度很慢。可能这样算1000以内的所有质数还不算太慢,那如果是10万以内呢?这得算多长时间啊……所以我们要对算法进行优化。我们知道,合数有一个特点,任何一个合数一定是由比它小的质数相乘得出的,那么接下来,我们可以这样筛选合数,首先我们算出第一个质数,在算第二个数时只要和之前算过的质数相除,能除尽就是合数,除不尽就是质数。这样是不是计算量一下就大大减少了呢?但是这还不是最优化的方案,如果说我们已经知道我们要算的最大数字是多少,那么只需要除以比这个最大数字的算术平方根小的质数就够了。这样每次算的时候需要除的数字又少了一半,算起来速度就会更快了。虽然这个算法不错,但有时我们甚至不需要这个算法就可以更好的解决这个问题。因为我说的是列出1到1000之内的所有质数,这个数字又不是很多,那么我们可以提前算好,这样就可以更快的解决问题了,这样的操作我们叫它预计算(Precomputed)。
程序设计是一个很严谨的事情,每一个方面都需要做到最好。但是人无完人,总有我们想不到的地方。尤其是计算机安全方面的事情,总有你想不到的地方,总有别人比你多想的地方,正是因为这样,才会出现黑客这样的人。这里我仍然用举例子的方式为大家展示程序设计的漏洞:我最早发现的网站漏洞似乎是在一个主机商的网站上看见的。由于一个很偶然的原因,我看到了那个主机商,而那时我正好想建一个网站,然后就在那个网站上注册了一个账号。那个主机商正好在搞活动,好像是买主机可以给你便宜5块钱,而账号初始上也有5块钱,主机最便宜的每个月也要30块钱。然后我想了想,要不然我干脆买上0.1个月的主机吧,0.1个月应该是3块钱,我应该能付的起。于是我在购买里输入了0.1,当然结果是失败的,它不能让你买小数或者是负数之类的月数。但是我返回来惊奇的发现,我的账户里居然多出来了5块钱,我想了想,它应该是对我的账户上减去了0-5元钱,毕竟是在搞活动,然后算一下5-(-5)=10。这个好啊,我感觉我可以免费得到那个主机商的主机了。于是我通过这个BUG买了1年的主机,居然成功了。当然在大约10天后被发现了,账户也被封禁了。通过这个例子我们应该明白,不要相信任何用户输入的数据,还好我仅仅是用这个漏洞买主机,很明显,这个漏洞甚至可以通过SQL注入之类的东西破坏他们的主机系统。不过这个例子似乎离日常生活有点远,那么接下来我再说一个近一点的事情:在几周前,我们不是进行了禁毒考试吗?我看了一下那个网站,很明显是一个宁夏的网站公司包办的东西。一看就知道是一个做的很不认真的网站。我在答题前看了一下源代码,发现它在批阅卷子时先在本机批一遍,只有成绩大于60分时才会把答题数据传到服务器中再批一遍。这样确实可以有效的减小网站的负载,但是这不就把答案也下载到本机上了么……于是我照着答案就在禁毒考试中得了A。这个例子又告诉了我们什么呢?就是不要将不应该让用户看到的东西下载到客户端中。
总的来说,做一个程序并不复杂,但是做一个逻辑严谨,界面美观而易用的好程序就没那么简单了。设计师在设计时需要考虑各种各样方面的东西来让用户用的舒服,又要想尽各种办法防止整个程序出现奇奇怪怪的BUG。这也就是为什么说写程序很难了。但是我希望大家听完这个讲座后能改变对写程序的看法,它看起来很复杂,但是只要仔细思考,就能解决一切问题。
以上就是我对编程以及设计的看法,也许语句中有不通顺之处,请大家谅解;如果有不对的地方,欢迎大家批评指正。
最后,谢谢大家前来听我的演讲,谢谢大家对我的支持与信任,本次演讲结束。