怎样学习新编程语言,且能兼顾工作与生活

本文是翻译,版权归原作者所有



我不是要写一篇关于「生活技巧」方面的文章,但是,在过去几周里,有一个问题时常出现:

「你是怎样找到学习 Elixir 的时间的?不用工作、或保持单身,肯定更好吧 :P」

首先声明,我肯定不精通 Elixir,但是我找到了学习这门语言的方法。我在周末把前两个 package 推到了 Hex,我过得非常开心。

我也结婚了,有两个孩子,我在 Pluralsight 快乐地做着全职工作(真心比全职工作要多)。但是,我仍然有足够的时间投入到 Elixir,我愿意分享我是怎么做到的。

这里我只是得出一个小结论:一系列小胜利。我给自己设定一些小任务,搞定这些小任务就能导致带来更多的小胜利,我给自己定的下一个目标,就是学习 Elixir。一系列小胜利,无需太多。下面我详细谈谈。

本文综合了「生活技巧」和可操作的步骤,通过两周的课程,我还算熟练了这门语言。不管你喜欢什么语言,都应该适用。Elixir 是我学过的第 7 门语言(不包括我学过的 HTML 和 CSS):

上面列出的语言不分顺序,我们可能对「SQL 是否为真正的编程语言」存在争议,但是我曾用 PLPGSQL 编程,因此我说它就是:P

闲言少叙,书归正传。

给你自己下决心

做个决定,不要胡扯了。不要对自己说扯淡的话,比如:

我还能举出例子,不过你已经明白我的意思了。有很多让人沮丧的东西,它们只会浇灭你的灵感,让你感到不适。不要这样。

它只是热门一时(或:「我是个混蛋」)

每当我学习一门语言时,人们就对我说这样的话,Pasal(因为当时是 1980 年代)和 SQL(因为它是永远存在着的、老黄牛式的语言) 除外。从足够长的跨度看,每个事物的热门都是一时的,当你大声说这句话时,你就成了彻头彻尾的混蛋。或许你是对的,你正在使用的语言,在若干年后可能消失——你仍然像个让人厌恶的混蛋,因此要警觉,你的话是怎样影响其他人的,主要是怎样影响到你自己。

混蛋通常什么也不做,只是坐在线外,喊着场内队员的名字。不用管他们。你拉着你的四轮小车,想走多远就走多远,做一个更好的自己。我们处在一个不断变化、不断发展的行业,你需要随之移动,否则你就变成了场外观众。

市场上还没有岗位需求/用户案例/我能用它做什么呢?

你在这里只是正在打开一扇门,而不是解决一个问题。即使你从中没有积累到什么,你也拓宽了你的视野、锻炼了你解决问题的能力,这总归是好的。你不可能因为试着学习某样东西而做错事情。

当你在学习时,你或许发现自己正在创造一些有趣的东东、或用一种更加优雅的方式解决问题,你可以将其用到平时工作中。在我学习 Ruby 时,我就是这样做的——想法启示了我的大脑,我创建了 Subsonic、以及受此语言所激发的一些其它项目。

在未来几年里,你从来预料不到会发生什么。Ruby 和 JavaScript 在多年前还没有市场,Java 和 .NET 同样如此。关注前沿,或者亲自定义前沿。

下决心。只要……下个决心。然后……

执行

在我展开讨论之前,我需要你注意到执行的重要性。做了决定之后,你不能说「哦,哦,等我有时间了……或许这周末有时间」。不要这样,你必须执行,理论上可以是每天午餐当中的 10 分钟,或晚上的 2 个小时,要用在代码上、而不是在疯狂地玩 Xbox。

接下来就是如何给自己安排胜任的小任务了——从一个胜利走向另一个胜利,创造一个你可掌控的节奏。但是,如果你做不到,也就谈不上什么胜利了。我把「学习 Elixir 的时间」规划在每天的日历上,将其作为我需要坚持的约定。由于这种约定太多了,我有时会做的不够。

这是我对自己的投资,对自己职业生涯的投资。我没有时间产生质疑,我将不折不扣地执行。

下面是一些简单的步骤,需要脚踏实地地做,而不是停留在空想阶段。它们看起来有点儿傻,但是每个步骤都是对你交付的解释,即,一次小胜利:

好吧,现在让我们开始写代码。

我的一系列小胜利

我做为程序员,简直糟透了,因此对我而言,不要向我的无能与缺乏自信低头,这是至关重要的。我决定学习 Elixir,为自己安排执行的时间——现在,问题变成了,我需要真正做什么?

