This week's video for Dave Farley's Continuous Delivery YouTube channel is me ranting about why reading code sucks, and offering some advice on how to improve.
"Every programmer occasionally, when nobody’s home, turns off the lights, pours a glass of scotch, puts on some light German electronica, and opens up a file on their computer. They read over the lines, and weep at their beauty…."
https://www.stilldrinking.org/programming-sucks
The original idea for this video is from my presentation Reading Code Is Harder Than Writing It, which I only got to present twice. I feel like I never quite got the hang of what I was trying to say in the talk, but honestly that's normal for any presentation I've given less than three times.
When you take a 50-minute presentation and condense it down to a sub-15-minute video, you have to think hard about what the key points are:
- Generative AI == Reading More Code
- Developers Hate Reading Code
- Tip 1: Navigate the Code, Don't Write Code
- Tip 2: Make Notes
- Tip 3: Draw Pictures
- Tip 4: Annotate the Code
- Tip 5: Ask Questions
- Tip 6: Use Tests
- Tip 7: Tidy as you Learn
- Final Tip: Remove Your Ego
Here's the video. The transcript is underneath, if you prefer written content.
Special fact just for my blog readers: I'm wearing this Vampire top because I recorded this on Halloween. I've worn this top almost every Halloween since the late 90s/early 00s, and I love it.
Ask a developer what they do, and they'll say they write code. Actually, we spend way more time reading code and trying to understand it. But we hate reading code! Especially badly written code, by which I mean other people's code, or code I wrote ages ago (like last week).
Yet with the rise of AI, we're reading more code than ever. More code that we didn't write, more code that we might not understand. What can we do to get better at reading code? What can we do to perhaps hate it a little less?
The rise of generative AI as a productivity tool is supposed to be a good thing, but I can't help thinking that it takes away the fun part of being a developer, writing code, and leaves us with the much less fun part, reading code. We've traditionally always read code more than written it, but we don't talk much about the skill of reading code. We talk about writing readable code, but not about learning how to read that code, no matter how readable it's supposed to be. When we teach coding, we focus on teaching someone how to write new code, we don't teach someone how to understand existing code, or how to find the correct place to make changes or to write new code.
Developers hate reading code
We hate reading code often because we don't understand it. Perhaps because another person wrote it, or because our past selves might as well have been another person.
We hate reading code because we're judging it as we read it. We know a better way of doing it. We wouldn't have done it that way. This applies to whether the code is written by someone else or written by us.
We hate reading code because it's boring. It's not like reading a novel. It's not a story. It doesn't give you dopamine like writing code, where you're creating something and it works and the tests pass and we can see something happening! It doesn't feel like you're doing anything when you're reading code. It doesn't feel like you're being productive.
And we hate reading code because we don't practice it. We do it all the time, but we don't use [deliberate practice]. We don't intentionally get better at reading code, the same way that we intentionally get better at writing code or refactoring it.
Practice
It reminds me of this quote:
"My fingers", said Elizabeth, "do not move over this instrument in the masterly manner which I see so many women's do. They have not the same force or rapidity and do not produce the same expression. But then I have always supposed it to be my own fault because I will not take the trouble of practicing".
We won't get better at something unless we practice it. We don't really take the skill of reading code very seriously. We certainly don't take it as seriously as the skill of writing code. However, since we read code so much more often than we write code, we should be taking reading code very seriously as a skill.
We should be practicing it. We should be getting better at it.
1. Navigate the Code, Don't Write the code
When we're trying to understand what the code does, when we are trying to find the bug, when we are trying to identify where to put the new feature, we should be navigating around the code to have a look at what shape it is; which bits of the code are calling which other bits of the code; and how it all fits together.
I'm going to show you some tips in my IDE which help me to navigate through the code. You'll see as we do this that we don't read code in the same way we would read a novel. We don't read it from the top of the page to the bottom of the page. We read it more like we read the internet, using hyperlinks to skip through and find the relevant information.
To see the tips in action, watch the video. Here I've listed some of the shortcuts:
- (⇧⇧ | Shift+Shift) to open the Search Everywhere dialog
- (⌘B | Ctrl+B) to Navigate to Declaration
- (⌘⌥B | Ctrl+Alt+B) to Navigate to Implementation
- (⌥F7 | Alt+F7) to Find usages
- (⇧⌘T | Ctrl+Shift+T) to Navigate to Test
- (⌘[ | Ctrl+Alt+Left Arrow) to go back a step
- (⌘] | Ctrl+Alt+Right Arrow) to go forward a step
- (⌘L | Ctrl+G) to go to a specific line number
- (⌥⌘T | Ctrl+Alt+T) to surround with a custom folding block
- (⌘. | Ctrl+.) to fold or unfold a code block
- (⌥␣ | Ctrl+Shift+I) to display Quick Definition
- (F1 | Ctrl+Q) to display Quick Documentation
- (⌃⌥Q | Ctrl+Alt+Q) to toggle the rendered view for documentation comments
- (⌘E | Ctrl+E) to open the Recent Files dialog
- (⇧⌘E | Shift+Ctrl+E) to open the Recent Locations dialog
2. Make Notes
My second tip, which goes hand in hand with navigating the code, is make notes. It's all well and good navigating through the code, finding out what calls what, where the calls come in, where the data flows to, which bits are important, if we don't somehow make a note of that so we can remember it in future. Make notes about what's going on.
There are multiple ways you can do this. I, for example, do like to use a physical piece of paper, a physical notebook to make notes. I have a specific style of making notes which works for me. The limitation of using this is it only really works if you're going to take it everywhere you work, or if you always work in the same physical place.
I also like to make notes with OneNote because the notes are synced across all my laptops and my phone. You could also be using Evernote, Google Drive, or saving things in Dropbox, anything that will sync your notes across multiple computers.
If you're fortunate enough to have a whiteboard, you can make notes on a whiteboard. This is particularly helpful if you want to do diagrams, which I'll come to in a minute. My notes are often in list form, that's what works for me. but some people prefer mind-maps, doodles, or unstructured notes that work for them.
3. Draw Pictures
Pictures are a really important way for us to understand stuff. These pictures do not have to be official UML diagrams. You don't have to use a diagramming piece of software. You don't have to follow the principles of well known diagramming techniques (although if you want to, take a look at Simon Brown's C4 model)
You just need to draw something which makes sense to you. Often, if we write down notes and do drawings, those two different ways of codifying the information can help create a mental model which sticks in our head. You can draw these pictures anywhere you want. You can be drawing them on paper, on a whiteboard, on some sort of note taking application, which is easier if you have a stylus.
I often prefer to have the notes separate from the code. I quite like the physicality of having a piece of paper and a pencil which is separate from the machine that I'm actually writing the notes with. I don't really know why that is, but that's, that's a preference for me.
4. Annotate the Code
So far I've suggested notes and diagrams away from the code. However, you might want to keep the notes with the code itself. Annotate the code. You might want to use comments. You might want to rename methods to make it clear what those methods do. I'll mention refactoring again a bit later on. You might want to use a feature called code folding, which is something I've been using in IntelliJ IDEA.
It's quite a useful way to hide away distracting parts of the code, but annotate it with something to remind us what it does. We could even use it to effectively comment a specific section of code, the bonus here is that it clearly marks the beginning and end of the commented code. You can also use it to group together related methods so you, and other readers, have a clearer idea of the theme of the methods.
A short and shameless plug, if you are interested in any of the IDE tips that I'm covering in this video, I've got a whole section in my book Getting to Know IntelliJ IDEA about how to use IntelliJ IDEA to better understand code.
5. Ask Questions
My next tip might sound obvious, but I don't think our industry has been great at encouraging this practice. Ask questions. We don't like to look stupid. We don't like to look like we don't know the answers. However, we can't possibly know everything about the code or about the history of the code or about exactly who uses it and how.
If we don't understand something, we don't have to bang our head against it. There might be someone in our team who can answer our questions. If you're fortunate enough to pair program while you're understanding a piece of code, obviously you and your pair can ask each other questions, can bounce things off each other.
It's more likely, particularly if you're working remotely, that you're going to need to ask questions asynchronously over Slack or email or a shared Google Doc or whatever. But you should feel free to ask questions. And if your company culture is not one which encourages asking questions, try changing that culture. If you're senior in the team, you should set the culture by asking questions, especially the obvious, or sometimes stupid, questions. If one of the most experienced team members is comfortable asking questions, it shows everyone else this is acceptable and expected.
6. Use Tests
Here's a tip that regular viewers of the channel probably expected much earlier in the video: use tests. Use tests to find out what the code should be doing. I am, of course, assuming that there are automated tests in your code base, and I really hope, for your sake, that there are. Find the tests. In IntelliJ IDEA, you can use the keyboard shortcut Command Shift and T to go to the test for a specific class. It will also be pretty smart about finding tests which look like they're vaguely related to the class that you're trying to test.
Once you navigate to that test, you can have a look at what that test is doing.
Hopefully, it has a useful method name which tells you the expected behavior of the code.
Hopefully, the test is readable so that you can see things like what needs to bein place in order for that method to work.
Hopefully, the test will give you some clues as to what the method does and hopefully, why.
One way to understand the code may be to break those tests. So the tests go green. That's great. How can you make them fail? Have a bit of a play with changing the test code or the production code to see how to make those tests fail. That should prove or disprove any theories you have around how the code works.
Whether you have existing tests or not, you can write new tests for the code to check any hypotheses you have about how it works. If you think that the place order method will reject orders that have particular values, write a test to prove or disprove that hypothesis.
As developers, we do like to write code. So if you must write code while you're trying to read it, writing new tests is quite a good way to be writing and reading at the same time.
7. Tidy as you Learn
Given that we do like to write code, there are some other ways we can write code that will help us to understand the code we're reading. I'm reading Kent Beck's Tidy First and there are a lot of tips there about how we can make the code that we're looking at just that little bit better as we understand it more.
This will leave it in a slightly better state than it was when we found it. We can rename methods so it's clearer what they do. We can move related methods closer to each other so that you can keep them in your brain at the same time. We can extract small helper methods and give them useful names. We can do tiny things like add blank lines to more clearly group related lines of code.
Remove Your Ego
I want to leave you with my final tip for reading code: We have to remove our ego when we read code.
When we read code we are often, consciously or unconsciously, judging it. Perhaps because reading code triggers the part of our brains that has been trained to perform code reviews, or perhaps because our brains are racing ahead to thinking about how to change it.
We are judging it, and we're often judging ourselves at the same time.
For example:
- Urgh, this code is worse than something I could have written. I hate it.
- Oh my goodness, this code is so much better than mine, why can't I write code like this?
- Ugh, this code that I wrote is awful. I must be a terrible programmer.
We are constantly judging the code and, directly or indirectly, judging ourselves. No wonder we hate reading code.
If we're reading a book, we don't think "I wouldn't have written the book this way, I hate it". We might enjoy the book precisely because it was written in a way that we couldn't. Because it's unexpected and surprising.
Perhaps we could take a little bit of joy in reading someone else's code. Perhaps we could take something out of it like, "Oh, I never thought of doing it that way". Instead of "Ugh! Why didn't the author do it my way?"
When we're reading code, we should sit back and enjoy the ride. We're going to learn something from it. We might learn something from the code itself, or we might learn something about ourselves.
Most importantly, don't judge the code. Don't judge yourself. That will just make you miserable.