如何学编程?
此文最早发布在新生大学平台,是为在新生大学学习编程的初学者而写
详情参见[xinshengdaxue.com]
凡是可以被思考的,都可以被清楚地思考;
凡是可以被言说的,都可以被清楚地言说;
----维特根斯坦
什么是编程?
现代计算机的起点是源于莱布尼茨的一个梦想:将人的理性还原为计算,并且有强大的机器能够执行这些计算。这就需要两个前提:
- 一切都可以被计算;
- 可以执行一切计算的机器;
从十七世纪以来,数学家和哲学家主要就是在围绕上面两个问题展开自己的研究。
在数学领域,人类已经可以用一套统一的符号来处理代数表达式,并不断尝试用符号来表征全世界所有的概念和事物。另一方面,另外一些科学家,例如笛卡尔和费马,已经论证了,可以将几何通过某种方式转换为代数。因此,那个时代最顶尖的数学家在尝试下面的步骤:
- 将全世界的知识归纳起来;
- 针对上述的全集用一套符号体系进行表征;
- 用莱布尼茨所述的“推理演算”针对这些符号进行运算。
这一艰苦但充满挑战的过程,在那个伟大时代也产生了大量优秀的人才和成果,希尔伯特、康托尔、哥德尔等人都做出了重大的贡献。其中布尔在《思维的法则》中证明了逻辑问题可以演变为数学问题,现代编程语言的运算逻辑由此奠定。而现代编程语言的概念就源自弗雷格在《概念文字》所描述的:所有演绎推理都可以归纳在一个逻辑体系内。
这段时间内,哲学家也为编程语言和计算机的产生做出了重大贡献:维特根斯坦在逻辑哲学论中为现代编程语言的面向对象思想奠定了坚实的基础:
“对象包含了事务的全部状态的可能性,……,这种固定不变的模式由对象组成”。
在数学家和哲学家将一切均可计算的梦想逐渐实现的时候,图灵描述了一种通用的计算机模型,图灵机由此诞生。冯诺伊曼等人用电子管实现了这种模型,“可以执行计算的机器”发明出来了。
一直到今天,现代编程语言依然沿着当年的套路发展,而硬件形态不管变化多大,图灵机的基本原理和冯诺伊曼体系也始终没有本质变化。
因此,简单来说,现代编程语言(或者更精确一些的说是一种“图灵完备”编程语言),应该能够完整的描述某一个现实领域的问题,并通过运算规则,操作计算设备获得分析过程和结果。
所谓学习编程,就是学习使用一种特定的语言,来描述现实世界的一个问题,再将这个问题通过计算机的运算,给出分析和解答。
进入程序的思维逻辑
很多人说编程难,主要是因为还没有具备所谓的“编程思维”。而编程思维,正如上面所述,需要用一种新的语言形式来描述世界。我们都知道那个著名的笑话:
老婆给当程序员的老公打电话:“下班顺路买一斤包子带回来,如果看到卖西瓜的,买一个。”
当晚,程序员老公手捧一个包子进了家门。。。 老婆怒道:“你怎么就买了一个包子?!”
老公答曰:“因为看到了卖西瓜的。”
这个故事,充分的表达了用程序思维和生活思维的差异。那么,为什么程序思维会有如此的不同?
第一,人类的常用表达方式和逻辑习惯的是不完备的,很多信息包含在模棱两可的描述中,而用编程的方式来描述问题,必须做到完备和精确,因为截止到目前,机器的宽容度在很大程度上还远不如一个低年龄的儿童。不管多么厉害的代码,一个逗号都不能出错。
第二,“图灵机”的思维模式,是一种机械方式,因此,当前的编程语言,难免需要符合机械流程,也就是一种线性逻辑。而人的逻辑,本质上是一个非线性的反馈系统。所以在思维决策模型上的差异,导致编程的逻辑过程必然与人脑思维过程不同。
因此,学习编程,需要让自己养成这种线性思维,或者说是一种理性的反馈系统。否则,很难从所学的知识中举一反三,并建立自己的知识体系。因此,在学习时,经常的画流程图和时序图是一个好的习惯。用一些图表将自己的思维表达清楚能够有助于用机械逻辑来表述自然思维。另一个方式是写伪代码。有兴趣的同学可以搜索一下。
了解你所写的代码
不可否认,现在写代码已经变得越来越容易,老一辈程序员执念的很多东西已经不再被年轻人提及。随着技术的演进,越来越多的普通人,只需要简单的训练,就可以完成业务逻辑的编码工作,这是技术的进步,是生产效率提高的标志。
但是对于立志成为伟大程序员的人而言,解决业务问题并非其终极目标。在这个世界中,能够写一些代码的人不少,但能成为优秀程序员的人却并不多。这导致
了一方面很多学编程的人找不到工作,另一方面,很多高薪的工作却无人应征。
怎样才能从一个普通码农演变成一个专家级程序员?上网搜一下会有很多分析,我在这里只想提一个很基本的观点:“了解你所写的代码”。
比如随便一行最简单的代码:
var a = 1;
如果你是一个普通的程序员,你应该知道这行代码解决了什么问题。如果你是一个专家级的程序员,你应该知道这些:
- 系统是如何执行这行代码的?
- 系统因为执行了这行代码,发生了哪些改变?
如果要做到这两点,你需要对以下内容有比较深刻的理解:
- 深刻的掌握你所使用的编程语言;
- 了解和掌握你的程序所运行的操作系统;
- 在某些情况下,需要了解硬件的一些特性和限制,以及操作系统在这些硬件上的影响。
因为你写的代码,作用于一台图灵机,中间需要有操作系统,可能还有你所使用的编程语言所使用的运行时(例如Java Runtime)。
如果你立志成为一名优秀的程序员,你需要从一行程序出发,一步步的追踪到硬件的执行。这时候,你会发现很多隐藏在程序之下的东西。
优雅的控制机器
很多不懂程序的人,都会发现一个现象:凡是会写代码的,都会修电脑,修手机,修一切的电子产品……
可是,写程序和修电脑之间有什么必然联系么?
事实上,是真的有联系的。修手机的能力,来源于对手机的理解和对手机的控制力。这种控制力,包括各种输入输出设备(摄像头,传感器,蓝牙),包括操作系统,包括工具类的应用软件。
如果一个程序员希望自己的代码能够在一台设备上运行良好。他确实需要关注以上这些东西。一个程序是否可以合理的使用外设?是否在操作系统中兼容性良好?是否和主流软件不冲突?都是一个程序员需要考虑的问题。因此,一个合格的程序员,确实需要习惯性的捣鼓自己的手机、自己的电脑。
对程序员而言,一个幸福的事实是,随着可穿戴设备和智能家居设备的逐步普及,越来越多的传统设备配备了操作系统,成为了可编程设备。
如今,一个程序员懂得Android开发,就可以使用程序控制电视定时播放,可以控制智能手表表针的显示样式,可以控制空调的出风温度,可以将手机和门禁连接,可以在汽车的中控台上部署一个程序和手机共享音乐……
身为一个当代程序员,有太多的机会掌握一个以前只有专业人员才能掌握的设备,可以将不同的硬件和服务连接在一起创造出新的使用场景,在这个机器拼接的世界中自由发挥自己的智慧。
常学常新,吐故纳新
学习编程是一件无止境的事业,其一是编程语言和相关的知识技能如浩瀚星河,无穷无尽,其二是新技术,新思路层出不穷,日新月异。因此,仅仅是能在一个领域跟上时代的发展,都需要付出相当的时间和精力。但这种快速的变化也为程序员带来了无穷的机遇,随着新技术的引进,一些传统的问题可以有新的解决方案,更高的效率。作为一个优秀的程序员,理应不断的自我革新,用新知识和新技能自我革新。事实上,所有的高阶程序员,具备的一个基本能力和素质,就是不断的尝试新鲜事物,不断的阅读新的项目代码。也会主动的改进之前做过的项目,那怕它们当前运行良好。
同时,也不必因为新技术太多而产生恐慌,任何技术都有其特定的价值和适用范围。不必因为出现了新东西就急于否定手头正在学习和使用的技术。每一个新技术的掌握,都建立在对现有技术的充分理解之上,因此,学好当下,恰恰是掌握未来的最佳方式。
学到不如做到
学习编程的最佳方式,就是把它做到可以运行。在学习任何一门语言或技术之前,都可以给自己设定一个目标,例如学习JavaScript,可以要求自己做一个博客;学习Android,可以要求自己做一个日历App。一个可以运行的程序,不管多简陋,都具备必要的完整性和稳定性,在完成一个可运行程序的过程中,必然涉及到诸多方面的问题和陷阱。解决这些问题的过程,正是学习的最佳路径。在学习过程中,将各种新知识和新技能应用于一个自创项目,使之不断完善,是一个非常好的办法,它天然的帮助学习者制定了学习规划和进度。有一个明确的目标,就会有明确的学习路径,解决问题时就不容易发散。更有助于提升效率,也更容易衡量学习效果。