In 2019 I was studying languages at university and felt completely lost. I loved learning Chinese, but three years at university had left me disillusioned with the education system and I felt a huge amount of anxiety about where my life was headed. I had very little interest in becoming a translator, teacher or diplomat, or really doing anything related to languages as an actual job. It felt like I had just poured the last 8 years of my life down the drain.
This stress was compounded by the fact that I had no close friends - I’d fallen into the trap of grinding away in my room alone in pursuit of good grades at the expense of having a healthy social life.
At the end of my third year, I hit a breaking point and took a year out to live at home with my parents. I had no plan and no idea about what I was going to do and my stress levels were off the charts.
My one saving grace was that at the end of my third year in China I had stumbled across these obscure learning articles by a mad genius called Piotr Wozniak. I became fascinated by his software, SuperMemo, a flashcard and reading app on steroids with a UI like a NASA rocket dashboard, and devoured all of his articles ranging from critiques of traditional education, to the importance of sleep and the effect of learning on depression.
I was strongly influenced by those articles and decided that since I didn't have anything better to do, I might as well just follow his advice to learn whatever I wanted. I studied finance and economics, heavily inspired by Martin Shkreli's Intro to Finance and Investing lectures, downloaded tons of textbooks from libgen and started building up my flashcard collection.
After a couple of months of mindless wandering, I stumbled across programming. I remember trying to learn to code as a kid using Visual Basic and Cheat Engine to hack games, but didn't really get anywhere. I think I must have been part of the last generation to never have compulsory programming classes, so I didn't get any exposure to it at school. But with an abundance of free time and nothing better to do, I started to really get into it. Between coding, reading and doing flashcards, I spent all day learning about computers and talking to friends I made in the SuperMemo.Wiki Discord channel.
Fast forward 2 years and I had completely altered the trajectory of my life, going from a completely non-technical linguist to a full-time programmer.
In this article, I want to share everything I know about learning to program from scratch.
This article is part of the Functions Describe the World series. I have a practical day-one introduction to programming and an introduction to theoretical computer science (both with accompanying flashcards, of course!) coming soon! Subscribe to my Substack or follow me on Twitter for updates.
Projects are all you need
Golden Rule: You cannot learn programming through flashcards, tutorials and reading alone. Programming is an applied discipline where knowledge is gained tacitly through hacking on tons of projects. I deliberately left my advice about spaced repetition and incremental reading to the end of this article, because it’s just not as important as projects.
Don't ignore this point and waste a bunch of time reading books. It's time to put the books down and start fucking around. If you aren't a student, why unnecessarily constrain yourself by copying the inefficient learning methods of school? The big advantage of being in your position is that you have the autonomy to choose whatever you want to do. In many ways, you have it easier than students who won't have free reign over what they choose to program.
You acquire programming expertise by working on subjectively interesting projects. That’s not to say that flashcards and incremental reading are not worth investing in - they are what this article is about after all - but only if you are actively working on projects that are interesting to you at the same time.
There is a balance you have to find between consuming information and actually programming. I think 80-90% of your time should be spent working on your own projects and 10-20% of your time should be spent reading, doing flashcards, and watching lectures or tutorials. Beginners looking to make as much progress as fast as possible should just pump out code like a factory until it becomes second nature.
A corollary of this is that if you are time-constrained, eg. you can only spend a maximum of 1 hour per day coding, then I think you should just forego flashcards, reading and tutorials entirely and just build projects.
My first project
Picking a project can be tough and it’s hard to give generally applicable advice because everyone has unique interests. The only general project that applies to everyone would be a blog because you can use it to write about your projects and host your portfolio.
My first project was a language learning tool. Here’s a description lifted from my old portfolio website.
“We know from the scientific literature that active recall is much more effective than passive review for learning, but while this understanding has been applied successfully in spaced repetition systems for text-based content, there are no systems that implement this effectively for audio and video.
Back in May 2019 I started learning Linux and bash scripting so I could create an language learning audio player with a Raspberry Pi. I used a USB battery pack as a power supply, a USB numpad keyboard as a controller and a pair of bluetooth headphones so I could record sentences and words from Chinese lectures, audio books and podcasts on my commutes to and from university while I was living in Shanghai. I had one of the chunky Raspberry Pi models, so I had to carry it around in my backpack everywhere. It would frequently overheat. And there was no way to restart it if it crashed so the user experience sucked.
Later I rewrote the program in Python with a proper SQLite database and added the ability to download YouTube videos, create “audio cloze” flashcards using a bluetooth remote and export the flashcards into SuperMemo. Audio cloze flashcards are flashcards where the question side is a sentence where a word or phrase has been "censored" with a beep sound. When you are presented with the question side, you have to try and recall which word or phrase has been covered by the beep. I would often ride around the city on my bike taking extracts from lectures and making audio cloze deletions from Chinese podcasts that I could later import into SuperMemo to review. I must have looked ridiculous. But these early prototypes showed me that the core idea was sound.”
It was completely impractical and useless to anyone except me, but it taught me more than any other project I've done since, and every time I bring it up people are impressed at how unique and interesting it is because it reveals a lot about my personality and interests. I was studying Chinese very intensively at that time, so it solved an actual problem I had which made me much more motivated to work on it every day. That's the essence of a good personal project.
Plugins
I also spent a bunch of time making plugins for personal knowledge management systems and flashcard apps like SuperMemo, Anki and RemNote. Plugins are great because they can be small self-contained projects manageable for a beginner. The project I made which got the most stars and users was actually an Obsidian plugin I made for doing incremental writing. It only took a month or so to make because Obsidian has a great API meaning I didn’t have to implement everything from scratch.
I remember I even got ~$200 in donations from it, just from putting a donation link in the README of the repository. That’s not a lot, but it felt amazing as a beginner without a job.
"What about tutorials?"
They can be okay but I don’t recommend copying tutorials line by line because you can do that mindlessly and learn very little. A strategy I have personally found more useful is taking a tutorial that is related to what I want to do, and then change it in some way - eg. by using a different programming style, a different set of technologies, or taking a different angle. So if your goal is to create a crypto dashboard, you could look up tutorials to create a normal stock tracker and adapt it to track crypto instead.
Projects are your credentials
Projects are important beyond just learning though. If you're from a non-traditional background, ie. you aren’t studying CS or math in school, then you need some way to prove to employers, potential collaborators, cofounders etc that you have skills.
Start thinking about how you are going to market your skills early. Build an online presence. Start a YouTube channel or a blog. Learn in public.
"But who's gonna hire me?"
There's infinite demand for software and an infinite demand for programmers.
Try to understand hiring from the other side - it’s costly, boring and difficult and the average applicant makes very little effort to differentiate themselves or show that they truly understand the business they are applying to.
For startups in particular, hiring is even more difficult because they can't afford to outsource it, so engineers have to sacrifice time spent building features to run interviews. They also have to compete with larger, more established companies for applicants.
If you can show an ounce of domain-specific knowledge or have done a project related to their business it will make you stand out. Develop the skill of doing cold outreach. You can get in touch directly with employees/founders through Twitter/email and ask for a 10-minute call. It's much easier to make a case as to why someone should hire you face-to-face rather than via some application form. You can get hired without even needing to write a single line of code in an interview, as long as you can show high-quality code samples and repos on GitHub that demonstrate your skills.
Meta-learning
Programming is hard to learn as a beginner because of the bombardment of unfamiliar terminology and concepts. What you learned yesterday evaporates overnight causing a constant churn effect as you battle against forgetting. I describe this as the chasm of incoherence. This is the period when you are most likely to give up because the feeling of not understanding is unpleasant and makes you feel as if you aren’t making any progress.
Why does the chasm of incoherence exist? Consider some basic facts from memory science. All memories naturally weaken over time unless they are reinforced, but memories of new information unrelated to things you’ve studied in the past decay extremely rapidly. In other words, those memories have an especially steep forgetting curve.
If you don’t have any experience programming and you are trying to learn the definition of a coroutine in Python, the memory decays very quickly because there aren’t many existing stable memories in your brain for the new concept to attach to. Integration between new information and prior knowledge is the prime weapon against forgetting, but as a beginner at programming, you don't have much or any prior knowledge, so the forgetting curve for new terms and concepts you learn is likely to be steep.
Those memories aren’t getting glued to any other stable memories. They are “orphan memories” cut off from your existing network of knowledge and ideas. What you need is to create rich connections between new information and prior knowledge. New information builds upon things you already know and "slots in" to your prior knowledge. The memories gain stability by their connections to memories existing in your long-term memory. That way the forgetting curve will look more like the blue line:
The basic lesson is that you need to find some way to meaningfully relate what you are learning to something you already know. Since functions, data and computation are such general concepts, this should be possible no matter your background. One thing you can try is asking an LLM like ChatGPT to explain a concept to you by analogy. In my opinion, analogical reasoning is the easiest way to quickly build a coherent model of a new domain. You might even go so far as to say that analogy is the core of cognition.
Once you’ve flattened the initial forgetting curve by learning in a way that connects new information to what you already know, you can further optimise the process by adopting an effective learning schedule using a spaced repetition system like RemNote or Anki.
If Git is like a save button for your code, spaced repetition is a save button for your knowledge. In a spaced repetition system you add flashcards about things you want to remember, like definitions of new concepts, and the system shows you the information at the perfect time to try and make sure you don’t forget it. With each review, the forgetting curve for the memory becomes less and less steep, so you can go longer and longer without reviewing it.
The practical effect is that the beginner stage of learning becomes much less frustrating and you build a more solid foundation.
Examples of Cards
If you do choose to make flashcards, I think it’s better to make cards from more conceptual things as opposed to specifics like syntax and surface level details of the language you’re learning, because you’ll naturally pick those up through exposure. But making cards from those things is worth it if it can boost you past the chasm of incoherence.
How large language models work from scratch
These are some more recent cards from my RemNote collection. Each => symbol represents a flashcard. Here’s what they look like in my notes. RemNote is cool because you can use hierarchy to compose flashcards and make your cards very concise:
And here’s what they look like in the flashcard queue:
How generators work in Python
The benefit of an analogy is that it transitively gives me a network of facts I can infer. If the yield statement in a generator is like a pause button, then presumably it can be played again? And most likely from the point where it left off last time.
These are some more standard cards filling in the details, helping me retain the key properties of the concept.
Understanding new concepts in terms of old ones is key! Disambiguating similar terms will prevent memory interference.
And of course knowing the reason behind using a particular programming thing is useful:
Async/await in C# and the useEffect hook in React
Here’s another example of understanding a new concept via a similar one:
And then connecting it to CS theory:
And then finding more applications of the theory:
Physical Analogies
In my intro to computer science article, I show how computation is a physical process.
A computation is a physical process in which physical objects (likecomputers, or slide rules or brains) areused to discover, or to demonstrate, or toharness properties of abstract objects likenumbers and equations. Hence the reliability of our knowledge of mathematics,nothing to do with whether propositionsare true or false, just our knowledge ofmathematics, remains forever subsidiaryto our knowledge of physical reality. - What is Computation? (How) Does Nature Compute?
As such I think it really makes sense to use lots of physical analogies to understand certain programming concepts. Parallelism and concurrency is a natural example:
How are the Haskell standard lib functions are implemented using recursion
Here’s a weird experiment I did, based on Paul Raymond-Robichaud’s math spaced repetition method. I tried to memorise the implementations for a lot of the list-processing standard lib functions in Haskell. Most of the functions are extremely concise - between 1 and 3 lines of code. And they are great for learning about recursion. Notice that I only require myself to recall a tiny snippet of code. It’s important that your cards are atomic.
The full list (I called them legos because I thought they would become the basic building blocks of more complex algorithm cards, but they never did :P)
Then I would test myself by writing them all out from memory and testing them:
Pointers and Memory in C
How math links to programming, natural deduction, interactive theorem provers.
See my full guide: Mathematics for the 21st Century
Connecting abstract algebra to functional programming
For a complex subject like abstract algebra, a great approach is to lean on intuitive analogies to connect it to concrete things you understand.
You can also connect the mathematics to more practical programming things you already understand like basic data structures.
Extra resources
Article: SuperMemo as a Tool for a Programmer by Piotr Wozniak.
Reddit: Reddit user SigmaX’s comments on Reddit where he shares examples of programming cards.
Blog: Reddit user SigmaX’s blog. He has a couple of articles on using SRS to learn programming and machine learning.
Blog: A guide about using Anki to learn programming which the author calls the “Janki Method”.
Incremental Reading for Programming
Incremental reading systems like SuperMemo are a superset of spaced repetition systems. Incremental reading involves interleaving your flashcards with snippets from thousands of articles, books and videos in a big prioritised queue.
The general idea is to form a "funnel of knowledge" in which a vast worldwide web is converted into a "selection of own material", that moves to important highlights (extracts), that get converted to active knowledge (cloze deletion), which is then made stable in memory, and, in the last step, acted upon in a creative manner in problem solving. - Incremental Reading
The power of incremental reading is that it is incredibly good at helping you search and find things that you are interested in. It makes learning fun and can even help you figure out your values and purpose. Incremental reading helps you create an “immersion environment” of high-quality articles, videos and books you can learn from and turn into knowledge. People like to describe incremental reading as a knowledge grinder:
My personal recommendation is to use RemNote and my Incremental Everything plugin. I will have a more in-depth guide on how to use it coming out soon™, but here are my quick tips:
You should explore rabbit holes, import interesting stuff into your queue and postpone stuff that looks important but you can’t understand yet. If you prioritise things based on your personal interests, then your queue will naturally order itself with information that is most interesting and easiest to slot-in to your prior knowledge first.
Use Wikipedia and books for theory. Wikipedia articles are densely connected and show the links between CS, math, logic and the practical side of coding. You can also find tons of high-quality content easily using AI search services. I particularly like using the Metaphor search API.
For whatever you want to learn, there will likely be a network of high-quality blogs with street knowledge you can’t find in documentation and explanations of useful design patterns to improve your code.
Here’s an example of stuff I incrementally read back in 2021 to learn C#:
High quality books: C# in a nutshell, C# in depth.
Blog posts by top C# developers and language designers: Eric Lippert, Jon Skeet, Stephen Cleary, Stephen Toub, Marc Gravel, Alexey Golub
Threads answered by the C# language designers or C# experts. Eg. You can do queries on StackOverflow to find posts that are answered by multiple knowledgeable people
Some twitters are also very relevant. Once you follow one you get suggestions for more.
Next Steps
I hope you enjoyed this article. Be sure to check out the other articles in the Functions Describe the World series and follow my Twitter.