你是怎么学的?


这些年来,我被问过很多次,我到底是如何学习新东西的,不管是新的编程语言,新的平台,什么的。这显然是一个高度个人化的(意思是特定于提供答案的个人)主题,所以我的方法可能对你有用,也可能不有用;不管怎么说,我还是建议大家试一试,如果成功,那就冷静点。

关于我如何学习新知识,首先要理解的是,我完全同意我们前国防部长唐纳德·拉姆斯菲尔德的观点,他说有“三种知识”:

  1. 你知道的你知道的。换句话说,你已经知道的东西。你对这门学科有经验性的知识。我知道C++:我知道大部分的关键字,我知道几乎所有的语法,我理解语言如何编译的机制,以及它编译成什么,等等。就我个人而言,我认为自己“了解”一个主题,如果我使用它,在某种程度上,为一个适度复杂的任务。“hello world”不算数(如果我们说的是编程语言),但是做一个code katas可以,如果它有一些好的“范围”(做一些I/O,一些算法练习,等等)。
  2. 你知道的你却不知道。我知道这个问题,但我没有花太多时间在这方面。然而,对我自己来说,这一类别和下面这一类别之间的关键区别是,“我是否理解这个主题的目的是什么?我知道这是“两句话故事”吗?我能把这个故事讲给别人听吗?“(一会儿我会讲更多关于这两句话的故事。)这通常意味着在这个主题上做了一点阅读,或者做了“Hello World”/入门教程。我知道的足够多,可以很好地了解这件事在世界上的位置,但如果不做更多的阅读和研究,我还不足以开始做这件事。
  3. 你所不知道的。我对这个问题一无所知;我都不知道它的存在。显然,这对我来说很难举出例子,因为如果我知道有任何例子,我已经把它们移到第二类了。其中一种可能性是Kali Linux(从我看到的几篇文章/书籍的上下文来看,以及刚才参考网站获得其地址)显然是一个专为进行安全攻击和渗透测试而定制的Linux发行版。我不知道是什么让这个发行版在某种程度上比其他发行版更好,所以现在除了你刚才读到的以外,我还不能围绕它写一个两句话的故事。(即便如此,人们可能会争辩说,既然我知道它,我现在才知道我对它一无所知,因此它属于第二类,而不是这类。)

困惑了吗?这并不是一个很难解释的问题,但它开启了知识与无知的概念--我可以知道一件事,或者我可以意识到一件事却一无所知,或者我可以对一件事一无所知。(当然,其他人会对这些区别有不同的解释,这也没关系。这就是我如何将这一点应用到我需要了解的与工作相关的讨论/约会等话题上的。)

所以,假设某人或某事引起了我的注意,下面(大致)是我学习新事物的过程:

在上面写一个两句话的故事

