Why Learning Programming is Slow

Everyone says that learning to program is a slow process and I have to agree. But what exactly makes it so slow? In this blog post, I'll discuss some of these reasons in detail. Understanding them is the first step in creating a strategy for speeding up the process of learning.
By Ciprian Stratulat • Aug 20, 2019

Is programming harder than other skills out there? It's honestly hard to say for certain. However, I do think that programming is less forgiving than other skills for the beginner because of the limitations that current computers have. What I mean by this, is that there is no room for error in your thinking as a software developer, because computers are fairly dumb and they cannot infer what you meant to do. They only do exactly what you told them to do.

The instructions you provide to the computer when you write a program are still fairly low level in this day and age: you can't instruct a computer to build you a website, for example. You have to tell it exactly how to build it, step by step, in great detail, using only the limited set of instructions that are available in the programming language you are using. Skip one step, or get one step slightly wrong, and your program won't work, or worse, it will work in most cases, and then mysteriously fail in some obscure cases.

On the positive side, things have gotten a bit easier over time and, in general, there is a trend towards higher and higher level thinking and, in some cases, computer assisted software development. In addition, free, open-source libraries and modules that package certain 'abilities' and make them easy to be used in your own software are making it easier to build ever more complicated programs.

Going back to the website building example, things have gotten much, much easier over the last couple of decades. This is not because computers have become smarter and are able to understand more of our intentions, but simply because people have created and offered for free these packages of higher-level abilities that make it easier to build a website.

Despite all this, however, programming itself is still very much about the low-level details rather than the high-level picture, although awareness of the latter is always something that a good software developers keeps in mind. So with all this in mind, let's explore a few different reasons why learning programming is a slow process.


Thinking in small steps takes practice

Contrary to what beginners may think, what most people learning to code struggle with is not as much the new syntax of a programming language, or even the programming environment with all its tools and commands. From my experience, the hardest thing about programming is that it requires a slightly different way of thinking.

As human machines, we are pretty good at doing complex tasks, but are not always good at describing how we achieve what we do. Sometimes, that's because we genuinely don't know how we perform those tasks. For example, I couldn't exactly explain how I recognize shapes, or how I am able to utter words.

Some tasks, however, we could describe in great detail, but we're not in the habit of doing so. If I asked you to describe your morning routine, you could do it. You could probably describe every step in great detail, but you don't do this often, so it would require some thinking.

Programming requires thinking in very small steps, using a limited number of building blocks and concepts to build solutions to general problems. This is because, on some level, programming is simply the act of translating our intentions into a language that computers can understand. As I mentioned, despite their ever-expanding raw computational powers, computers are still fairly dumb: natively, they only understand a few, very low-level concepts. Popular programming languages build on top of those abilities and offer slightly-higher level concepts to work with, but even these concepts, or building-blocks, are still more like lego pieces rather than finished parts.

Let's go over an example. Say I give you a list of names - 'Mary', 'Alice', 'James' - and I ask you what number you'd get if you put together the number of letters in each of the names. Upon some thinking, you could probably tell me that the number is 455. This is because Mary has 4 letters, Alice has 5 letters and James has 5 letters.

This is a question that a computer can also answer, and in fact it would answer it in a somewhat similar fashion to humans, namely by taking each name in turn, counting the letters in each name, keeping track of those counts and finally building the number 455.

But the solution that I described here is actually pretty high level. What does it mean to 'take each name in turn'? How do we actually determine the number of letters in each word? How do we keep track of the counts for each word? How do we actually assemble the final number? These are pretty high-level tasks that computers would not natively know how to perform. A program needs to be written that breaks down each and every step into smaller steps that a computer can actually understand.

