In the paper Teaching Programming Languages by Experimental and Adversarial Thinking, an approach to teaching programming languages is outlined that reflects a more natural approach to learning:
…a programming language is less a purely mathematical object and more like an object found in nature. In addition to any formal interfaces it may present, we should – and do – also view it as a target for experimentation. We subject it to a variety of tests. Most of all, we follow a loose version of the scientific method: we form a hypothesis about the language’s behavior; we construct tests (example programs and their expected outputs) consistent with the hypothesis; if the tests pass, we reinforce the hypothesis, otherwise we find it falsified; we use the falsification to generate a new hypothesis, which results in new tests. When we have exhausted our ability (or energy) to falsify, we accept our hypothesis as a tentative truth about the language, and use it to construct actual programs (whose behavior may – after painful debugging sessions – again falsify our understanding).
Basically, we learn a new programming language best by just jumping in and trying stuff.
This is super validating because it often feels like The Right Way to learn is a task list of the most boring words you have ever heard, including but not limited to:1 data types, variables, expressions, operators, classes, inheritance, structs, interfaces, enums, events, enumeration, standard libs, special language features, concurrency, I/O, networking, serialization, and on and on. I just fell asleep writing that.
The better way, in this case, is also the most fun: copy/paste something that looks interesting to you; change some stuff around; when something doesn’t work out, head over to Stack Overflow, check out the documenation, or ask questions on the language’s public chat; then change some more stuff and do it all again.
To learn a skill efficiently you need to get in the zone with some deep, deliberate “practice.”
The Importance of Deep Work & The 30-Hour Method for Learning a New Skill takes an interesting approach—divide your learning into seven or eight, four hour blocks of learning over the course of a few weeks and dive deep.
I like this informal structure because it gives you some bare-bones guidelines for what you need: time to get into the flow, some consistency to build up some working knowledge, and a timeframe for which you can expect to have a basic understanding of the subject matter.
The article gives a sample of how you might break it down. Something specific to learning a programming language might look something more like this:[^rusty]
- Session 1: Read some posts about the language, watch some videos, etc.
- Session 2: Install the language, go through the Getting Started
- Session 3: Do a small project, something you are interested in
- Session 4: Start a larger, more advanced project that will stretch you
- Session 5: Wrap-up the larger project from Session 4
- Session 6: Pick up a book, skim it, refactor based on your learning
- Session 7: Implement more advanced functionality, or start a new project
But I think it’s important not to systematize this too much. If it’s not fun, it won’t get done.2
Anecdotally, I have been using a loose version of this to learn Rust, and it has been a breeze. It feels like all the pressure and drudgery of learning a new language has been replaced with fun and excitement, which I think is exactly what one would want.