有个目标,固然不错,但是,如果你对其一无所知就定下来了,那么它也可能打击你。所以,跳过这个目标,让我们执行下去,过个好时光!

任务一:创建一个新项目

这有多容易呢?在 C#/.NET 下,点击 文件 > 新项目,挑选你想要的项目类型。如果用 Ruby,那就是单个文件,然后发展到结构良好的目录集合。那里有点儿像荒野的西部,不过值得一试。在 Node 下,那就是 npm init my_project

在 Elixir 下,借助快速的 Google 搜索,就能得到详细的解释

mix new my_project

➜  Projects  mix new my_project
* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/my_project.ex
* creating test
* creating test/test_helper.exs
* creating test/my_project_test.exs

Your mix project was created successfully.
You can use mix to compile it, test it, and more:

    cd my_project
    mix test

Run `mix help` for more commands.

读起来需要 3-4 分钟,执行起来只有 3 秒。此时,我们已经做了很多,但是首先要注意的是最后一行——从哪儿找到帮助。这里提到了关于项目的一些信息。我们得到了 README.md.gitignore/test 目录,以及配置文件。不错!

我们学了很多东西,并取得了一点小胜利。现在可以休息一下,去玩 Xbox 了。

任务二:编写测试

我们已经创建了初始化好的项目,现在,该怎样写测试呢?这有点儿疯狂,因为我们甚至还没有接触过这门语言!在这一点上,我们不要对此感到失控——我们需要一点小胜利,因此简单做吧。

看到 test 目录里有两个文件: my_project_test.exstest_helper.exs,这意味着:

正如项目配置中所示的那样,Elixir 语言的文件扩展名是 .ex.exs。稍后写下来,这就是小胜利。

my_project_test.exs 文件像是被忽视的机会,它很不错,因为我们能够鼓捣它。

Test Helper 说的就是这个意思。太棒了!

打开文件看看:

➜  my_project  cat test/my_project_test.exs
defmodule MyProjectTest do
  use ExUnit.Case

  test "the truth" do
    assert 1 + 1 == 2
  end
end

熟悉的语法,我能将其它语言的规则用到这里。结构清晰,对我而言,觉得极具 Ruby 风格。我喜欢这种风格(我喜欢 Ruby),现在,我觉得我能够写一个自己的测试了:

defmodule MyProjectTest do
  use ExUnit.Case

  test "the truth" do
    assert 1 + 1 == 2
  end

  test "my name" do
    assert "Rob" == "rob"
  end
end

有点儿蠢的 test,但是我想看到它运行不成功(希望是这样)。如果它没有失败,我只不过学了点小东西。现在我需要搞清楚如何运行一个 test。

我记得,在我创建项目时,有句话「Run ‘mix help’ for more commands」。就从这里开始,如果 mix 为我们创建了项目,那么它或许也能运行 test:

➜  my_project  mix help
mix                   # Run the default task (current: mix run)
mix app.start         # Start all registered apps
mix archive           # List all archives
mix archive.build     # Archive this project into a .ez file
mix archive.install   # Install an archive locally
mix archive.uninstall # Uninstall archives
mix clean             # Delete generated application files
mix cmd               # Executes the given command
mix compile           # Compile source files
mix deps              # List dependencies and their status
mix deps.clean        # Remove the given dependencies' files
mix deps.compile      # Compile dependencies
mix deps.get          # Get all out of date dependencies
mix deps.unlock       # Unlock the given dependencies
mix deps.update       # Update the given dependencies
mix do                # Executes the tasks separated by comma
mix escript.build     # Builds an escript for the project
mix help              # Print help information for tasks
mix hex               # Prints Hex help information
mix hex.build         # Builds a new package version locally
mix hex.config        # Reads or updates Hex config
mix hex.docs          # Publishes docs for package
mix hex.info          # Prints Hex information
mix hex.key           # Hex API key tasks
mix hex.outdated      # Shows outdated Hex deps for the current project
mix hex.owner         # Hex package ownership tasks
mix hex.publish       # Publishes a new package version
mix hex.registry      # Hex registry tasks
mix hex.search        # Searches for package names
mix hex.user          # Hex user tasks
mix loadconfig        # Loads and persists the given configuration
mix local             # List local tasks
mix local.hex         # Install hex locally
mix local.rebar       # Install rebar locally
mix new               # Create a new Elixir project
mix phoenix.new       # Create a new Phoenix v1.0.0 application
mix run               # Run the given file or expression
mix test              # Run a project's tests
iex -S mix            # Start IEx and run the default task