A more detailed solution could probably be something like this:

  • store in memory the list of names ('Mary', 'Alice', 'James')
  • store in memory the fact that we are now considering the first name in that list
  • recover from memory what the first name in the list is (it's Mary)
  • store a counter in memory (starting at 0)
  • go letter by letter through the current name, increasing this counter by 1 for each letter, until we run out of letters
  • store the final counter in memory (it's 4)
  • store in memory the fact that we are now considering the second name in the list of names
  • recover from memory what this second name is (it's Alice)
  • store a counter in memory (starting at 0)
  • go letter by letter through the current name, increasing this counter by 1 for each letter, until we run out of letters
  • store this new final counter in memory (it's 5)
  • add this final counter next to the previous counter to obtain the number 45
  • store this number in memory
  • store in memory the fact that we are now considering the last name in the list of names
  • recover from memory what this last name is (it's James)
  • store a counter in memory (starting at 0)
  • go letter by letter through the current name, increasing this counter by 1 for each letter, until we run out of letters
  • store this new final counter in memory (it's 5)
  • add this final counter next to the previous counters to obtain the number 455
  • say the answer is 455

We don't usually think in this much detail. In fact, when we're asked to explain our thought process, we rarely go down to this level of detail. But oftentimes, this is the kind of level of detail that we need to think at in order to write computer code. The reason for it is simply that computers cannot think at a higher level than this.

But thinking in small steps requires training. Understanding how small these steps should be requires knowledge of what fundamental building blocks or concepts are available to us, as well as practice combining those building blocks into solutions to problems.

For example, in the solution above, I use a lot of 'store X in memory' or 'recover X from memory'. This is something that as humans we do naturally - in fact, we're probably not even aware of it, unless we're having a hard time remembering something. When programming, however, accessing and using information stored in memory is something that must be done explicitly.

The takeaway is that part of learning to code is learning to think in small steps and learning how small these steps should be, such that they can be easily translated into instructions that go into the programs we write. Acquiring this ability takes time.


Generalizations are hard

Another thing that makes learning to code hard is that programming requires us to learn to generalize well. Computer programs aim to solve classes of problems, not just individual problems. This means that, if we were to write a program to solve the task I described above, ideally we would write a program that works for any list of names given to us, not just for when the list is 'Mary', 'Alice', 'James'.

Many inexperienced programmers can find a solution to a specific instance of a problem, but have problems generalizing that solution to solve all similar problems in an efficient manner. However, these general solutions are exactly what make computers so powerful. In fact, the ultimate goal of computer science, one could argue, is to create a program so powerful that it could solve any problem. This, of course, would be akin to replicating the human brain, something called AGI (artificial general intelligence).

So the takeaway here is that while we may be natively good at solving problems, as intelligent beings, we're not necessarily good at generalizing our solutions to apply to similar problems. Developing this ability can be a slow process, thus making programming a slow skill to acquire. This is also where having some math experience can help, though I do believe that you can be a good software developer without necessarily being good at math, something perhaps a bit controversial in some circles.


Learning the right patterns takes time

Here's an interesting thing: programming languages have very few words. In fact, you can read below the list of all Python keywords:

False, None, True, and, as, assert, async, await, break, class, continue, def, del, elif, else, except, finally, for, from, global, if, import, in, is, lambda, nonlocal, not, or, pass, raise, return, try, while, with, yield

These are all the reserved words, as of Python version 3.7.2. You can use these words, and other words of your own choosing to make programs that solve very complex problems. Compare this to an actual human language, like English, which has, by some accounts, hundreds of thousands of words.

Looking at it this way, it's perhaps more obvious that the difficulty doesn't come from mastering 'the language'. It comes from mastering the 'patterns'. These patterns describe concepts that build upon other concepts to create ever more powerful building blocks that you can use to solve problems. Acquiring a library of patterns that you can use is a process that takes time. 

As a side note, while acquiring a library of patterns you can use to solve problems takes a long time, it comes with a surprising benefit: it makes it easy to pick up new programming languages. In fact, once you've mastered one programming language, you can pretty much teach yourself any additional programming language you want. This is because, fundamentally, these building blocks are common across programming languages. It's also for this reason that I do think that novice programmers would benefit more, in the long run, from learning more about programming concepts in general, and less about specific libraries for a given programming language.

This last point is also part of my biggest criticism of most software bootcamps in existence today: they teach a language, not a way of thinking. They may be focused on Python, or Javascript, or even narrower, on a library like React JS. This can be useful to make someone immediately productive, and immediately hireable (though not always), but in the end they fail to teach students how to create solutions to problems in a way that they can be translated frankly to any programming language, and ultimately understood by computers.


Final words

The difficulties I highlighted above are not the only ones that slow down the process of learning to program. There are, unfortunately, many other obstacles: programming requires the ability to focus for long periods of time, something that is becoming more rare nowadays; it requires a very strong short term memory; it requires the ability to think very clearly etc. It also requires the ability to sit in a chair for hours on end, which should not be underestimated.

For some tips on how to speed up the process of learning to program, check out my blog post about how to learn programming faster.

Ciprian Stratulat

CTO | Software Engineer

Ciprian Stratulat

Ciprian is a software engineer and the CTO of Edlitera. As an instructor, Ciprian is a big believer in first building an intuition about a new topic, and then mastering it through guided deliberate practice.

Before Edlitera, Ciprian worked as a Software Engineer in finance, biotech, genomics and e-book publishing. Ciprian holds a degree in Computer Science from Harvard University.