导言

自学编程是一种态度。从来没有学习过编程的同学自学编程更是一种值得尊敬的态度。在之前的一篇文章中我以R语言的学习为例简单地讨论了一些学习的通用技巧,然后又通过阅读《如何学习》一书写了两篇笔记对一些通用学习方法进行了一部分补充。

这篇文章则主要是介绍我自学编程时候的一些经验,主要围绕“初学者在自学编程时可能会遇到的困难以及如何克服这些困难”展开。

正式开始之前,我们一起来看一下这两个短片快速学习一部分与“学习”有关的概念和方法:

这两个视频最主要传达的思想如下:

  • 多角度观察/实践一项事物有助于我们更全面和深入地理解/掌握该项事物(比如3/4这个数字?)
  • 长周期分散学习的效果优于短时间高强度学习(这一条我想起了很多只有两天的培训班)
  • 学习效果 ~ 质量和效率(专注度、从慢到快、定时定量的练习、合理的休息以及回想)+ 时间
  • 挑战我们自身的极限达到新的高度

补充:

  • 假设自己要将学习的内容系统地教授给他人可以提高你的学习效率和分数(这一条是我想起了另外某个视频所补充)
  • 和高手一起学习(鸡头或者凤尾?)
  • ……

需要注意:上面仅仅是我总结出来的信息(可能会遗漏很多额外信息),最好的可能是由你自己来进行总结。

和自学编程相比,学习这两个视频所传达的信息应该相对容易。你完全可以将学习这两个视频所传达的信息作为你的一次自学练习,并记录下你的总结,这个“总结”的过程在以后你自学编程的路上会经常需要。

自学编程的几个阶段

第一阶段:无感期(完全没想过要去学习编程)

以我自己为例:本科生物工程专业,只在上两门课期间接触编程:计算机基础课程和C语言课程。潜在相关的课程也有一些:工科数学、线性代数、生物统计学等。本科阶段从大二开始做一些分子生物学相关的课题(抽DNA/RNA、跑胶……),所以完全没有想过要系统去学习编程以及计算机科学知识。或许现在你也处于这一阶段。

第二阶段:入门期

以我自己为例:大三考研的时候我就开始想在生物信息学方向进一步学习和深造。所以,当时边复习考研科目,也在学习一些Python(在线的一些教程入门)和Linux操作(《鸟哥的私房菜》入门)。因为当时主要还是以复习考研科目为主,平时并没有去接触一些实际的项目,真正到复试的时候,很多操作已经生疏。当时另外一个课题组的师兄出了一些题目,现场我都没能操作出来(这会让别人对你的印象很不好,也充分说明准备和复习的重要性),有一些我需要想一段时间才记起来应该怎么做。

进入课题组之后,导师给了几个月的时间去学习编程,主要是ShellPythonRHTML/CSSJavaScriptBootstrap)、PHPMySQL(没有硬性要求Perl)。额外的一些工具也是在这个时候学会的:vim的操作、登陆远程服务器的工具等。

主要攻坚下面几本书:

  • 《鸟哥的Linux私房菜》
  • 《Shell脚本学习指南》
  • 《Python学习手册》
  • 《R语言实战》
  • 《R语言核心技术手册》
  • 《R数据可视化手册》

其他的就是看互联上的一些文字教程,比如w3school菜鸟教程廖雪峰写的一些教程等等。

除了学习编程,这个阶段我已经开始接触实验室的课题,最开始是用PhotoshopillustratorExcel处理一些图片、表格(本科和硕士一年级干过学院级宣传部的部长,所以这些任务相对比较容易)。同时,我也需要用bash运行一些命令行工具、用RPython处理数据、开发简单的数据分析脚本、用PHPBootstrap开发一些简单的网页界面。

第三阶段:项目实践期

