The Pyramid of Learning to Code

When you think about what it takes to build modern software, there three levels of understanding we must go to to become senior developers: Language, where we understand the fundamental parts of the language we are working with; theory, where we understand the why and how of structuring our code, using patterns, and decomplecting codebases; and testing, where we understand how to write automated tests and use test-first practices, known as test-driven development, to build the most maintainable application we can build.

Although the foundation for learning theory is the language and the foundation for learning testing is theory + language, we don’t necessarily have to learn them in this order.

What many new developers do is fail to see the big picture: many fresh entrants see only the language part of the ladder and thus focus too much attention to a mastery of the language, all the things you can do with it, and all the ways you can use the language to write code that’s fancy.

That is wrong.

It’s wrong because of the “sophomore” effect of learning anything: While at first you have low competence and low confidence, as you start learning your ego believes yourself to be a rockstar. Too often we see people who are actually at the low end of the competence spectrum with an outsized sense of confidence. This is called the Dunning-Kruger Effect.

Because the programming industry grew the way it did, many people do not realize or understand the magnitude of this effect, or how significant the magnitude of it has been on our industry.

The Pyramid of Learning to Code is a model to understand not only the full mountain of what you need to learn but also but also gain an insight into how you need to go about learning to code.

Although starting with language fundamentals is important, too much attention paid to language and algorithms will make you a sophomore coder — a wise fool who writes smart, “clever” code that isn’t actually very good code. That’s because good code is loosely coupled to the other parts of the system, and “clever” code is difficult to understand.

The most experienced coders — the ones who’ve made it over the “Peak of Mt. Stupid,” through the valley of despair, and up the slope of enlightenment— understand that application development isn’t about being clever. It isn’t about algorithms or what you learn on LeetCode (although that can help you in some professions in the industry, most application developers will never need to write or know an algorithm).


Automated testing and TDD are the only answer to this problem. Not only is automated testing the absolute pinnacle of good application development, testing when used as a design exercise helps you make your code less clever and more loosely coupled to the components around it.

I believe that while learning language fundamentals (Typescript, Ruby, Swift, etc) are important, it’s equally if not more important to learn software development theory and also testing at the same time. While it might be daunting to think you have to learn everything all at once, there is a real danger to learning a language without learning the theory and testing for the language. For one, your code will wind up clever and brittle, deeply coupled, and if you don’t write tests you will be the only developer ever who is able to work on it.