Welcome to this talk: Ouch! That code hurts my brain.
Raise your hands if the following scenario sounds familiar to you.
After a day of work, you feel exhausted and have a headache.
You get back home feeling so tired that you don’t want to say a single word.
You close your eyes and feel the pain inside of your head.
This talk is about how to turn code from brain-hurting to brain-friendly.
I work at a startup called
I blog at sihui.io. I share lessons learned at work and things related to software design.
This talk contains three parts. First, why some code tires us out? Why some code makes total sense to a group of people but is hard to understand to a different group of people? Second, how to turn brain-hurting code into brain-friendly one? Last, we will look at some code samples together.
Here’s another scenario.
You stumble upon a piece of unfamiliar code at work. Because it’s not immediately obvious what the code does, you jump to the definitions of some of the methods it uses. You read the definitions, but still don’t fully understand those methods. So you search the codebase and see how they are used elsewhere.
15 minutes later...
This is how you look like from your coworkers’ perspective.
But, this is how you truly feel inside. You are so frustrated by the code that you want to flip your desk. Sometimes this even happen to code we wrote ourselves weeks ago.
So why? Why the exact same piece of code made total sense when it’s written, but became hard to understand later?
It’s because the process of writing code is very different than the process of reading code. When we receive a feature request, we have a big picture in mind about what the code eventually should do.
During development, we break that big picture into smaller pieces, into classes and methods.
But when we read code, we don’t have that big picture in mind. We don’t know what the code suppose to do. All we have is a small piece of the big picture.
If it’s not immediately clear what that small piece does, we try to find more relevant code. In order to understand the code, we read all these pieces and try to reconstruct the big picture. We do all these work in our heads, using working memory.
Working memory is for short-term memory and reasoning. It’s limited and precious. When our working memory is filled up, we feel overwhelmed. Any work that requires thinking becomes more difficult than usual. That’s where the headache comes from.
Having the big picture in mind or not makes all the difference.
It's all about the context we have. When we code, we have the full picture in mind. But a few weeks later, when we look back at the code, most of the context is gone and the code in front of us is all the clues we have.
The key is to keep each puzzle small and leave many clues in the code. When each piece is small and the code provides enough context, the code becomes self-explanatory.
Before we dive into the “how”, let’s take a look at why brain-hurting code is bad. Brain-hurting code is like this slide. You couldn’t tell what it’s about at first glance. You either have to make a guess or ask its author.
Brain-hurting code is exhausting.
Because it doesn’t tell you what it means to do immediately, it’s hard to reason about,
which makes it hard to understand the underlaying business logic.
As a result, discovering edge cases becomes difficult.
Essentially, code that’s hard to understand makes us unproductive and takes away to joy of programming.
So how can we turn brain-hurting code into brain-friendly one?
We start by spotting brain-hurting code.
If you are the reader of the code, for example, you are reviewing a pull request, stay sensitive when reading through the code. If you have questions when reading through it, the next developer who comes to deal with the code might have the same questions. If you have to spend five minutes to figure out what a piece of code does, the next developer might have to spend the same amount of time. Stay sensitive and note down areas where the code is not immediately clear to you. These are the brain-hurting parts. And the goal is to make the code clear enough so the next developer won’t have the same questions. The goal is to save all future developers who might stumble upon the code that five minutes of their lives.
If you are the author writing the code, ask a coworker from a different team to look at your code with you. You need to pick someone who doesn’t have the context you currently have. Note down areas where your coworker has trouble understanding. When your coworker asks you what you are trying to do with a specific piece of code, don’t answer the question immediately. Instead, ask your coworker what he or she think the code does. And work with your coworker to make the code more self-explanatory so the next person won’t have the same question.
After spotting brain-hurting code, how can we make it brain-friendly?
Again, the key is to keep each puzzle small and leave many clues in the code. So the code becomes self-explanatory.
Small means doing only one thing at a time.
Small means breaking a big picture into small parts that makes sense.
Leaving clues means to code as if you are writing English.
Let your code tell the story. When your code directly says its intention and what it does, readers can understand the code at first glance. Instead of having to figure out what the code does, they can now focus on if the business logic is correct and if there are any edge cases.
Let’s take a look at a code sample from the discourse open source repo.
HandleChuckUpload class with a
check_chunk method. Let’s see what this method does. It begins with a condition check. If the result of the condition is true, it returns 200. Otherwise, it returns 404. What exactly is the condition checking? It sees if the chunk exists. If so, it then checks to see if the existing chunk size is the same as the
current_chunk_size. As I read this code, my first question is: “what exactly is this code checking?” Seems like the condition is checking to see if the chunk exists. And the class is
HandleChunkUpload. So I guess the condition is checking to see if the current chunk has been uploaded. Let's give this condition a name so the code tells exactly what it’s checking. So the next developer doesn’t have to go through the same thought process we just did.
Now the code becomes, first check to see if the chunk has been uploaded. If so return 200, otherwise return 404. My next question is what exactly are 200 and 404. Coming from a web development background, I guess they are http status codes. Why don’t we just tell the reader that so they don’t have to guess?
Now the code becomes first check to see if the chunk has been uploaded. If so returns 200 as the status, otherwise return 404 as the status.
If we want to be even more clear, we can leave comments. This is how the code looks like in the discourse repo. 200 means the chunk exists and 404 means it has not been uploaded yet. The code is so clear that anyone who could read English should be able to understand it without any problem.
Clear writing requires clear thinking. The process of making the code more clear is the process of gaining a deeper understanding on both the problem and the solution. When our thinking is clear, our code becomes clear.
Next, let’s take a look at another code sample. (The live coding part is included in
In the software world, we talk a lot about making our products as user-friendly as possible. Code is written once, but read many times. As a developer, readers of your code are your users. Writing brain-friendly code is about being thoughtful of the reading experience of your code. Create a great reading experience for your users. Write brain-friendly code.
Slides are available on sihui.io/brain-friendly-code. You can find me on sihui.io or @sihui_io.
Thank you! <3