英文原文:The main pillars of learning programming — and why beginners should master them.
编者按:随着众多传统工作面临失业风险,编程成为 21 世纪必备的技能。网上有许多编程的资料,也有各种各样的培训班,但是很多都没有抓住编程的重点方面,其教菜鸟的办法很糟糕。为此,有 20 多年编程经验的 Rainer Hahnekamp 总结了新手学习编程的 5 大支柱,希望初学者能够从中掌握到学习的方法。
我编程都已经超过 20 年了。在这段时间内,很高兴能跟很多人一起工作,我从他们身上学到了很多。同时我也接触了很多的学生,他们都是刚刚大学毕业的新人,这时候我就得担负起老师或者导师的角色。
最近,我作为培训师参与到一项教完全的初学者学编程的计划当中。
学习如何编程是很难的。我经常发现大学课程和新手训练营没有抓住编程的重点方面,其教菜鸟的办法很糟糕。
为此,我愿将我所认为的一门成功的编程课程必备的 5 大支柱分享给大家。一如以往地,我会将介绍放在主流 web 应用的背景下。
菜鸟的目标是掌握编程的基础并且理解库和框架的重要性。
像云、一般运营或者开发工具这样的高级主题不应该成为课程的一部分。说到设计模式我也持怀疑态度。这需要的经验是初学者所不具备的。
那么我们就来看看程序员新手应该从何开始。
测试驱动开发(TDD)
TDD 带来了很多好处。不幸的是,这是一个高级主题,初学者恐怕还没有完全准备好。
初学者不应该写测试。对于他们的基础技能水平来说这要求太高了。相反,他们应该学习如何使用测试以及配合测试。
每一门编程课程都应该以练习为核心。我把练习拓展到单元测试,给学生一个已经为运行那些测试做好设置的环境。
学生需要做的就只是写他们的代码然后看着 testrunner 的灯从红色变成绿色。结果的游戏化是一个很好的副效应。
比方说:如果选定技术是 Spring,我在一个 Spring 项目内会提供练习和测试。学生不需要知道 Spring 的任何事情。他们所需要做的就是知道练习和触发测试的按钮在什么位置。
此外,学生必须知道如何使用调试器并且要有一个读取﹣求值﹣输出循环(REPL)环境。在运行时分析代码的能力以及有一个进行小型实验的场地对于 TDD 要说是必不可少的。
要点是要确保学生在习得核心变成技能之后不需要学习基本的 TDD 行为。在学生职业生涯后期改变习惯要比现在学习这些习惯困难得多。这就是为什么他们应该从一开始就感受单元测试的原因。
在其以后的职业生涯里,他们应该会对没有进行单元测试的项目感到厌恶。他们应该本能的将缺少单元测试视为反模式。
基础优先
我经常听说菜鸟应该马上从框架开始学习。这就好比把人放到赛车上让对方避免转向过度一样教人如何开车。这根本是忽视了他们仍然会把刹车误认成油门的事实。
一开始让学生学 Angular 这样的框架也是同理。初学者首先需要理解编程的基础。在使用别人的代码之前,的他们需要熟悉基本要素以及写代码意味着什么。
函数、变量、条件、循环这些改变对于新手来说完全就是陌生的。这四个要素构成了编程的基础。程序构成的一切都要靠它们。
学生都是第一次听说这些概念,但是他们最终精通这些概念是极其重要的。如果学生没掌握这些基础,后续的一切看起来就像是魔术一样,会导致迷惑和沮丧。
教师应该在这些基础上花更多的时间。不过,悲哀的是,很多人向前推进得太快了。问题在于很多教师没能从学生的角度去考虑问题。他们编程有些年头了,已经忘了初学者必须应对的问题类型是什么了。这相当类似于专业赛车手。赛车手是无法想象某人刹车前还要想一下的。他的动作都是自动的。
我设计练习会利用这四种要素的结合,一方面要具有挑战性,同时在合理的时间范围内又是可以解决的。
一个很好的例子是罗马与阿拉伯数字的转换。这个挑战需要学生有耐心。一旦他们成功应用了 4 个要素解决了这个问题,其积极性就会得到很大的促进。
基础很重要。在学会基础之前不要贸然前进。
库和框架
在学生花费了大量时间去编程后,他们必须知道大多数代码已经以库或者框架的形式存在了。这与其说是一种模式不如说是一种理念。
就像我之前写过那样:现代开发者了解并选择合适的库。他们不会浪费时间自己去写一个充满 bug 的版本。
要想让这种理念转变成功,“基础阶段”的例子应该用 Moment.js、Jackson、Lodash 或者 Apache Commons 等知名的库来解决。
这样一来,学生马上就能理解库的价值了。之前他们曾经绞尽脑汁去解决这些复杂问题。现在他们发现库一下子就把那些练习给搞定了。
跟 TDD 类似,学生应该对同时吹嘘自己编写的状态管理库秒杀 Redux 保持怀疑态度。
说到框架,一旦理解了库的用处之后学生理解其重要性就会毫无问题。
取决于课程的时间长短,专门开辟时间将框架也许会比较困难。但是正如我已经指出那样,最重要的方面是心态的转变——从一切都白手起家自己写转到使用库来实现。
我没有给这根支柱添加工具,因为工具只对有经验的开发者有用。在现在这个早期阶段,学生不需要了解如何集成和配置工具。
师傅与徒弟
我 20 出头的时候曾想学钢琴。我不想找老师,以为我自己就能学。5 年后,我咨询了一位专业家教。怎么说呢。那 1 个月内我学到的东西就比我 5 年时间学到的还要多。
我的钢琴老师指出了我在演奏过程中出现的错误,那些是我自己听不到的,这让我意识到一些我从未想象过的东西。毕竟,她给我灌输了音乐和艺术的理念,这些都不是我这个搞技术的人能了解的。
编程也一样。如果某人对编程毫无经验,则自学就是个糟糕想法。尽管有很多成功故事,但我质疑其效率。
相反,应该有一种“师徒”关系。一开始时,师傅给出规则让徒弟遵守——盲从!师傅可能会解释一下规则,但通常推理会超出徒弟的理解范围。
这些内化的规则会形成一道安全网。如果一个人迷路了,能保证有一些安全地带可以返回。
教学不应该是独白。师傅必须因材施教。应该看看学生是怎么做的,然后给出建议,根据他们的进展情况调整课程速度。
挑战与激励
“我们来做个 Facebook 克隆版吧!”这话不是出自有一群资深开发者和数百万欧元预算撑腰的 CEO。而是来自一门针对程序员的介绍性课程的练习。这样一项任务几乎是不可能的。甚至更糟的是,学生被放到仙境里面被哄骗以为自己有做超出自身能力的技能。
教师无疑是意识到这点的,但出于激励的原因还是设立这样的练习。
练习的主要目标不是娱乐。练习应该围绕着特定技术设立,同时应该帮助学生理解那项技术。
激励是好的,但不要牺牲掉内容:编程不易。如果学生缺乏内在动机,编码这条路也许不合适。
新手应该体会到成为职业开发者意味着什么。在投入大量时间之前他们应该知道等待他们的是什么。
比方说,很多商业应用围绕着复杂表格进行处理。创建表格是练习可以赋予的一项重要技能。开发类似 Facebook 那样的应用也许不是学生马上就能学习的最佳课程。
类似地,非程序员可能会对开发者每天写的代码行数至少感到惊讶。甚至有时候我们还删除代码或者一事无成。
为什么?因为总有状况发生。我们花费了无数时间去修复一些极其怪异的 bug,结果最后发现只是拼写错误而已。一些工具工作不了可能仅仅因为一个库进行了小型的版本升级。或者因为某人忘记把一个文件添加到 git 而系统崩溃。这样的事情可以一直列下去。
学生应该享受这些练习。在时间压力下面向一个未知库的练习未必合适。
现实生活中不是每天都充满阳光。初学者应该对编程的现实做好充分准备。
最后建议
最后但并非最不重要的一点:一个人无法在 2 周、2 月或甚至 2 年之内成为职业程序员。这需要时间和耐心。
培训师不应该赶时间或者做出虚假承诺。他们应该聚焦在学生是否理解了概念上面,而不是赶得太快。