原文地址

在你学习编程的过程中会有一个时刻, 一切都开发发生改变. 在 Firehose, 我们常常称之为编程的拐点(inflection point of coding). 在这个阶段之后, 作为一个开发人员, 你的各种行为都会变得不同. 经历过这个拐点之后, 你将能够自己编写程序解决问题, 而不再需要手把手的帮助. 这可能是一段痛苦的经历, 但是当你经历过后, 你将从中获得巨大的提升.

graph-1

Firehose, 我们的目标不仅仅是教你 Ruby 语言, 怎么编写 web 程序或这怎么编写测试脚本, 虽然我们也教你这些技能,但是我们最根本的目标是加速学生通过编程转折点, 从而使他们能够拥有解决现实问题的能力. 我们相信能自行解决问题是一项宝贵的能力, 并且这个教学方法也可以让你学习到更多的知识, 而不仅仅学习一些程序的编写.

入门阶段(3-8周的编程)

当你开始学习编写程序的时候, 会有大量你并不知道的问题. 这些信息叫做 特定领域知识(domain-specific knowledge). 比如: 知道怎么用 Ruby 语言编写一个循环或从数据库中提取数据等. 特定领域知识包括在一个特定的编程环境下所需要了解的全部内容.

成为一个独立的开发者第一步就是学习如何完成一个具体指定的任务. 当你能够完成一些任务, 你就会慢慢清楚这些代码如何在更大的范畴内组合. 随着时间的推移, 你会慢慢认识到设计模式的重要性, 那些一开始陌生和令人困惑的东西, 最后也会也会变得很好理解且易用.

PS. 从编写一段代码到写一个程序再到写一个软件, 就是范畴的不断增大

对于初学者来说, 这最重要的能力是关注细节

在查阅文档或者教程的时候, 关注细节是非常重要的. 即便是最小的拼写错误也可能会导致错误的信息或 bug 出现. 一开始看到错误信息是令人沮丧的, 但是这是整个学习过程中至关重要的一部分. 在这个阶段, 处理错误信息和问题能够帮助你掌握一个重要的编程技能: 关注细节.

根据错误信息进行调试是非常重要的, 因为处理错误信息本身就是编程的一部分. 无论是菜鸟还是老鸟在编程过程中都会面临错误信息. 唯一的区别是, 处理错误信息的经验越丰富解决问题就越快. 这主要是因为:

  • 随着经验的积累, 你将会学到如何根据错误信息快速定位到问题的细节. 一开始你看到错误信息的时候, 你可能要花很多时间去发现问题所在. 但是当你看过成百上千的错误信息之后, 你就能熟练地根据错误信息快速定位到问题的细节了.

  • 你应该从你解决过的每一条错误信息里学习. 在修复程序程序错误的时候, 更重要的事情是理解为什么会出现这样的错误. 从你遇到的每一个错误信息里学习, 下一次你遇到类似错误的时候就能够快速解决.

  • 一开始遇到问题的时候, 你可能需要寻求外部的帮助. 随着经验的积累, 你会自己检查代码或者使用 Google 快速解决问题, 这样你寻求别人帮助的频率就会大大下降.

在接受指导阶段, 你会接受一系列的具体教学指引. 一开始, 你可能会发现跟上教学的进度并不那么容易, 错误信息此起彼伏. 随着时间推移, 你锻炼出了 debug 的能力, 并且越来越注重细节, 这个时候你跟上进度就变得更加容易. 当你完成了整个接受指导的阶段, 编写代码的速度会大幅上升.

在这个时候, 一些人觉得非常自信——好像他们已经不再需要接受系统性的指导并试着造一些东西——最后开心的掉入深渊而不自知. 另外一些人会读更多的教程, 试图获取更多的特定领域知识, 以达到“完全理解”的程度. 不幸的是, 教学指导只能带你走到这里, 仅靠教程和指导无法获得真正的自信. 真正的自信来自于面对一个你无法解决的问题, 经过一番挣扎之后最终独立解决问题的过程.

关于编程一个不可告人的小秘密是……

你永远不会完全知道解决问题所需要的一切知识. 你也许认为持续编程之旅, 总有一天你会学到一切需要学习的东西, 然后觉得编程索然无味. 想多了, 这一天永远不会到来.

PS. 选择了计算机编程, 就是选择了面向未知编程, 选择了一生逆流而上. 学习是逆人性的, 但是满怀好奇心去探索未知, 不断解决问题, 创造出精准的程序是令人兴奋的. 这就是编程的痛并快乐着.

编程是一种终身学习体验. 经验丰富的软件工程师对于他们尚未解决的问题孜孜不倦地寻求解决方案, 是因为这能让他们有机会学到更多的东西. 如果你期望某一天你会了解编程的一切, 记住, 那一天永远不会到来. 这不是一件坏事.

learn to code

