QIAOPANG.COM · SELECTED ESSAYS (2013–2026) · 260 ESSAYSBrowse Chronologically (2013 → 2026) ↗
QiaoPang · Programmers LifeSelected Essays · Systems, Craft & Agentic Era
Timeline ↗

How to Learn a Programming Language from Scratch

How to Learn a Programming Language from Scratch

How Should You Choose a Language?

My first practical language was Visual Basic. After spending a stretch of time with Windows programming and getting lost in a maze of handles, message loops, and the baroque sprawl of MFC, VB showed me the value of simplicity, directness, and documentation (MSDN). The barrier to entry is a serious problem: some languages (and the frameworks behind them) are best left alone until you have some foundation.

Of course, languages keep evolving, and VB under the .NET framework has long since lost that simple, direct beauty.

For your first language, it’s best to pick one with the following properties:

    1. Simple syntax, clear structure — the code you write comes out relatively concise and readable
    1. A mature ecosystem, especially documentation
    1. Ideally the language offers a REPL (Read-Evaluate-Print-Loop) and introspection
    1. Enough sample code in the open-source community (GitHub, say)
  • …

Let me use Python to explain the third point a little. Python’s shell (python or ipython) is a proving ground for syntax and library functions, and it’s a huge help when you’re first learning the language. Want to get Python’s data structures straight? Half an hour of practice in the shell and you basically have it. What’s more, the shell lets you introspect any function or library at any moment — through help, dir, type, the inspect module, and so on, you can dig into the callee’s internals and learn how it behaves, which lowers the barrier for beginners even further. When you’re writing C and hit a function you’re not quite sure how to use, your options are to read its source or hunt down the documentation; in Python, convenient introspection tools are there to help you anytime, anywhere.

One more note: these two languages aren’t really comparable — I’m just using them as an example. Someone might say, “I can introspect with gdb!” But that’s a solution at an entirely different level, and not something a beginner can pick up on day one.

The first point needs little explanation — nobody likes complexity right out of the gate, do they? Points two and four are about what references you’ll have while learning, and what help you can call on when you get stuck. You can gauge the completeness of a language’s community documentation from its official website, and gauge the strength of its ecosystem and community from Stack Overflow and GitHub.

If you force me to make a thoroughly subjective recommendation: Python for your first language. It satisfies all of the above (Ruby, Scala, and others are also worth considering).

At this point you might ask: doesn’t requiring a REPL rule out most statically typed languages? Yes, it does!

Because the premise here is learning from zero, the back-and-forth during learning (with the shell) and the learner’s steadily building confidence matter enormously. Having a compiler in the loop only adds unnecessary burden at this stage.

How Should You Learn?

To learn a language, start with its history and its ideas.

From a language’s history you learn about the forces present at its birth and the choices made during its later development. Beyond that, you should get a rough sense of what products that language’s community has produced along the timeline. All of this deepens your understanding of, and affinity for, the language.

Learning a language’s ideas (its philosophy) matters a great deal — it shows up in the language’s design, its syntax, even the behavior of the whole community. To turn a number into a string, in Python you’d probably do this:

In [1]: str(10)
Out[1]: '10'

But in Ruby you should do this:

irb(main):001:0> 10.to_s
=> "10"

If you treat that as syntax to be memorized by rote, you’ll work twice as hard for half the result. Ruby’s philosophy is pure OO: tell the object to do something, rather than doing something to the object.

Comparing Ruby and Python is fascinating. Ruby’s author was heavily influenced by Smalltalk and Perl, so in Ruby everything is an object (Smalltalk), and there is more than one way to do it (Perl). The author gave Ruby flexible control — you can change the system’s behavior (reopening a class from a library to amend it, for instance), which feels a bit like Lisp.

Python descends from ABC, a teaching language (in the Algol lineage), and never warmed to pure OO, so code can freely mix procedural and object-oriented styles. Perhaps because of that teaching-language DNA, Python insists on doing one thing in the single clearest way (“There should be one - and preferably only one - obvious way to do it.”), which is why people in the community call an implementation “pythonic” — meaning it’s clear, concise, and true to the Python way. Of course, Python has also absorbed good ideas from many other languages: list comprehensions (Haskell), applying a function to a list (Lisp), and so on.

