How to read code without ripping your hair out
- Write More Code
- Read More Code
- Repeat Daily
That was the advice given to me when I made the career switch to programming almost two years ago. Fortunately, there are plenty of courses and tutorials online for writing code. Unfortunately, there are still little-to-no resources that teach reading it.
If it runs on [your] machine, it’s [your] software. [You’re] responsible for it. [You] must understand it.
While every programmer should be reading code, they aren’t. The reason many programmers choose to avoid it is because it’s hard, frustrating, and makes them feel stupid. I know because that’s how it made me feel.
It doesn’t have to be that way.
In my time of reading other peoples’ code, I’ve come up with a process that only involves three steps. Many of you may already be following these steps, but I can guarantee there are many who aren’t.
Here are my steps.
1. Pick a specific point of interest
The first time I tried to read code was a disaster.
I was learning Sinatra at the time and wanted to better understand what was under the hood. Yet, I had no idea where to start. I found the repo on Github and picked a file at random. No joke.
I figured I could spend the afternoon studying it and have a solid grasp on its capabilities by dinner. After all, reading my own code was easy enough, how could this be any different?
We all know where this is going. Suffice it to say, it felt like I was smacking my head against a wall of text.
I had tried to learn too much at one time. It’s the same mistake many beginners commit when they try to read source code for the first time.
Mental models are built piece by piece. Code should be read the same way.
Instead of trying to stomach 1000 lines of code in a herculean effort, focus on a single topic. If it can be parsed down to a single method, even better.
Having a narrow focus will help you know what is relevant and what isn’t. No need to chase down red herrings.
However, choosing a specific topic won’t solve all your problems. There’s still the dilemma of knowing where to look in the code base to find it.
That’s where step two comes in.
2. Find a loose thread
Now that you have a specific method you want to learn about, what do you do next?
Luckily for us all, programming languages come with investigative tools.
Whether you want to know the class of an object, the ancestry of a class, the stack trace, or owner of a certain method, most languages offer these features. Once you begin to unravel the tapestry that is a code library, you will find plenty of loose ends to follow.
Instead of explaining this concept in words, I’d rather show it to you in code
Say I want to learn more about ActiveRecord associations. I’ve narrowed my focus to the
belongs_to method and want to understand how it affects my ActiveRecord models.
ActiveRecord is a part of Rails, which is built in Ruby. Ruby provides plenty of research tools.
My first approach would be to use a bugging tool, such as the
pry gem, to dissect one of my ActiveRecord models. For context, this is the code for the model I chose to debug.
class Comment < ActiveRecord::Base
belongs_to :creator, foreign_key: 'user_id', class_name: 'User'
validates :body, presence: true
Pay attention to the
binding.pry statement. When Rails comes across this line of code,
pry will pause the app in mid-execution and open up a command line prompt.
Below is a sample exchange I had in the pry console when I studied this
- All my inputs are on the lines that start with
=>shows the outputs by the console.
pry> class = belongs_to(:post).class
...omitted for brevity ]
pry> defined? belongs_to
In case you don’t understand Ruby and this exchange confuses you, let me give the SparkNotes.
belongs_to :postruns, it returns an instance of the
MacroReflectionis the superclass of
belongs_tois a class method that is defined on the
ClassMethodsmodule that is inside of
Now that I have some leads, which one should I follow? Since I’m more interested in the
belongs_to method itself and not what it returns, I’ll begin my search in the
3. Follow the trail
Now that you have the thread you want to follow, all that’s left is to trace it until you find your answer. This may seem like an obvious step, but this is where most beginners get tripped up.
One reason for this is that repositories don’t have a table of contents. We are at the mercy of the maintainers to organize their files in readable fashion.
On bigger projects that have many maintainers, that’s usually not an issue.
On smaller projects, you may find yourself wading through monolithic files, deciphering single name variables, and asking yourself “Where did this come from?” too often to count.
One tool that can make this task easier is GitHub search (assuming the project you’re reading is on GitHub). GitHub search is handy because it shows you all the files that match your search query. It also shows where in the file your query matches.
To get the best results, you need to make your search query as specific as possible. This will require that you have an idea of what you’re looking for. Aimlessly searching GitHub with your fingers crossed is not a valid strategy.
Going back to my example from Step 2, I’m trying to find the
ClassMethods module inside
ActiveRecord::Associations. In layman’s terms, I’m looking for the module
ClassMethods located inside the module
Associations nested inside of the
ActiveRecord module. Furthermore, I’m searching for the method
This was my search query.
The results showed me exactly what I was looking for.
More research may be required
GitHub search will significantly narrow the scope of your search. Because of this, you will find an easy entry point to dive into the code base.
Unfortunately, finding the class or method itself is rarely the end of mystery. You may find yourself jumping from module to module until you understand the bigger picture.
In my case, the
belongs_to class lead me to the
build method inside the
BelongsTo class. This took me to the
Association super class.
In the end, I discovered that
belongs_to causes Rails to add several instance methods to my model, including a getter and setter. It does this with an advanced programming technique known as meta-programming.
Rails also creates an instance of the
Reflection class which is used to store information about the association.
From the Rails API docs:
Reflection enables the ability to examine the associations and aggregations of Active Record classes and objects. This information, for example, can be used in a form builder that takes an Active Record object and creates input fields for all of the attributes depending on their type and displays the associations to other objects.
Pretty neat stuff.
While I can’t promise that interpreting someone else’s programming will be fun and enjoyable, it is worthwhile. It will add a crucial skill to your tool belt and grant an extra layer of freedom. You will no longer be dependent on thorough documentation or examples. While those are appreciated, they are not a cure-all. As Jeff Atwood wrote:
No matter what the documentation says, the source code is the ultimate truth, the best and most definitive and up-to-date documentation you’re likely to find.
So take a stab at it!
There must be something you’ve been itching to learn about for some time now. Don’t let the size of the code base intimidate you. Open up the repository to your favorite framework and start digging. If you follow the steps I’ve laid out in this post, you’ll be a source code guru in no time.