当你做好如下的准备时, 就可以开始下一阶段了:

  • 你对错误信息已经习以为常, 因为你看过太多的错误信息了, 你可以迅速解码出错误信息的意义, 并且找到代码中出问题的地方

  • 你已经非常擅长使用 Google 解决问题了. 当你要有一个新功能需求或者遇到了一个令人困扰的错误信息时, 你知道如何去搜索所需信息

  • 你能够使用你在应用的其他部分编写的代码并遵循设计模式去解决问题, 而不总是寻求一步一步的说明/指南

拐点阶段(良好心态下大概2-4周)

拐点阶段是学习编程时最让人沮丧的阶段, 从各种角度来说, 这也是一个非常重要的阶段. 当你不再依靠教程, 开始解决没人提供完整解决方案的问题时, 这就是拐点阶段.

有时你会觉得你还没有准备好面对这个阶段, 可能想要回去根据详尽的说明和指南去编写程序. 不要沦为这种心态的牺牲品. 你觉得很受打击的原因可能是:

在拐点阶段, 你编程的速度可能是之前阶段的 1/10 ~ 1/20

你可能开始怀疑自己是否有能力成为一个程序员. 在这个阶段感到这些问题是正常的.

尽管你学习和编程的速度在下降, 但事实上, 你在完成最重要的事情. 当你在特定领域的知识足够丰富的时候, 你所学的东西实际上是过程性知识.

过程性知识是一种持续学习的能力. 当你需要实现一个新功能的时候, 你要用什么关键词搜索? 这个阶段很多你想要做意见事情的时候, 你会感到自己处于一片黑暗之中. 黑夜给了你黑色的眼睛, 你却用它寻找光明, 这是一种很重要的能力. 因为你永远不可能了解所有东西, 所以你必须教会自己如何自我学习去解决手头的问题.

大部分人没有意识到, 学习编程需要同时学习特定领域知识与过程性知识.

在人生的每一天里探索自我边界以外的东西

很多软件工程师一但找到自己的立足点, 就停留在自己的舒适区内. 这种程序员被叫做维护程序员——显然不是你应该成为的类型. 相反, 每一天你都应该试着做超越自我的事情. 大部分程序员辞职的原因是: 我已经解决了所有有趣的问题, 再也没什么挑战了.

PS. 在中国有一个, 程序员35岁中年危机的说法. 个人以为也是因为这些程序员丧失了探索未知的梦想, 信心和孩子气. 一个人开始废掉的标志之一就是习惯于待在自己的舒适区.

相比将代码和项目拉入到你的舒适区, 你更应该去尝试解决那些超出你的能力范围之外的问题, 这是习得和拓展新技能的唯一方法.

下边是一个越过了拐点的学员的感想:

我依然感觉到身处深渊, 但我感觉棒极了, 因为这就是我要呆的地方.

在Web开发中, 实际上有两个拐点一同出现

第一个拐点: Web 开发拐点, 出现在你能够创建任何基于数据库驱动的应用时. 这意味着你有能力创建一个拥有许多页面, 从一个简单的数据库进行存取数据的Web应用. Web开发者管这个叫做: “精通增删改查”. 在这个阶段, 你还可以通过阅读文档, Github 或者技术博客, 将一个第三方库(比如 Ruby Gem)集成到自己的 Web 应用中.

第二个拐点: 算法与数据结构拐点, 是一个不那么明显的拐点, 但实际上更加重要. 已经征服了这个拐点的人, 会精通他们所用的编程语言, 了解编程的基础体系, 拥有面对复杂问题的深厚知识储备.

越过算法与数据结构拐点的人通常可以:

  • 写排序算法
  • 实现并反转链表
  • 理解和编写使用栈、队列、树的程序
  • 使用递归和迭代思想编写程序

简要的说, 一旦你越过了这个拐点, 你就掌握了如何操作数据, 并且了解代码的性能影响. 大学里传统的计算机科学教育特别注重让学生越过算法与数据结构拐点. 但很多大学都使用在业界已经不流行的语言来教授这一点, 比如 Scheme, RacketLISP.

在大部分技术面试中, 面试官都假设面试者已经越过了 Web 开发拐点, 因为这个拐点相对容易, 所以会将问题集中在评估面试者的算法和数据结构能力上. 通常面试问题会集中在上边提到的几个方面: 排序算法, 反转链表, 使用栈、队列和树.

一旦开发者同时越过了 Web 开发拐点和算法与数据结构拐点, 他就掌握了整个世界.

这些开发者能够解决两者兼备的挑战: 在复杂的高级Web应用内构建复杂的算法. 这是专业的Web开发者每天都要做的事情.

征服拐点之后

征服拐点之后, 你将明白的东西听上去有点违反直觉:

对于学习编程, 特定领域的知识在宏观角度并不重要.

我并没有开玩笑, 特定领域的知识确实没有那么重要. 一旦你通过拐点, 你会在一到两个星期, 甚至几天内理解这句话.

真正重要的东西是:

  • 对于一个Web框架牢固的掌握
  • 在任何编程语言中编写复杂算法的代码

