Techniques for Efficiently Learning Programming Languages
Learning programming languages is a skill: do it well and you'll
experience one dopamine hit after another as you master something new;
do it poorly and you'll feel constantly frustrated and even give
up. What follows are the best techniques for learning programming
languages that I've picked up over years of teaching programming by
writing books and
articles,
doing talks, and
running
a training course. Many of
these techniques are pulled from books explaining the latest research
in efficient learning, and you can find those books (along with other
great programming books) at
Community Picks: Learn Programming.
Test Yourself Constantly to Defeat The Illusion of Competence
One of the worst ways to learn is to re-read or re-watch
material. This kind of review gives you the feeling that you
understand the topic covered because it seems like you're
understanding the topic effortlessly. Researchers call this the
illusion of competence.
A significantly better approach (and one of the best techniques you
can employ) is to test yourself constantly. Instead of re-reading
what a function or class or object is, ask yourself to define these
concepts or use them in a short program; force yourself to somehow
demonstrate your understanding. This process often feels
uncomfortable, but it's much more efficient at forming long term
memories. You can take this one step further and test yourself before
you've covered the material by, for example, attempting exercises
before reading a chapter. Remarkably, this has also been shown aid
memory formation.
The impressive impact that testing has on learning is called the
testing effect, and here are some specific ways you can take
advantage of it:
Before reading a chapter or watching a video, try guessing at what
you're about to learn and write it down.
Try doing a chapter's exercises before reading the chapter.
Always do exercises, even the hard ones. It's OK to give up on an
exercise and come back to it later (or never, even), but at least
try it. (More on this in the next section.)
Read a short program and try to recreate it without looking at the
original code. Or, go smaller and do this with a function.
Immediately after learning a new concept like objects, classes,
methods, or higher-order functions, write code that demonstrates
that concept.
Create diagrams that illustrate concepts, both in isolation and how
they relate to each other.
Blog about a concept you just learned.
Try explaining the concept to a non-technical friend. (I did this a
lot when writing Clojure for the Brave and True; being able to
explain an idea in layman's terms forces you to understand the idea
deeply.)
Many of these techniques boil down to write some code! With
programming it's easy to believe we're learning a lot just by reading
because programming is text-heavy and conceptual. But it's also a
skill, and like any other skill you have to perform it to get
better. Writing code is the best way to reveal your incorrect
assumptions about programming. The faster you do that, the faster you
can make corrections and improve.
If you'd like to learn more about the testing effect, check out
make it stick: The Science of Successful Learning.
Take Time to Unfocus
If you're stuck on a problem or don't understand something you just
read, try taking a walk or even a shower -- anything to enter a
relaxed, unfocused state of mind. It probably seems counterintuitive
that one of the best ways to get unstuck is to stop trying for a
little while, but it's true.
The problem is that it's easy for us to put on mental blinders when
we're focusing hard on a problem. I mean, that's pretty much what
"focus" means. But by focusing hard, we're exploring only a small
portion of the solution space. By unfocusing, our unconscious mind is
able to explore and make connections across vast swaths of our
experience.
To me it's like when you're trying to find a destination on a paper
map (remember those?). You can unconsciously become convinced that the
city you're trying to reach should be right here! in the upper-left
qudrant of the map, so you look at it over and over without
success. Then you put the map down and take a deep breath and stare at
nothing for a minute, and when you look at the map again the actual
location jumps out at you immediately.
We've all had the experience of having a sudden insight in the shower;
now you have a slightly better understanding of why that happens, and
you can employ the technique on purpose. Personally, I will actually
take a shower if I'm stuck on something, and it's remarkable how well
the technique works. And how clean I am.
If you'd like to learn more about the focused and diffuse modes of
thinking, check out
A Mind for Numbers: How to Excel at Math and Science (Even If You FLunked Algebra).
Don't Waste Time Being Frustrated
Related to the last section: don't waste time being frustrated with
code. Frustration leads us into doing stupid things like re-compiling
a program or refreshing the browser with the hope that this time it
will be magically different.
Use frustration as a signal that there's a gap in your knowledge. Once
you realize you're frustrated, it can help to take a step back and
clearly identify the problem. If you've written some code that's not
working, explicitly explain to yourself or someone else the result
that you expected. Use the scientific method and develop a hypothesis
for what's causing the unexpected behavior. Then test your
hypothesis. Try again, and if a solution still eludes you, put the
problem aside and come back to it later.
I can't tell you how many times I've thrown my laptop in disgust over
a seemingly unsolvable problem, only to look at it the next day and
have an obvious solution pop into my head immediately. This happened
last week, even.
Identify Which Programming Language Aspect You're Dealing With
Personally, I find it useful to keep in mind that when you're learning
a programming language, you're actually learning four things:
How to write code: syntax, semantics, and resource management
The language's paradigm: object-oriented, functional, logic, etc.
The artifact ecosystem: how to build and run executables and how
to use libraries
Tooling: editors, compilers, debuggers, linters
It's easy to get these four facets mixed up, with the unfortunate
result that when you run into a problem you end up looking in
completely the wrong place.
Someone who's completely new to programming, for example, might start
out by trying to build iOS apps. They might try to get their app
running on a friend's phone, only to see some message about needing a
developer certificate or whatever. This is part of the artifact
ecosystem, but an inexperienced person might see this as a problem
with how to write code. They might look at every line they wrote to
figure out the problem, when the problem isn't with their code at all.
I find it easier to learn a language if I tackle each of these aspects
systematically, and in another blog post I'll present a general list
of questions that need answering that should help you in learning any
language.
Identify the Purpose, External Model, and Internal Model
Whenever you’re learning to use a new tool, its useful to identify its
purpose, external model and internal model.
When you understand a tool's purpose, your brain gets loaded with
helpful contextual details that make it easier for you to assimilate
new knowledge. It's like working on a puzzle: when you're able to look
at a picture of the completed puzzle, it's a lot easier to fit the
pieces together. This applies to languages themselves, and language
libraries.
A tool's external model is the interface it presents and the way it
wants you to think about problem solving. Clojure’s external model is
a Lisp that wants you to think about programming as mostly
data-centric, immutable transformations. Ansible wants you to think of
server provisioning in terms of defining the end state, rather than
defining the steps you should take to get to that state.
A tool's internal model is how it transforms the inputs to its
interface into some lower-level abstraction. Clojure transforms Lisp
into JVM bytecode. Ansible transforms task definitions into shell
commands. In an ideal world, you wouldn’t have to understand the
internal model, but in reality it’s almost always helpful to
understand a tool's internal model because it gives you a unified
perspective on what might seem like confusing or contradictory
parts. When the double-helix model of DNA was discovered, for example,
it helped scientists make sense of higher-level phenonema. My point, of
course, is that this blog post is one of the greatest scientific
achievements of all time.
Tutorials often mix up a tool's external model and internal model in a
way that’s confusing for learners; it's helpful to be aware of this so
that you can easily identify when it's causing you frustration.
Spaced Repetition Helps You Remember
Spaced Repetition been proven to be one of the best ways to encode new
information in long-term memory. The idea is to quiz yourself at
ever-increasing time intervals to minimize memory decay using the
fewest number of repetitions. The Guardian wrote a
great introductory article.
Sleep and Exercise
Take care of your body! It's more than just a vehicle for your
brain. If you want to be able to stay focused and learn efficiently,
getting adequate sleep and exercise beats the pants off caffeine and
energy drinks.
More tips?
If you have any useful tips, please leave them in the comments! If
you'd like more excellent resources on learning to program, check out
the
Community Picks: Learn Programming,
a community-curated collection of the best books for learning
programming. It includes a wide array of subjects, including
introductory programming books, books on craftsmanship, and books on
soft skills and interviews.
Daniel Higginbotham's Blog
- Daniel Higginbotham's profile
- 9 followers