Once you know the history and the ideas, you’ll have a reasonable explanation for the language’s behavior, and it becomes much easier to generalize from one lesson to the next. Of course, as a first language you certainly won’t know the names of all those other languages — many of which I don’t know either — but you can look them up on Wikipedia as extended reading.

After that comes reading documentation and books, watching all kinds of video tutorials online, learning the language’s syntax and its various libraries. This stage is fairly tedious (a REPL eases the tedium a little). Don’t learn a language from a textbook — the exercises in textbooks have mostly nothing to do with real problems, and you shouldn’t be trying to write pigeonhole-principle or eight-queens code. You’re learning a programming language, not doing mental training or mathematics.

When choosing books, try to choose ones by the language’s author (or a master of it): for Ruby you should read 『松本行弘的程序世界』 (Matsumoto Yukihiro’s World of Programming), for Python “Programming Python” (with a foreword by Python’s author), for Erlang “Programming erlang - software for a concurreny world”, and so on. These authors pour a great deal of knowledge and insight into their books.

There’s also a book that isn’t about any particular language but is about the essence of programming, and is very much worth reading: 『冒号课堂』 (The Colon Classroom). If more domestic authors wrote books like this and fewer cranked out thousand-page bricks of syntax and library reference, Chinese technical publishing would be much the better for it.

Once you’re past the syntax hurdle, there are two learning methods:

  • Learn by building
  • Engage with the community
  • Learn by teaching

Learning by building means finding an interesting project and rolling up your sleeves, writing code as you learn. Driving school will never actually teach you to drive, but within a week of being on the road you’ve basically got all the skills; drive through every kind of complex traffic every day for a month and you’re a veteran. Learning a language works the same way.

You’ll always have questions while learning — hunt for answers in Google Groups and Stack Overflow. If you truly can’t find one, ask in a way that meets the community’s standards. That, too, is a process of accumulating experience.

On top of learning by building, it’s best to teach someone who doesn’t know the language but wants to learn it, or to find some like-minded people to study with. Sometimes our thinking gets set in its ways and filters out a lot of the “dumb” questions in our heads. Someone else’s seemingly trivial question may jog something loose, making you think hard about the answer to something you’d written off as “simple.”

Opportunities to teach a language to others are rare, but browsing the community to see what people are asking and trying to answer is itself a way of practicing learning by teaching.

How Do You Level Up?

Once you can more or less comfortably write simple applications in a language, you should consider going back to fill in the pieces you skipped over — to re-examine the language:

  • What are the characteristics of its type system?
  • What does its memory management model look like?
  • What concurrency facilities does the language provide, and what does the library?
  • What support is there for generics?
  • What are the exception-handling mechanisms, and what are the community’s established conventions?
  • What support is there for OOP?
  • What support is there for FP?
  • How does metaprogramming work?
  • How does interoperability with other languages (C, for example) work?
  • What are the language’s inherent limitations?
  • …

As you go through this examination, keep filling in the fundamentals — these are the foundation for picking up your next language quickly.

You should also seek out some interesting source code and see how other programmers write code. Reading excellent code is like reading a good book: savor it carefully and the pleasure is endless.

When you’re tired of writing code, read the masters and cultivate your thinking. Hackers & Painters, Matsumoto Yukihiro’s World of Programming, The Pragmatic Programmer, and a whole shelf of others are all worth reading.

For example, The Pragmatic Programmer says:

You shouldn’t be wedded to any particular technology, but have a broad enough background and experience base to allow you to choose good solutions in particular situations.

I think that’s the attitude you should have in software — there is no perfect language, only the most fitting tool.

Closing Thoughts

Having said all this, it feels as though I’ve said nothing at all. Learning a language is inherently a matter of individual variation; there’s no dogma that holds everywhere. As the saying goes: cultivation is a personal matter!

MORE IN Languages & Craft

Further Reading in This Column

View all essays in “Languages & Craft” →

Time to Meet jj: Git's Next Evolutionary Step

Git has ruled version control for twenty years, but its staging area, brittle rebases, and blocking merge conflicts are becoming liabilities in the AI era. jj rebuilds the mental model from the ground up — while staying fully Git-compatible. Here's why it deserves your attention.

New Hope (2025–2026)5,588 chars · 12 min read