HR 希望开发者同时具备 Web 开发技能和算法技能

我在 Paypal 工作时, 我的团队招进来一个高级 Ruby Rails 开发工程师, 但是之前他没有任何 Rails 经验, 只有 Python, LISPPerl 经验. 仅仅在几天之内, 他已经给我们带来很大震撼. 几星期之后是巨大的震撼. 他迅速被提升为技术团队的领导, 也是我当时最成功的招聘决定之一.

不要盲目追求热点, 许多人说: “最近 Angular.JS 好热门”, “ JavaScript 上升势头猛烈”, “最近流行用…”. 我对此的回复是: “那么又如何呢?”. 当你开始学习编程时, 你唯一的目标是找到拐点然后越过拐点, 当你成功之后, 学习那些新的, 好玩的东西毫不困难.

自力更生, 拥有无需结构化的指导, 就可以学习新编程技能的能力, 意味着你无需等待别人帮助你. 对于你所需要学习的大部分知识, 你可以搜索互联网或者阅读各种材料.

PS. 自己去探索学习, 而不是学习别人写好指南, 整套告诉你的知识. 这样反而能够学到更多东西.

这并不意味着你可以迅速“了解”所有东西, 而是意味着现在所有的东西都是“可以去了解”的, 实际上, 你将所向披靡.

在拐点时你将练就的技能

作为一个软件开发者, 最好的参考资料, 就是你编写过的类似代码. 你完全理解了你所编写的代码之后, 不必将所有的细节都记住. 当你开发一个新功能的时候, 首先问自己: “我之前做过类似的东西吗?” 如果答案是Yes, 看一下以前写过的类似代码, 在脑子里一行行的重放代码, 重新解释给自己看, 然后问自己: “我现在可以使用相同的方式解决问题吗?”

视频并不是学习特定领域知识的好材料, 因为视频通常耗费大量观看时间. 比如你想调用 Google Maps API, 你亲自动手, 在 Github 上找到相关代码, 复制到一个新建的项目, 可能花费不到一分钟. 而通过视频指导, 看一遍可能需要10-30 分钟.

高效率征服拐点的一些策略

由于征服拐点是学习编程中最重要的事情, 所以你必须让自己尽可能顺利的越过这个阶段. 这意味着你必须在接受指导阶段就开始进行准备, 并在整个过程中保持正确的心态.

在接受指导阶段, 除了学习结构性的指导材料, 还要全程给自己一些挑战.

对于每一课, 尝试做超过教学范围的事情. 如果书上有“挑战”或者“自己努力完成”的问题, 把它们全部做掉. 解决没有指导的问题会带来无需结构化指导便能解决问题的重要经验.

尝试尽可能少的依赖教学材料. 在 Firehose, 我们通常让学生通过文档了解如何集成一些gems或者实现一些代码. 对学生来说, 他们主要根据程序文档操作, 教学材料仅作为备查, 而不是单纯的依赖教学材料按部就班的学习. 注意, 文档会将阅读者视为已经跨越了拐点的开发者. 习惯了在 Github 上阅读文档, 对你自力更生是莫大的帮助.
关注要点与可复用性. 从头开始编写应用程序, 提交一个新应用到 Github 或者 Heroku, 尽早构建数据库迁移.
越过拐点可能具有挑战性, 这里有一些建议值得尝试:

了解越过拐点是一个困难的过程, 别给自己太大压力, 并且设定现实的目标. 你不能将你在接受指导阶段的“超人”一般敲代码速度和这个阶段的蜗牛速度进行比较. 要记得你一直在学习很多东西, 在这个阶段, 你正在学习的是可以自己搞定全新事物的能力.

如果你自信心略有不足, 要知道你的感受是完全正常的. 继续努力, 如果你依然很挣扎, 试着和已经越过拐点的人交流一下, 也许他们会了解你现在所处的位置, 并且告诉你这种感受只是暂时的. 持续努力, 但不要过度劳累. 在学习编程的这个阶段, 你每天最多只能有效率的工作6个小时. 在疲劳的状态下学习只会延长你跨越拐点的时间.

这个阶段获取信心的最佳方式是解决自己遇到的疑难问题. 你的情绪可能会像过山车一样. 有时候你觉得你自己好像被放在火上烤, 但经过在一个问题上15小时的努力之后, 你可能有完全相反的感受.

如果你在某件事情上花费了5分钟到5个小时, 依然没有头绪, 确实很令人沮丧, 但每次你成功搞定一个问题, 实现一个功能, 那种自信源源不断涌现的感觉是你最需要的. 在不依靠帮助解决了很多困难的问题之后, 你会沉醉于在你的舒适区之外不断解决问题的感觉.

如何知道你已经跨越了拐点

拐点过程的最后阶段是接受. 接受软件开发是一个持续学习的过程. 如果你感觉已经学习了所有东西, 只意味着你应该想一想如何解决更复杂的问题.