掐指算来我开始学习编程也差不多快要五年了,在此道上我应该算是略显愚笨之人,看到大神的光鲜履历实在难以望其项背。直到现在我也常常问我自己:我应该如何学习编程?五年了,虽然我觉得我还只是管中窥豹,但是我也不是初出茅庐的小菜鸟了,昨天看到了王垠的博文:如何掌握所有的程序语言 ,想说说我自己的想法。当然即使王垠在微软不得志,我跟他的水平也有着数量级的差距,就当是一些瞎BB吧。

我没接触过函数式编程,所以这一块就……

有的东西写错了也没办法……反正也不会有人看。全文约3400字。

学编程是学什么

学计算机还是学编程

现在的大学是没有专门的CODE专业的,只有计算机相关的专业,这不是没有道理的,也不是因为coder码农是最近才出现的职业,而是因为编程本身并没有什么学习的意义;

  1. 记住一些关键字
  2. 把脑内的解决方案翻译一遍
  3. 键盘上敲出来(编程)

这就是所谓“编写一个程序”把大象塞进冰箱的工作。第一步和最后一步我想不是什么问题,所以编程难,难就难在第二步。

而第二步又分为

  • 如何分析问题
  • 如何得到解决问题的步骤
  • 如何用编程语言来表达这些步骤

如何分析问题是算法,乃至于数学与逻辑学的范畴。第二步则需要你对于所能使用的工具足够熟悉,就像数学家可以把尺寸算的很精确,但是不会用锯子榔头也做不出来一把椅子;这要求你懂得操作系统、计算机网络、数据库、数据结构等应用型的知识。第三步才是编程语言介入的环节,选一种编程语言来实现你脑中构思好的步骤。

所以不存在可以单独学习的“编程”这种东西,编程必然是要建立在扎实的@楚哥计算机知识的基础上,三大件不行只有方向盘手感不错的车必然不是好车,单纯的从语言入手而不顾及其他的知识是注定学不好编程的。

学语言是要学什么

举个夸张点的例子。我发现很多编程培训班和野鸡大学的编程入门课,往往一来就教学生如何使用 printf 打印“Hello World!”,进而要他们记忆 printf 的各种“格式字符”的意义,要他们实现各种复杂格式的打印输出,甚至要求打印到文本文件里,然后再读出来……

这是垠神博客里的一段话,我现在看来是真的觉得很有道理。学一种语言写的第一个程序都是输出一个“Hello world.”这个习惯来自于K&R的C Programming Language,因为C语言以及这本书的历史地位而成为了一种惯例。但是实际上printf并不是C语言的一部分,它是函数库提供的一个输出函数,用这个函数来写第一个C程序无可厚非,但是一上来就要求死记硬背各种格式控制字符就属于很扯了。

但是初学者几乎肯定是分不清这其中的区别的,他们很可能会纠结于一些函数的实现细节而忽略了什么是语言本身的特性,什么是库函数提供的特性。我想说的是学习一门语言学的不是函数的使用,而是语言的变量定义、流程控制、函数定义等部分。垠神的博客中还提到了类型推导、lambda表达式、垃圾回收、指针等应该学习的东西,我觉得这些已经超出了最简单的“使用”语言的范畴,程序员这个群体中大概大多数都没怎么也不会接触这些东西吧,包括我也是对这其中不少东西还是了解的不是很清楚(比如C++的类型推导),我认为对于一两门有兴趣的语言有所了解就行。

为什么要学

我想很多人都是为了高薪来当码农,当然我也不例外。高薪是一部分,但是只为了高薪是不够的,编程是一种让人快乐的事情。下面这段话深得我心:

首先,这种快乐是一种创造事物的纯粹快乐。如同小孩在玩泥巴时感到的快乐一样,成年人喜欢创建事物,特别是自己进行设计。……

其次,这种快乐来自于开发对他人有用的东西。……

第三,快乐来自于整个过程体现的一股强大的魅力——将相互啮合的零部件组装在一起,看到它们以精妙的方式运行着,并收到了预期的效果。……

第四,这种快乐是持续学习的快乐,它来自于这项工作的非重复性。……

最后,这种快乐还来自于在易于驾驭的介质上工作。程序员,就像诗人一样,几乎仅仅在单纯的思考中工作。程序员凭空地运用自己的想象,来建造自己的“城堡”。……

——《人月神话》第一章

我认为编程这一活动属于马斯洛需求层次理论中最高的自我实现,就像是文学、电影、音乐等创作型活动一样,本身就是有足够的魅力的,能从中找到乐趣那么学起来自然事半功倍。

学到什么程度

程度随语言不同