天哪!这么多行信息——我应该直接无视它们,因为我会被绊住,信息量太大而堕入不安,我上面已经谈过了(我做不到,它太庞大,它只是热门一时)。

就在靠下的一行「mix test # Run a project's tests」,正是我需要的。搞定。

➜  my_project  mix test
Compiled lib/my_project.ex
Generated my_project app


  1) test my name (MyProjectTest)
     test/my_project_test.exs:7
     Assertion with == failed
     code: "Rob" == "rob"
     lhs:  "Rob"
     rhs:  "rob"
     stacktrace:
       test/my_project_test.exs:8

.

Finished in 0.02 seconds (0.02s on load, 0.00s on tests)
2 tests, 1 failures

太棒了!从这次小胜利,我学到了很多:

有了这两次小胜利,我现在继续感到格外的兴奋。

String、Date、Number - 基础

这部分貌似比较明显了,的确如此。除了 Google,还需要一本书、或某种学习材料。对于这方面的东东,我倾向于直接访问 Pragmatic Programmers。研究 Elixir,并找到一套书籍。但是,有一个很不错的书,让人称奇:Dave Thomas 著的《Programming Elixir》。这本书精彩绝伦,必须推荐给你。

一般地,当我阅读编程书籍时,我喜欢按照书中顺序阅读,对我而言,先学习基本类型,然后是操作符、数据结构等。我发现,Dave 将我们带到了一个有趣的地方——我强烈推荐。

Elixir 是函数式语言,正如本书开篇所写的那样。我认为,函数是由最初的元素构成的,比如 string、number、date 等。因此我想知道这些类型的运行机制。我看了之后,就在我的小项目里鼓捣,并写一些测试代码来观察它们的运行情况。

尤其是 string——对我而言。我发现,如果一门语言有什么要槽点的话,那么,槽点很可能在于,该语言是如何处理 string、易变性、正则等等。

这就到了你和我面临不同选择的地方。我让自己去理解基本类型,而你,或许需要学习数据结构和方法调用。哪种方式都能发现技术点,因此你每次学一点即可。对我而言,包括了:

对于 date,我发现(还算迅速),Elixir 里的 date/time 有些不足,如果你需要使用它们,将需要安装一个 Timex 的 package。我还发现,你能够直接访问 Erlang 里的东西(很多人都这么做)。我将其收藏,回头再看(我还没有看)。

数据结构和数据库

我的第一批实验和小胜利持续了一周,随着我取得的胜利越多,需要关注的东西就越难。我持续地战斗着——我只是想跳到终点线,开发出东西。我费了很多努力才阻止我的这一企图,并保持专注。

我对于这些基础知识以及项目一起运行的方式感到非常了解了,现在,是时候着手基础列表和数据结构了。

这是我脑洞大开的地方。Elixir 是函数式语言,有很多地方是我完全陌生的地方(真的不足为奇)。我尽量控制着如流水般、向我涌来的概念……但是最终我放弃了,让它从我面前流过,我通读了那本书。

要知道,我愿意再次捧起这本书,多读几次。

此时我盯着面前成堆的概念,决定挑一个并深入进去。我也是这样做的,为自己设定一些小胜利,每一次都搞懂一些基础之上的「更高级」的概念。尤其是:

我通常碰到的这类问题,都偏向于 demo 级别。我需要理解一些真正的东西!因此我修改了一下清单:

自此,我就能够搞出数据列表了,这十分有意义,使用我之前开始理解的类型和测试……小胜利正累积起来……

进行中的事情:找到惯用法

这里是关于 Elixir 优雅的地方——还有人们用到的一些惯用法(类似于 Node 里的回调结构),简化操作。比如:

必需的函数参数,可优先被列出来。可选参数通过 Keyword List 传递进来。 函数结果通常用元组结构(tuple structure)来体现,比如 {:ok, return_data}{:error, message} 模式匹配支持你用非常优雅的方式控制应用程序流。 编写更小、更简明的函数,并在管道里组装,使程序更有趣

还有更多的惯用法,这里只是我用到的。如果你乐意,可称之为「Level 5」,现在到了启动做东西的地方。从小胜利走到学着开发,恰恰就是我已经开始做的事情。

我对这种做事方式感到舒心。

总结

你对本文感到热切吗?你想对我说,你是多么希望有时间、或看起来不错但是我需要赚钱?我想问你一个问题,你为什么要致力于一个年轻、充满活力的行业、却还期望一切都为你而不变呢。

做一名创新者,做出积极改变,你能做到——只需给自己一些时间,取得一点点小胜利。

译文:怎样学习新编程语言,且能兼顾工作与生活 》| 腊八粥