Play the long game when learning to code.
Learning to program can be brutal. You don’t know if you’re learning the right things and there just seems to be so much content to learn. Most of us don’t have the time to spend several years trying to nail down programming fundamentals.
Chances are, you’re concerned with how long it will take you to learn how to code. You feel this pressure to learn as much as you can in as little time as possible. You want to get away from your current role, or lack thereof, and make your way towards finally landing a job that pays you to code.
Aspiring coders tend to take one of two types of learning approaches. The first approach involves trying to learn syntax as fast as possible. People who use this approach copy and paste their way to completing projects and whiz through courses and tutorials. Unfortunately, many people burn out learning this way and ultimately cannot apply what they’re learning to real world problems.
The second learning approach emphasizes understanding above all. People who use this approach play the “long game” with learning how to program and aren’t in a rush to learn every bit of syntax. They learn at a methodical pace and ensure they understand each programming fundamental before moving onto the next.
In this post, I’ll take a look at both learning groups and break down the pros and cons of each. By the end of the post, I hope to show you why opting to play “the long game” with learning how to program is the faster, more effective learning approach.
Learning fast will do you wonders (but some harm too)
One of the best parts of learning how to program is that there are a multitude of resources to help you along your way. The internet is chock full of free online courses, video tutorials, and communities of people ready to help point you in the right direction. It’s only natural to want to take advantage of these resources in as efficient a way as possible.
Learning to code fast has its perks. You’re exposed to a vast array of programming concepts and you get the feeling of making a lot of progress in a short amount of time. With so many online resources available, you could complete several tutorials and projects in the course of a day. The biggest perk might be that you can start applying to jobs faster and then land a job offer.
When I first started to learn how to code, I made it my life’s mission to complete two beginner’s Python courses and finish three different fullstack development projects. I went from printing ‘Hello World’ to writing functions, classes, and register files in a matter of months. I felt like I was learning a lot and well on my way to landing a job.
However, I soon realized I had to slow down. I started interviewing for programming roles and I failed every technical interview. When interviews didn’t work out, I tried taking W3Schools’s Python quiz and failed miserably. The reality was that I was settling for the short-sighted joy of “completing” courses and tutorials.
Many aspiring programmers fall into the very same trap I just described. They copy and paste code without understanding it or mindlessly “complete” courses and tutorials. If you can understand and apply what you’re learning, then by all means keep “learning fast.” If you can’t apply what you’re learning, then I recommend you slow down. Start to prioritize understanding and test yourself by trying to solve problems outside of your learning environment. If your course or tutorial is taking you through how to write a for loop, try writing another one with different numbers or naming conventions.
Learning to code at a rapid pace will expose you to a ton of different concepts and you may even get to interviews and job offers faster. But don’t “learn fast” at the cost of not understanding what you’re learning. When you get to technical interviews, you’re going to be asked questions that test for your understanding, not just your ability to regurgitate syntax. If you prioritize understanding now, you’ll solve interview questions with success and show interviewers you’re ready for the job.
Play the long game as you learn
If you want to make real, lasting progress in your programming journey, you should embrace a “long game” mentality as you learn how to code. This may mean taking longer to understand a programming concept rather than moving on to the next concept. You may not get to interviews as fast as somebody who’s “learning fast,” but you’ll have a much better chance at acing technical interview questions than someone who’s simply regurgitating syntax.
The best programmers embrace a “long game” mentality. They aren’t in a rush to memorize every bit of syntax, but instead, focus on real, sustainable progress. They know each programming concept builds off of another one and they don’t move on to another concept until they’ve understood the current one.
As I was learning how to program, I kept looking for a magical point of arrival where I would become a legitimate programmer. I was in a rush to reach self-imposed benchmarks because I felt like I needed to learn how to code and land a job as fast as possible. That feeling of legitimacy never came by way of completing courses or memorizing syntax in a frenzy. Rather, I started to feel a sense of legitimacy when I began to embrace the “long game” of becoming a programmer. I started to focus on understanding what I was learning and applying my knowledge to real world problems. Concepts like recursion and data structures made more sense because I spent extra time trying to understand control flow and computer memory.
Realize the “long game” isn’t so long
If you’re committing to a lifetime of learning, why not start now? Start building a solid foundation of programming fundamentals. Each concept will build off the last, and you’ll be glad you took the extra time to fully understand a concept before you move on to the next one.
Others who are “learning fast” may get to interviews faster than you, but their odds of acing technical interviews and landing job offers won’t be as high as yours. You’ll have spent the extra time building your programming foundation and you’ll be able to apply what you’ve learned to problems outside of your learning context.
So yes, focus on understanding the concepts in front of you and don’t worry about rushing through the process. Commit to a lifetime of growth and embrace the “long game” of learning how to program.
Tags: learning to code
18 Comments
I feel that one of the biggest problems is that people conflate two things when they talk about “learning to program”:
* learning to program and
* learning a programming language
Those are two orthogonal things. I know how to program, but I don’t know Rust. And I can memorize the syntax and semantics of Python all I want, but that doesn’t tell me how to write a program.
The big problem, of course, is that when you are starting out, it doesn’t make sense to separate the two: if you learn a programming language without learning to program, that’s boring because you can not apply what you have learned. And vice versa, learning to program without learning a programming language means you can never experience your creations actually *working* and doing something.
So, you *have* to learn a programming language when your are learning to program. But! Every second you spend learning the programming language is a second your are *not* learning to program. Logically, then, it makes sense to *minimize* the time spent learning the programming language in order to maximize the time spent learning to program.
This makes sense, in fact, *even if* you want to *both* learn to program *and* learn a programming language, because it is easier to pick up programming languages when you already know how to program.
This is where *many* programming courses, books, and tutorials fail, in my opinion. They use complex and large programming languages like Python, Ruby, Java, or C++ to teach programming. Now, Ruby is my favorite programming language, but I wouldn’t recommend it to a beginner. There are a lot of rules, corner cases, exceptions to the rules, exceptions to the exceptions to the rules, etc. The same applies to Java: Martin Odersky, who after all co-designed a large part of Java’s type system, has said that the can think of only three people who understand Java’s type system (and reading between the lines he did not count himself among those three). How can you expect a beginner to understand a programming language that even the people who designed it don’t understand?
That’s why I am a huge fan of *How to Design Programs* (http://htdp.org/). It uses a simplified, restricted subset of Racket (https://racket-lang.org/). And when I say “subset”, I mean that they actually specified and implemented that subset (in fact, a series of subsets), so that their compiler can actually give sensible error messages and help, This is very different from most books that use Java, C++, Python, Ruby, etc. They also *use* a subset of the language, but they don’t *provide* said subset. Instead, they just *pretend* that the parts they don’t teach don’t exist, but that’s not the case: a student may very well accidentally write some code that happens to be invalid according to some part of the language they haven’t been taught yet, and then they get an error message that talks about things they have no idea what they mean. Even worse, they may write some code that happens to be *valid* according to some part of the language they haven’t been taught yet but doesn’t do what they expect it to do, then they get *no error*, and the code does inexplicable things. This doesn’t happen with HtDP: for every part of the book, they define an ever-growing subset of the language containing only what has been taught so far, and provide implementations for all of those subsets.
The advantage of a book like HtDP is that it can focus on teaching *programming* because the programming language it uses is so simple (and also the tools the book provides around that language, i.e. the IDE are so good and specifically optimized for teaching and learning) that it only needs to spend a tiny fraction of the time teaching the language and can focus on teaching programming.
And once you understand programming, it is much easier to pick up another language because, let’s face it, you won’t get a job programming in “BSL” (Beginning Student Language), “ISL” (Intermediate Student Language), etc.
That’s my rant about learning programming.
Programming Languages implement Programming Paradigms. There are thousands of programming languages, probably. Maybe tens of thousands. But! The number of Paradigms is much smaller. In his famous poster (http://www.info.ucl.ac.be/~pvr/paradigms) of the relationship between the principal Programming Paradigms, Peter van Roy identifies only the following 34:
* active object programming / object-capability programming
* ADT functional programming
* ADT imperative programming
* concurrent constraint programming
* concurrent object-oriented programming / shared-state concurrent programming
* constraint (logic) programming
* continuation programming
* descriptive declarative programming
* deterministic logic programming
* event-loop programming
* first-oder functional programming
* functional programming
* functional reactive programming (FRP) / weak synchronous programming
* imperative programming
* imperative search programming
* lazy concurrent constraint programming
* lazy dataflow programming / lazy declarative concurrent programming
* lazy functional programming
* monotonic dataflow programming / declarative concurrent programming
* multi-agent dataflow programming
* multi-agent programming / message-passing concurrent programming
* nonmonotonic dataflow programming / concurrent logic programming
* relational & logic programming
* sequential object-oriented programming / stateful functional programming
* software-transactional memory (STM)
* strong synchronous programming
That means, you don’t need to learn thousands of languages. You only need to learn 34 Paradigms, and you will be able to rapidly understand *any* of those thousands of languages.
We can do even better: Paradigms are composed of Concepts, and in that poster, there are only 18 of those:
* by-need synchronization
* cell (state)
* closure
* continuation
* instantaneous computation
* local cell (private state)
* log
* name (unforgeable constant)
* nondeterministic choice
* port (channel)
* procedure
* record
* search
* single assignment
* solver
* synchronization on partial termination
* thread
* unification (equality)
All of the listed 34 Paradigms are composed of those 18 Concepts, and all even remotely mainstream languages implement one or more of those 34 Paradigms. This allows you to understand the *semantics* of pretty much any programming language very quickly.
Peter van Roy deliberately ignores aspects of *typing*, but again, at least when talking about mainstream languages, pretty much anything can be understood in various subsets, extensions, or extended subsets of System F.
There are similar “building blocks” for understanding the *syntax* of programming languages. Pretty much anything you see today can be traced back to Lisp, Algol, C, ML, Miranda, ISWIM, Smalltalk, or APL.
As a personal anecdote, I can say that playing around with Self and Scheme taught me more about ECMAScript and *faster* than if I had learned ECMAScript directly. Even if you factor in the time I played around with Smalltalk before Self, I am confident it took me less time to understand Smalltalk, Self, and Scheme, and transfer that knowledge to ECMAScript than it would have taken me to learn ECMAScript directly, *and* now I know 4 languages instead of 1. Likewise, toying with Haskell made TypeScript a *lot* more accessible to me. In fact, I have never looked at either an ECMAScript or a TypeScript tutorial.
So, here’s my tips on learning to program and learning programming languages:
Programming:
* Try to find books, courses, tutorials that focus on *programming* and especially *teaching programming*. I already mentioned *How to Design Programs*. *Concrete Abstractions* (https://Gustavus.Edu/+max/concrete-abstractions.html) is good, too.
* Learn Fundamentals: Abstraction and Reuse. That’s what *all* of programming is about.
Languages:
* Learn Fundamentals: Try to find languages that deeply embody one of the Paradigms or Concepts. If you want to learn OO, use Smalltalk, Self, Newspeak, Eiffel, not Java. If you want to learn FP, use idiomatic Scheme, Clojure, Haskell, not Functional JavaScript.
* Get proficient with some of the widespread syntactic styles. C# and JavaScript doesn’t count. You shouldn’t be terrified if the type comes after the variable.
Of course, once you have learned Programming and learned half a dozen Programming Languages, you will quickly discover that neither of those two is enough to successfully Engineer Software. SoftwareEngineering, Project Management, and the social dynamics of teamwork, are a whole other kettle of fish. But this “comment” already ran way over budget and scope (Software Engineering joke!)
When I was a computer science teacher, I noticed the habits that new coders tend to pick up.
1) Be proud of what you code, but don’t try to make it pretty or tricky. The end user does not care about the code, but they get upset when your gem of code fails.
2) Make your code easy to troubleshoot and fix for other coders who might have to fix or modify it. Your clever double indirection may make you feel proud, but the coders working on your code will hate you.
3) Don’t waste your time by trying optimize it too much. Normally a millisecond is not something you should cure by making your code an awkward mess.
I am a retired programmer with 33 years of experience, and agree with these points, especially 1 and 2. My observation is that many of the programmers that I have worked with seem to code for themselves, with little regard for those who have to maintain it. Playing the long game also means preparing for the day when someone else is modifying your code.
Unfortunately, the prevailing attitude seems to be document code as little as possible. Sometimes the argument goes, “if I write documentation, then I will have to maintain the documentation too, and the documentation may become out-of-sync with the code.” In my view, that’s a cop out. Good programmers understand that their product is more than just executable code. Leaving behind documentation is important for maintainers to understand WHY something was coded the way it was, and is important for avoiding future bugs as the code is modified. Perhaps more beginning programmers would appreciate this if they spent more of their time modifying undocumented code before writing their own.
Many junior programmers who I have mentored have the habit of starting to code immediately without spending the time to think about the problem. More than once I have had to advise a junior programmer to take their hands off the keyboard and spend the time to explain the problem to me and how they were planning to solve it. I think this is partly due to the pressure from management to produce code as quickly as possible.
It is also difficult to abide by item 3 because many organizations place such a high value on code performance. At my last company, the policy that was that new versions of the code must run as fast as or faster than older versions, even when significant functionality was added. In many cases that I observed, this was too stringent a requirement to meet and resulted in countless fights with the quality assurance team.
I agree with you about programmers should write codes with the intent of helping maintainers. It is also good to note that the documentation can be the code itself that’ why it’s important to write “clean code.”
Certainly, writing clean code is important for maintenance. In my own code, I regularly use long descriptive names, despite the fact that it means more typing. But the source code alone is limited in the information that it can convey. A programmer who is tasked with modifying a module that is undocumented is forced to review all of the code in the module to understand its intent and nuances and has no information on the decisions made by the original programmer. If a programmer makes a choice to code in a way that avoids errors or improves performance, it is probably a good idea to leave a record of that choice in documentation so that the maintainer can also avoid introducing an error or degrading performance.
It is probably true that much in-line documentation does not turn out to be beneficial, but it is sometimes difficult to know when it is needed because you probably won’t be able to predict how skilled the maintainer is or whether they will form the same conceptual model of your code that you had when you wrote it. I err on the side of including more documentation. As a rule of thumb, if you wrote some code a week ago and today had difficulty understanding what you coded, you should probably add documentation.
I feel you talk to a junior me,…Great advice
Your points are off-topic, but important. If you want to learn English, you should also spend some time on english literature, e.g. Shakespeare. If you want to learn programming (“code”), you should also spend some time reading e.g. Knuth, Programming Pearls, Brooks (No Silver Bullet), Coding Horror.
Re 2: coding is communication to another human coder. The compiler can handle any syntax, but we like a high level syntax that is human readable. Communication to other humans is important for fewer bugs (code review) and maintenance.
Re 3: aka Premature Optimization. Usually causes more problems than it solves.
My view on “the long game”: rather than gazing at linear videos I try to program something to solve some immediate problem in the new language. Going criss cross through the book, using the index, while coding “hands on” I learn concepts also quite fast.
After all, programming is not about delivering new code fast. Usually, your code will be used by many users over a long period of time, and the payback of the coding effort should be a huge multiple of your coding effort. Better spend even more time on the application to make your users even more productive. If not, why bother programming? Most problems can also be solved without computer, and when that goes faster, great!
You don’t learn shit with most pre prepared tutorials and exercises, directly. You need to choose a project that means something to you (a problem solved) and just dive in and start trying to make it happen
You’ll make mistakes, hit brick walls, probably write 3 or 5 or even 7 to throw away and restart multiple times when you realise you got architecture wrong, but you will learn useful things the hard way, which is the only way you will ever get any good.
If tub could write good applications just by pasting together code snips to AI would already be doing it.
More people should realize this.
It’s also a good indication of a good company if they hire on this kind of mentality, rather than asking if you know some wonder-stack™ and be able to poop out a crud application in 10 minutes.
I taught myself the basics of programming at 13 with a book and a copy of Turbo Pascal. Using those foundations, over the past 30 years I’ve written production code in Visual Basic, PHP, Ruby, Perl, Python, ECMAScript, C, and Go (off the top of my head, there are probably more.) Once you grasp the fundamentals of programming – control structures, algorithms, debugging – learning a new language is just a matter of varying syntax and vocabulary.
That’s a vast array of languages you’ve programmed in. What would you suggest to someone like me? I love programming, but if I face a roadblock that drags me down and I give up too soon. But once I know the workaround to it it seems like how could I even miss that. Any concepts that you would suggest I should focus more on in order to understand a problem related to programming much better than what I do now.
Amazing post. I won’t hesitate from saying that I belong to the first category. Will spend more time understanding the fundamentals which can probably make things more clear.
Amazing article… I have to spend more time for learning programs… Understanding concept in any programming, practicing programs according syntax its one method of learning the program urself…. And I agree with one more with one concept in this article doing this copy paste and completing given job its not a method of learning.. Without understanding the program and logic doing work is very wrong…
Good learning ideas, refer to reference and learning
100% agree with you Daniel…
I think the majority of learners (myself included) initially get tempted into the speed route but the majority of successful learners at some point grow up and realise that you cannot take time out of this equation, and it is at this junction that true learning and the real journey actually begins.
I completely agree with the point that it is very easy to get trapped in the Tutorial Hell, I have recently published an article on “How I saved myself from the tutorial hell” here is the link: https://medium.com/@sourabhbagrecha/how-i-saved-myself-from-the-tutorial-hell-fdbd0e1b67e9
lmk know your thoughts.
you opened my mind and made everything clears to me after I was feeling insecure and confused it turns out that things are simple and using your logic will help you
As someone who operates from a first principles approach to learning (i.e. deriving things from intuition and building up to pre-requisites/precursors of identifiable tools for building), I feel really relieved coming across your blog. The base logic of flow and creating pathways for things to “click” requires an internal compass calibrated from time to time, and that happens with practice. However, the bane of my existence is learning syntax. In either case, it is essential. But, still annoying to have to work with. I wish coding languages can be more symbolic. Codeblocks helps with visualization, but what if the written form itself was symbolic and intuitive enough? idk.