学习编程不可能永远只处于入门阶段,比如只停留在对变量类型、循环、条件判断等编程基本概念的了解。在项目实践期,基于之前积累的编程知识和初步实践,大部分人的语法问题应该已经基本解决。这个时候也就进入了编程学习进程中最重要的一个阶段:通过大量实际项目检验之前学习到的知识并学习新的知识(理论和工具使用都需要)。

以我自己为例:我在这个阶段能基本看懂别人写的代码(如果有比较好的注释的话),也是这个时候学会去用print来调试代码,看代码的输入和输出,同时学会了gitGitHub来管理代码的版本。也做了一些“第一次”项目:

第四阶段:回顾反思期和深入学习

通过第三阶段的实际项目锻炼,我们也就拥有了实际的编程开发经验。而这个时候最需要的就是自己的反思,去思考自己哪方面知识有所欠缺。从而选择自己感兴趣的方向,学习其他项目的相关源码以及相关书籍的特定章节(主题)来进一步提高你在某个方向上的的编程水平。

编程世界大量存在着这样一群人:觉得某些实现方案比自己的更佳,就会对之前的项目进行优化和重构,不断迭代。

编程世界也大量存在着这样一群人:对已有的工具不满,想到了更好的功能和实现,就会大胆的去实现出来并发布,并且不断迭代。

不是所有人都能够轻松在这一阶段有所突破,这个阶段的学习会维持很长很长一段时间,而且往往新技术的产生的速度远远会超出你的想象,一直能保持好的学习心态以及动手实践的热请是非常有挑战的一件事,而且我们除了需要进一步学习更多的知识和技能,还要经常去回顾以前的项目经验和编程技巧。

书山有路勤为径 学海无涯苦作舟

第五阶段:出神入化期

除非你天赋异禀或者兴趣浓厚,对于大多数人来说应该很难达到第五阶段(哪怕你是计算机科班出身)。这个阶段最主要的特征:计算机理论知识精通、熟悉计算机硬件、算法精通、编程语言随意切换、对编程语言的核心库和第三方库信手拈来、拥有较大影响力(比如能够出版一本被当做经典的书籍),动不动就可以自己开发出一种编程语言出来。

初学者自学编程可能会遇到的困难

拍脑袋一想,初学者自学编程可能会遇到的两大类困难,一个是学习动机和学习兴趣方面产生的问题,另一个则是学习方法论上的问题:

  • 容易失去学习的兴趣(比如看不懂、学不懂、挫折感满满、做不到坚持学习等等)
  • 不知道如何去学习(找不到适合自己的学习资料、有问题不知道问谁、学习效率低、容易忘记等等)

如何克服自学编程时候遇到的困难

克服自学编程遇到的困难是一个系统工程,为了尽量简洁明了的来初步回答这个问题,我在这里用了三个小标题:

  • 给自己一个强烈的动机
  • “造轮子”的重要性
  • 进阶之路:挑战难题

很多问题和细节可能很难一下子讨论周全,但是通过这三个部分的内容,我相信至少已经可以为你解决一部分问题。

给自己一个强烈的动机

“被逼”这个被动的动作本身是一件很痛苦的事情,特别是逼你去做完全没有兴趣或者没有什么价值的事情。学习新的东西对于我们来说一般是有一定成本的,而与之相对应的是往往我们都想要获得一些回报(价值)。

自学编程这件事情在初期一般也是“被逼”的,比如老板让你学某个新的技术、毕业课题必须要用编程、你想用编程开发工具等等。然而,随着时间的进行,最初“被逼”自学编程的同学可能就会产生分化:一部分学习很主动,思考和实践的意愿非常强烈;另外一部分对学习很消极,不愿意花多少心思去琢磨和实践。

造成分化的原因我这里暂时想到了一点:挫败感的打击,成就感的缺失,而且自尊心不强。

