This post may contain affiliate links that earn me a small commission at no additional cost to you. For more information read my Affiliate Disclosure.11 min read
When you first start to learn programming and spend some time in the various communities, it can feel as if you just landed on an alien planet and now try to adapt to this foreign race by learning their complicated languages, adopting their way of thinking and understanding the correct manners. Everyone is talking in this strange way and you seem to be the only person on the planet that has no clue what is going on.
But it’s not that these people are from another species or that they are all geniuses, they just spent enough time learning and talking about programming that it became second nature for them. You can catch up to that and become a part of it, but how quickly you catch up is up to you. And once you reach a certain skill level, your approach to learning determines if you further build upon your knowledge, or if you fall back in the face of the quickly advancing and always changing programming world.
As some of you already know, I started learning programming pretty late, in July 2017 at the age of 26. I am happy with my progress and the learning process overall, and when I look back 6-12 months and see some of my old questions on Stack Overflow and my old videos, it makes me smile, because I realize how much better I have gotten. While there is still a lot of stuff I don’t know, I think that I am progressing pretty quickly and the frequent changes in frameworks, languages and best practices don’t scare me, because I know that I am able to catch up on all of that.
In my How to Learn Programming Fast blog post, I briefly talked about the concept of “deliberate practice” and that you shouldn’t always go for the easy route when you are trying to learn something. Deliberate practice is how you get better quickly and don’t end up one year later feeling like you made almost no progress.
In this post, I want to explain how I understand the concept of deliberate practice and what it means in relation to programming in my eyes. My view might vary a bit from other articles on deliberate practice, because I want to describe the way of learning programming that I personally found most beneficial.
All practice is not the same. This is true in pretty much every field. Some people spend thousands of hours learning and executing a craft and stay mediocre, while others become experts in their field with the same time investment. You might think that this is a matter of talent vs no talent, but in most cases it’s actually just how they learn that makes the difference. I’m not saying that genetics don’t play a role at all, there are certainly smarter people and less smart people, but if your way of learning is not optimized for fast improvement, you are operating way under your potential. You probably know a lot of people that have been driving a car almost daily for 20 years or longer. How many of them have race driver skills? Probably no one that didn’t actually train to become a race driver. If you want to get really good at something, it’s not enough to just put in the hours. You have to put in quality hours.
Practicing deliberately means practicing in a purposeful and systematic way. It means figuring out what needs improvement and then focusing on that thing until you are confident in it. It also means accepting discomfort and frustration sometimes, because these feelings will inevitably come up when you try to learn something that is above your current skill level.
If you try to learn programming while having a full time job, this kind of quality practice is especially important, because you only have a small time window every week available. If you often feel like what you are coding is easy, it’s a sign that you hit a plateau and you have to increase the difficulty level. If you often feel frustrated, confused and have 10 browser tabs opened at the same time, trying to figure out how something works, sweating like a pig, feeling like you’re about to cry, then you are probably doing it right. I am exaggerating a bit, but learning something that is outside your current skill level generally comes with a fair amount of struggle. That doesn’t mean programming has to feel uncomfortable all the time, but it should regularly confront you with some difficulties. You will progress much quicker by learning stuff that you don’t know, rather than repeating the things that you already know (and which will probably be outdated very soon). You can still just code for the sake of it and enjoy doing the easy stuff, but make sure to challenge yourself a little bit regularly (ideally daily).
When we start learning programming, we are pretty much forced to practice deliberately, because we know nothing and everything is new and difficult. But we’re also in this honeymoon phase where the excitement and novelty temporarily blind out the discomfort and we are more than willing to put in the hard work. But this phase eventually passes and finding the motivation to learn difficult new concepts will become harder. And once we reach a skill level we are happy with (for example when we land a nice job), it can easily happen that we stop pushing ourselves regularly, settle for the comfortable daily grind and avoid as much challenge as we can. That’s like going to the gym and lifting the same easy weights every day rather than increasing them and this way force more growth. But stopping to progress in the quickly changing programming world means eventually falling behind. There’s new stuff to learn all the time and you should make sure to keep improving your abilities and set yourself goals that are out of your comfort zone. This most likely has to happen in your own hobby project in your spare time, because only there you have the freedom to do what you want.
So pick something you don’t know, like a popular library that you’ve never worked with, and then search for a tutorial. But never just passively watch a video or read an article. Execute on it. And don’t write the same code as the tutorial, because then it can easily happen that you just mindlessly type down what you see there without understanding it, or even worse: copy-paste it. Instead, build your own version of the project, structure it a bit differently and use different layouts, values and variables names. This way you can’t just copy the code and you are pretty much forced to understand what is going on there, because otherwise you don’t know how to transfer it over to your own project. I create all my video tutorials in a way that you can watch them in a small browser window or on your smartphone. So even if you only have 1 screen, you can watch my tutorial and at the same time code along in Android Studio. Do that, but create your own variation and regularly pause the video and try to think for yourself. Focus on the parts you actually want to improve and don’t spend much time on the other stuff, like trying to create the perfect layout (unless of course, you want to get better at creating layouts).
If something in your version doesn’t work, use all the tools you have available to figure out what is wrong. This means you look into the source code, you try different approaches, you use the debugger and log messages and you search in Google to find posts and existing questions about it. Divide your big problem into smaller sub-problems and try to solve them one by one. It’s very tempting to just go into a Facebook group, programming forum or Stack Overflow, dump your code and problem there and then do something else while waiting for an answer. But this way you will progress much more slowly. Yes, if you get an answer to your question, you will learn something new. But if you figure it out yourself, by experimenting and researching, you will learn a lot more and you will remember it so much better.
When you look into the source code, you learn how things work under the hood, you draw your own conclusions and you practice reading other people’s code. When you research the topic online, you see the different approaches, common patterns, side information and past changes. You will train your logical thinking and problem-solving skills like a muscle. This process will often feel awkward and you will probably think that it shouldn’t be that way and that the answer should come to you naturally, but again, it is supposed to feel like that. It just means that you are taking something that is above your current skill level and integrate it into your tool belt. It feels wrong but it’s actually good.
Generally, don’t try to avoid things. Develop a sense for when you don’t want to do something just because it’s too hard, or because you are used to doing it in another way. For example, if you never learned how to use the debugger of your IDE and instead always hack some alternative solution together, realize that this laziness costs you a lot of time, because the debugger does a better job than your quick fix.
Whenever you run into difficulties, don’t just switch to another project. And also don’t multitask. Focus your attention on your problem and accept the discomfort of the challenge at least for a little while. Every time you figure out a difficult concept or tool, you will feel proud, accomplished and happy and it also means that you have to put in much fewer hours than if you just mindlessly repeat what you already know. When it comes to practice, focus on quality rather than quantity. Stop after an hour if you want, but make this hour count.
The great thing about programming is the rapid feedback you get. You know that you implemented something successfully if it works as you intended. Of course there can be bugs that you currently don’t see, and there are programming skills that are not easy to measure, like the quality of your code. But generally, you can see a lot of your progress by the stuff you are putting on the screen. If you try to implement a networking library the first time and your app shows the results from the server, you know that you got it to work. But don’t stop there, figure out what needs improvement. Dig deeper than necessary, understand how things work rather than just getting them to work. Ask other developers and participate in discussions. Post your code online and ask questions about it. But only post relevant snippets, not the whole source code.
The other component of deliberate practice is repetition. Just writing and implementing a feature one time isn’t enough to make it stick. You have to do it over and over again. Ideally, you should practice programming at least a little bit every day (outside of your normal day job). Vacations and family time are exceptions here. But the point is not to remember all the syntax of the code, because you can look that up online. You should rather try to learn the steps to implement a certain feature and how it all works together. It’s about understanding, not so much about memorizing.
Write as much code as possible, but remember, it’s not mindless repetition that we want. We don’t just want to build the same old stuff in different forms over and over again. If something becomes easy, go for the next level. You can also try to combine different new and old features and libraries into the same project. This way you have a mix of repetition and novelty and you learn how to implement the same code into the different structures of different projects.
Since deliberate practice is uncomfortable, it can very easily lead to procrastination. A time constraint on your practice sessions can help you power through them even if it’s hard. Also, scheduling your day properly can help you plan for quality practice time. Read my How to Beat Procrastination blog post to learn more.
And if you want a good book on the topic of deliberate practice, check out “Grit” by Angela Duckworth or “Peak” by Anders Ericsson. Or just get both audio versions for free with the Free Audible Trial Membership.
Just remember: Whenever you struggle with a difficult concept, it means you are in the process of getting better. Embrace it.