“两句故事”这个术语可以追溯到我在Developmentor的时候。当我们在编制新的课堂材料时,常见的副词是,“这个东西的两句故事是什么?”换句话说,如果你只能用两句话描述这个东西,他们会说什么?最初,TSS更多地围绕类本身进行设计--“这个类的两句话是什么?”--这与为整个技术设计TSS有一点不同,但我发现它是一种有用的机制,可以帮助识别和隔离我所关心的某一特定技术的新事物的各个方面。一些例子:

  • AspectJ:面向方面编程是“元对象编程”的一种风格,这是一种代码机制,它寻求捕获“跨越”传统面向对象层次结构,围绕字段和/或方法的一流构造,并在多种情况下可重用地应用这些构造。AspectJ是在JVM上运行的针对Java语言的AOP的基于语言的实现。
  • Groovy:Ruby和Java有一天晚上在酒吧相遇,度过了一个激情之夜。Groovy是最受欢迎孩子,它展示了Ruby的语言倾向,但具有Java的底层结构和(或多或少)公共语言遗产。
  • Parrot:一个面向寄存器的虚拟机,它为动态语言寻求JVM或CLR为静态类型的对象语言(Java和C#)所提供的功能。最初与Perl语言的下一代紧密联系在一起,结果或多或少与它一起消亡了。
  • MongoDB:一个无模式的,面向文档的数据库,编写成在没有任何平台依赖(静态链接的可执行文件)的情况下运行。Mongo希望提供一些传统的基于服务器的数据库体验,这些体验对于那些习惯于传统RDBMS环境的人来说是熟悉和舒适的,同时也提供那些来自NoSQL人群所期望的“自由形式”体验,包括能够“扩展”到大型数据集,而无需对访问它的代码进行大量重新编程。
  • BOO:一种基于Python的CLR语言,它为插件打开编译器管道,以便在执行之前查看和/或修改代码的AST。在CLR上解释和/或编译。
  • CouchDB:一个无模式,面向文档的数据库,它在第n个程度上支持HTTP和REST,同时也支持分布式版本控制系统所青睐的“分布式非集中式”模型。换句话说,Couch没有一个单一的真理来源,而是通过复制和乐观的更新共同决定了真理可能是什么。
  • Lua:一种动态类型的以元组为中心的脚本语言,旨在轻松地嵌入到本机平台环境中,尤其是从C/C++代码中嵌入。它广泛应用于游戏行业,并且有一个设计非常好的FFI(外部函数接口),专门用于在“高级”Lua代码和它下面的原生实现之间实现轻松的互操作。

正如你所知道的,并不是所有这些都是用学术语言包裹的,因为在某些情况下,它们特别地绑定在我自己对其他事情的理解上。例如,Groovy是“Ruby和Java一夜情的爱情孩子”,这告诉了我很多事情--也就是说,Groovy运行在JVM上,可以被看作是“另一个Java”,但它受到了Ruby遗传的很多影响。(考虑到James Strachan刚开始研究Ruby时,他非常特别地想要介绍他在Ruby中看到的一些东西,这并不奇怪。)

这里的关键是,两句话的故事是我自己的故事;对我来说,这有点私人色彩,因为它是我熟悉的其他事情的关键。我并不期望我对任何一个特定主题的两句话的故事,当我单独看或者在我的头脑之外这样看的时候,实际上会传授给其他人很多关于实际理解的东西。纯粹是为了我。

但显然,要想制定一个关于它的TSS,还需要进行一些研究。

这东西是什么样子的?

像大多数人一样,我没有太多的时间,所以我需要相当快地处理一件事情。所以当我第一次看一个主题的时候,目标是找到一些我已经知道的东西,它和/或它是相似的,和/或它是从它下降的,或者是基于它的。虽然建立了最初的联系,但并不意味着我对这件事已经有了足够的了解--接下来,我必须开始寻找它与锚点不同的方式:“A”怎么不像“B”?没有两个事物“A”和“B”是完全相同的,那么区别在哪里呢?这些差异有多大?这是不是意味着我需要一个新的锚来支撑我对新事物的理解?

例如,当我第一次学习Ruby时,它与其他面向对象的语言有明显的相似之处。因此,很容易将其视为“另一个Java”或“另一个C#”。然而,Ruby是动态的O-O,而Java和C#是静态类型的O-O,因此连接很弱。更弱的是,C++编译为本机代码,而Java编译为字节码并在虚拟机上运行;Ruby不做这两件事。它是一种直接解释的语言,所以这更不是一个比较。是的,Java/C#和Ruby都有“对象”,“字段”和“方法”的概念,但这就像是在暗示法拉利和Mack卡车是相似的,因为它们都有“引擎”,“车轮”和“驾驶员”。

当我开始从周围的Ruby爱好者那里听到更多关于Ruby的信息时,Ruby和Smalltalk之间开始形成一种更精确的连接--两者都是对象语言,但都是动态类型的,并且都支持一些非常相似的“元编程”,最显著的是“method_missing”的思想,在该思想中,试图在没有所述方法的对象上调用一个方法不会导致编译时或运行时错误,而是可能通过一个定义良好的“陷阱”来处理请求,然后在运行时检查方法调用以确定下一步做什么。(顺便说一下,这就是ActiveRecord的工作原理。)

哦,Ruby的语法最初是非常基于Perl的,但后来已经变得非常成熟,以至于大多数知名的Ruby爱好者都避免使用Perl,所以现在读起来更像“英语”了。(对那些不是英语母语的人表示歉意。)

显然,这不是百分之百准确的Ruby求和。例如,JRuby是一个运行在JVM之上的Ruby实现,因此,它有点不符合我前面所说的对它的解释。够公平的。但在这种细微差别的水平上,我很明显地脱离了第二类,进入了第一类。

这东西是干什么用的?

开始理解一件事的最好方法之一就是看它是用来做什么的。对于我们大多数人来说,Ruby是因为Rails而脱颖而出的。(当时我认识的几个经常谈论Ruby和RoR的人都喜欢说:“Ruby-on-Rails是一种用于生成web应用程序的特定领域语言。”)方法很明显:Ruby是关于快速生成web应用程序的。不担心微调,不担心性能,目标是快速推出一个新的web应用程序。

不管是对是错,这将Ruby画成了一个更高级的工具,一个喷漆枪,如果你愿意的话,它将迅速喷出大量的东西,而不太关心边缘的控制程度。(顺便说一句,这也没关系,即使它对Ruby本身的解释可能有点误导。)这种定位故意把它放在Java等工具的对立面,当然也与C++相去甚远。

但是它也(也许是错误的)错误地将Ruby描述为“仅仅”一个web工具,结果Ruby错过了它所代表的“跨平台”特性,而JavaScript/Node社区正努力利用这一特性。

用它!

假设我现在对事物有了更好的把握,下一步,把它从“已知的未知”中拿出来,带入“已知的已知”中,就是试着把它用在某事上。

与…相反popular myth“每个人学的东西都不一样”,实际使用一个东西仍然是抓住一个主题并保持它的最好方法之一。在这个特定的例子中,我的意思并不是说仅仅浏览一个现有的教程并重复步骤,而是创建您自己的项目并从头到尾苦读一遍。有时候,一遍又一遍地做同一个项目是有帮助的,但有时候我想尝试一些新的东西,部分原因是我想探索一个想法或概念。

一个很好的例子:15年前,我想要一个博客,当时,所有现有的博客都不是我想要的。(我不记得为什么了--我可能只是告诉自己,因为我也想写自己的。我只是不记得了。)更重要的是,我有一个关于自我修改JSP页面的想法:从编码的角度来看,如果我有一个像Wiki一样会自我修改的博客实现,实际意义会是什么?换句话说,创建一篇新的博客文章就等于将一个新的JSP页面写入磁盘,随后对该页面的请求就像对任何其他JSP页面一样,只是在动态中编译该JSP?所以我构建了这个实现(实际上是和家人在迪斯尼乐园度假的时候),而且很酷!起作用了。不过,它也有一些问题--例如,我必须对servlet过滤器进行一些创新,并将其用作传统MVC模型中的“控制器”--但这让我明白,过滤器在MVC模型中可能与servlet一样好,如果不是更好的话。(这也是15年后NodeJS“中间件”对我来说意义重大的原因。)

另一个例子:一两年前,我的一个朋友找到我,想知道开发一个web应用程序有多难,它可以让志愿者追踪自己的工作时间,并使他们能够更容易地生成必须发送的电子邮件报告。(他是一个部门的领导,负责一个志愿者组织的西北太平洋部门,公司希望每月收到关于哪些人在哪些地点做什么工作的电子邮件。他必须跟踪那些人,然后将他们的电子邮件手工消化成一个更大的电子邮件,然后发送给公司,这样他每个月都要花费几个小时才能更好地利用。)当时,我正在学习AngularJS,所以我想,“当然,为什么不呢?”我为他构建了一个粗略的原型,AngularJS在前端,但是(这是一个大胆的架构举动!),我决定尝试“无服务器”,转而使用MongoLab到云中的MongoDB实例。它工作了,但我一直在和AngularJS斗争,谢天谢地,他从来没有真正开始在任何类似生产的能力中使用它,因为那些代码绝对是一团糟。直到工作的最后,我才开始看到“角度的方式”,到那时,我不得不把它全部撕碎,重新开始。(我一直试图将它作为一种杂碎的jQuery来使用,但效果并不是很好。)

这些“强制功能”项目通常是与生产需求不太接近的项目,通常围绕我自己的兴趣和/或问题。最近的“Devopsing The Blog”项目就是一个很好的例子:我遇到了一个问题,我决定探索如何使用TeamCity来解决它,结果是。(话虽如此,一位评论者提出了我认为可能是a much better solution到Twitter和LinkedIn的自动发帖,我现在也在探索这个问题。如果你是从我的Facebook feed上看到这篇文章的,那么Facebook的集成--我不确定是否会保留,我们会看到的--是有效的,我只需要决定我想保留哪种方法。)

理想情况下,“强制功能”项目将是我可以扔掉并放弃的项目,因为有时,使用特定工具或特定方法的尝试将会以惊人的失败告终,由此产生的混乱将是没有人,尤其是我,想要支持的。所以它总是更好的不使用一个项目,我正在得到作为一个强迫功能项目的报酬。(唯一的警告是:如果客户知道这是一个我正在使用的“强制功能”项目,并且他们口头上和合同上同意付钱让我去探索它,那就另当别论了。在我看来,任何其他事情都是违反职业道德的。)但是希望这个项目不是微不足道的(没有CRUD应用程序),并且应该比我在工具的教程部分看到的更大一些。

在某些情况下,重用强制功能会很有帮助--例如,blog。我可能会重做那哥们的志愿服务系统MeteorJS,看看它的效果如何,并比较这两种方法。

在任何情况下,做一个像这样的强迫函数项目,通常足以将某些东西从类别2纳入到类别1中,从那里,我倾向于将它留在那里。

摘要

可能还有其他几个技巧我现在就忘了(或者可能甚至没有意识到我在做,直到我发现自己在做),如果有什么事发生,我会追加/更新帖子。但就目前而言,这基本上就是它的发展方向。