Learning modern software development is hard. The list of tools, techniques, platforms, and systems to master is immense and growing. Over the years I’ve seen some junior developers get up to speed remarkably quickly, while others struggle for months or years to achieve a basic level of productivity.
Why is that? There are a few patterns I’ve observed. Everyone is different, but I do think there are some approaches to learning, particularly in the field of software development, that yield an outsized return on investment. These are things I find myself repeating over and over in coaching conversations, so I thought I might as well write them down.
In this article I’ll focus on mental models. Part two will be about curiosity and validating understanding, and part three will be about practice and tool sharpening.
The fastest learners I know are constantly constructing mental models of how the systems they interact with actually work, and adjusting those models to fit new information.
Well, the first rule is that you can’t really know anything if you just remember isolated facts and try and bang ’em back. If the facts don’t hang together on a latticework of theory, you don’t have them in a usable form.Charlie Munger, “A Lesson on Elementary, Worldly Wisdom”
I like this quote a lot. As developers, there will always be aspects of the technology we use that we don’t have time to understand in depth. So when we need to learn how to use these tools, we sometimes fall back on “remembering isolated facts.” When I was starting out, I memorised a handful of git commands that I needed to use every day. I had no “latticework of theory” on which to hang these facts: I had no mental model of how git works. It was a black box, but I knew that if I poked it in certain ways I could get it to do what I needed.
Junior developers, out of necessity, treat virtually everything as a black box: the language interpreter, the operating system, the network protocol, and so on. It would be thoroughly overwhelming to attempt to understand even half of the tools and systems we interact with daily from the get go.
But as the days and weeks pass, we need to start cracking open some of those black boxes, for exactly the reason that Munger points out: our ability to remember isolated facts and recall them on demand is very limited. But when we integrate those facts into a coherent model, they become a lot easier to remember. The git commands I had memorised are no longer magic incantations, now they make sense.
Mental Models and Memory
Let’s say I give you two short, one-sentence stories to remember. In a week’s time, I’ll ask you to recite them word for word. Which of these are you more likely to remember accurately:
- Keyboard from Sally ordered her marketing, so she had to break a new one
- Sally from marketing broke her keyboard, so she had to order a new one
Both sentences are made up of the exact same words in the same structure, the only difference is that one of them makes sense based on our mental model of the world and the other is nonsense. But that distinction makes a significant difference in our ability to remember it.
Putting it into Practice
Let’s take a very common scenario in software development: you encounter an unfamiliar error message. So, of course, you Google the error, and find a useful post with some code purported to solve the problem. Now what?
If you want to deepen your understanding, first form some hypothesis as to why the error occurred. Your guess doesn’t need to be correct, it just needs to be consistent with everything you know about the system. When you’re just starting out, that won’t be much, so your mental model will likely be simple, vague, and wrong. This is fine.
Now that you have this model, try to predict what you need to change. You probably won’t know how to change it, but that doesn’t matter. If you think the problem is that the process doesn’t have permission to modify a temporary file, fine. If you think the florbagorgle can’t zyphox the redux, that’s fine too. Then, when you Google the answer, try to understand what the proposed solution is doing to the system. Let’s say the answer says you need to pass
self to the function. Why? What will that change? Then when you implement the change, observe how the system reacts. Are you surprised? Good, that means your model was wrong in some way. Try to come up with a new model that fits everything you know plus the new observation.
Rinse and Repeat
This is just science. Formulate a hypothesis, then refute it by experiment. Gradually, as you do this over and over, your mental model of the system gets less and less wrong. As a result, it becomes easier and easier to reason about.
When people thought the earth was flat, they were wrong. When people thought the earth was spherical, they were wrong. But if you think that thinking the earth is spherical is just as wrong as thinking the earth is flat, then your view is wronger than both of them put together.Isaac Asimov, “The Relativity of Wrong”
Error messages are just one example. Almost every interaction we have with software tools and systems affords us some opportunity to understand them better.
I should note here that even experienced programmers don’t do this all the time, because that would be exhausting and you’d never get anything done. Sometimes you just use the tool or remember commands by heart (I still don’t properly understand
ps, I just type
ps aux | grep foo every time). Sometimes you just copy/paste the snippet from StackOverflow. But that shouldn’t be the default. It’s ok if you’ve consciously decided that something isn’t worth understanding because it’s not central to your job, or because you don’t have time right now. But in other cases, try to build mental models when you can.
This first part has mostly been about how to learn about software systems from the systems themselves. In part two we’ll look at learning from your team, colleagues, and mentors by practicing curiosity and validating your understanding.