现在所能见到的大多数流行语言(非函数式)都是所谓类C语言,在最基本的语法上总是能见到C的影子。所以对于不同的语言,他们的基本语法是相通的,搞明白了一种比较基础的语言,就可以说基本可以使用现在所能见到的大部分语言了。

我曾经在知乎上看到一个说法,建议一个程序员应该掌握三种语言:

  1. 一门OOP语言(C++/Java)
  2. 一门脚本语言
  3. 一门函数式语言

当然我还要再加上一门C语言。我觉得这种说法还是比较合理的,同样,我也认为需要达到的掌握程度是递减的。

关于C

其中比较特殊的是C,我认为C是每个想要学习计算机(编程)的人都必须掌握的。当然,C的语法是比较简单的,但是因为C是那么底层,那么贴近硬件,而且基本上最底层的软件如OS、数据库、服务器、解释器、硬件驱动等都使用C,所以想要深入的学习下去,C是绕不过去的。另一方面,通过学习C,比如函数的调用、指针的使用、编译链接的细节等,可以与其他部分的知识相对照,会有一种茅塞顿开的感觉,不禁想说一句なるほど。

所以,掌握C不仅是C的语法本身,更是它背后的传统计算机科学知识,我觉得这应该是研究最深的。

关于C++/Java

这一部分可能还要加上Go?不过Go现在还躺在的我的学习计划小本子中,所以……不提不提溜了溜了

我认为这是应该第二深入的部分,具体到什么程度呢……我想应该是编译、运行的细节吧。也就是两个方面:编译器+运行环境。

对于编译,不仅要知道一个语言特性是如何使用的,也应该知道编译器是如何实现这一特性的(比如面试必问的虚函数)。知其然而且知其所以然,虽然不一定能提高代码效率和质量,但是可以做到真正的心中有数,不会被编译器的一些诡异行为带到沟里去,调试的时候也可以做到游刃有余,对于生成的目标代码不至于有一些错误的印象。

对于运行环境,C++和Java有所不同,C++与C类似,而Java却需要去了解JVM等虚拟机的实现(仍然是C/C++)。同样,了解了运行环境才能对程序的运行情况了然于心,知道在什么阶段可能会出什么样的问题。比如我最近用C++写的一个动态库放到测试服务器上直接coredump,原因是SIGFPE浮点错误,而我的程序中根本就没有浮点计算,最终发现原因出现在ld.so这个库的版本不一致导致加载动态库出错。这样的问题看源代码是没有用的,因为本来就没有问题,需要你对于运行时的整个过程有一定了解才行。

关于脚本语言

对于脚本语言我是没有什么深入研究的,虽然用过Python,PHP,JS来写过程序,但是都没有怎么深入的了结果,全部都是拿来就用,连一本教程都没看过。其实这才是熟练掌握了几门语言后在遇到一门新语言时应该出现的情况。打开语言官网,找到tutorial/handbook/documentation,花几十分钟读一下前几章就可以上手了。

实习期间我有一次需要写一个Shell脚本来封装一下我写的一个可执行程序,需要检查重复进程,处理输出文件,检查出错以及数据上报等功能,本来我是从来没有写过也没有学习过Shell脚本的,但是花了一上午不到两个小时的时间看了看语法后就可以写了。虽然没有研究一些细节的深入的特性,但是也达到了能使用的程度;而且也没有必要学的那么仔细对不对?毕竟是临时有用的东西,等到什么时候需要了解其他特性的时候再去学习也不迟。

应该怎么学

Google是最好的老师

国内大学中的课程实在是太慢了,而且也远远地与现实脱节,因此,自学是想学好计算机的人所必须具备的技能。而都是自学,用百度自学的和用Google自学的效率完全不可同日而语。所以,想学编程,第一步从扔掉百度开始。

选好教材

对于初学者来说一本好的教材是很重要的,当然入门之后就不是很需要语言教材了,因为更深层的东西不会写在语言教材里,它们在操作系统,计算机网络,编译原理,虚拟机等书籍中。国外的经典教材是最好的,也不要畏惧大部头,一般不会跟国内拼凑版的教材一样那么枯燥无味。更重要的是要坚持读下去。我是不支持通过看视频来学习的,信息密度相比于读书来说低了太多,而且质量也没有保证。

英语可能更重要

是的,相比于一门编程语言来说,要想学好编程,英语可能更重要一点。我一直认为数学能力不是必须的,但是逻辑思维能力和足够的英语能力是成为好程序员的重要条件。也不需要太高,过了六级就差不多,毕竟技术书籍和文档不会出现过于晦涩的文法和单词。英语搭配Google会使你的学习直接走上快车道。

还是要多练习

这一点是说给我自己听的,我也知道要多看源码,多写。看源码也不是什么过于艰难的事情,但是我总是以没时间,没有引起我的兴趣而不去做。这样不行,是时候定个小目标了。