如果想要自学好编程并且坚持下去做出一些成果,你需要完成的第一个任务就是尽早击败挫败感、找到成就感,培养提高自尊心。

  • 击败挫败感:先从简单的学起,从简单的练起,越简单的概念可能越要重视(从掌握简单的概念开始也可以减少挫败感的产生)
  • 找到成就感:解决一个TODO,解决一个问题,做出一个成果,发表一篇文章,做一次公开展示
  • 培养提高自尊心:……(相对比较困难,需要长期的内部和外部因素影响)

“造轮子”的重要性

“造轮子”是编程里的一种相对偏贬义的词,即“轮子”在原始社会已经被造出来,现在你还要去“发明”这个“轮子”。不过,对初学编程的同学来说,“造轮子”确非常有用。一个是因为同样一个“轮子”可以有不同的造法可以加深我们对于“轮子”的理解,同时也会让我们手变得更加熟练。

以一个非常常用的“轮子”为例:求一个数列中的最大值(R语言)。你能够想到多少种求解方式?用这个轮子你可以学会多少R函数?

## 实现方法一(现成的轮子)
num_seq <- c(2, 3, 2, 10, 23, 22, 21)
x <- max(num_seq)

## 实现方法二(sort)
x <- sort(num_seq, decreasing = TRUE)[1]

num_seq_new <- num_seq
## 实现方法三
while (TRUE) {
  x <- min(num_seq_new)
  if (all(num_seq_new == x)) { 
    break 
  } else {
    num_seq_new <- num_seq_new[num_seq_new != x]
  }
}
x <- num_seq_new

## 实现方法四
max <- NULL
for(i in num_seq) {
  if (is.null(max)) {
    max <- i
  } else if (i > max) {
    max <- i
  }
}
x <- max

## 实现方法五
my_max <- function(num_seq) {
  if (length(num_seq) == 1) {
    x <- num_seq
  } else {
    x <- sort(num_seq, decreasing = TRUE)[1]
  }
}
x <- my_max(num_seq)

## 轮子的本身实现:.Primitive可以获取R语言的原函数(用C语言编写)
my_max <- .Primitive("max")
x <- my_max(num_seq)

## 其他?

通过同一个轮子的不同的制造方法,你学到的可能已经不再只是相关的函数本身,同时还有可能涉及更多的背景知识、基础原理、算法知识等等。

上面求数列的最大值这个问题只是编程语言中最简单的一个需求之一,基本上所有编程语言涉及到的问题都可以这样来练习。这个简单的练习也和文章开头引入的思想一致:多角度的观察和实践有助于理解和掌握。

最为重要的是,当你在进行的这些多角度尝试的过程中,如果想到了别人没有想到的某种实现方案,做出了之前没有人做出来的成果,那是不是也会给你带来一些成就感?从而进一步促进你的学习热情?

进阶之路:挑战难题

要想精通某项技能,比如编程,挑战难题是必不可少的。这里的“难题”是相对于我们自己而言,即同学A觉得是难题的事情,同学B可能觉得不难,你觉得简单,其他人可能觉得难。

我们如果想有效突破现在的知识和技能水平的上限,最好的方式可能就是挑战一项对自己具有挑战的任务。这个任务的难度也就决定了我们现在所能达到的某个高度。

文章的最后用一段排比句结束:

如果你之前从来不懂编程,现在你已经可以熟练地写出你的程序并且让很多人用你的程序,这是一种突破(更加形象一点的描述:如果你之前不会写R包、Python模块等,现在你已经学会并且可以独立开发你的R包和Python模块,并且有能力发布至公共平台供他人使用)。

如果你之前对算法一点都不懂,现在你能够基于已有的算法并作出改进,这是一种突破。

如果你之前从来没有去系统地教别人怎么学习编程,而现在你通过你的文章、视频不仅教会别人人如何学习编程,而且教会了别人如何编程,这更是一种突破。

突破自己在编程技能上的极限就是编程学习。

扩展阅读

下面是我之前写的几篇笔记和文章,其中有一部分与自学编程这个主题相关,你可以快速的浏览看看。

网页前端大神尤雨溪写的这篇介绍Vue学习路线的文章也会对你有所启发: