How To Read Code

Scientifically Tested Code Reading Skills

I’ve run across a paper [pdf] researching how we read code. The article describes an eye tracking device that can identify what people were focusing on when they were given a piece of code. Each subject was given six snippets of code, each with a built-in error, and was asked to analyze the code and find the error. Here’s a sample from the article:

On the left, a small snippet of code that should sum numbers for 1 to a given maximum. On the right, the eye movement of the subject as he reads the code. Notice how the eye first scans the function headers, then briefly scans the function’s body and lastly focuses on where the problem is most likely to appear in real code (the loop).

Reading Code is Like Reading the Talmud

This reminded me of a very old post I’ve read at Joel Spolsky‘s blog. Joel quotes Seth Gordon which says:

The following Talmud-reading tactics are, I think, also useful for code-reading:

  1. Work in pairs, thinking out loud to one another.
  2. Argue. If your partner says “this means X”, and you either don’t understand why or you have another opinion, demand an explanation.
  3. Sometimes, when dealing with a chunk of text, it’s easier to figure out the middle *after* you understand what’s on both ends. Therefore, if a fragment of text has you stumped, try skipping over it and seeing if you can come back to it later. (But you still have to come back to it eventually.)
  4. Read the text both “inside” and “outside”. An inside reading translates the text into English (or whatever your native language is) phrase-by-phrase; an outside reading translates a larger chunk into an idiomatic paragraph. If you only read inside, you can miss the forest for the trees; if you only read outside, you can fool yourself by making broad guesses and not verifying them with details.

Seth describes two types of code. Some code is easier to read and understand first, and is the basis to the rest of the program (Type I). The second type of code is dependent of other code, and so is easier to understand in context (Type II). This fits with what I look for when I need to learn a new piece of code:

  1. Class and interface dependency: look for the base classes, which depend on no other class. These, usually, are small and simple objects, with the purpose of holding a little bit of state. They may do some calculations, but are mostly built around an internal storage and a bunch of get-set functions. These are classes of Type I. Skim through them now.
    After you are familiar with the basic building blocks, you can look for the manager classes. Most of the time there will be  a bunch of very big, hairy classes that are the core engine of the software. These are classes of Type II. Make sure you understand, from the function names, what each of these managers is supposed to do. After that, you can delve in. Manager objects usually only make sense when they interact with each other, so you have to have an idea about how all of them are designed before going into any of them too deeply. (Tip: The class called Manager is not always the manager. The class called from the main() usually is).
  2. Assume a lot: Assume that function and variable names matter. If you would have written the code, what would the GetNextIndex do? Assume it does exactly that. If a function has a name that sounds obvious enough, skip it. You’ll get back to it if you ever need to use it. Why waste your time on something you don’t need right now? There’s only this much detail you can keep in mind at this point. If you dig too deep, you’ll start forgetting things you’ve already read. Focus on purpose and structure, not on implementation.
  3. Learn by debugging: Unit tests matter, but real code matters more. If you really want to understand how the code works, the fastest way is to use it. Fire up your IDE and write a quick and dirty demo of what you wanted to use the code for. Chances are your code is bust. I’ll be surprised if you can get it to work on the first go. That’s OK. Now, start debugging. You’ll learn the inner workings of the code (and its bugs) much faster, and you’ll only focus on the parts that matter to your task.

Writing Readable Code Matters

  • Function names matter: we’ve known this for a long time, but now we know that we scan function names first. A good name, and you don’t need to focus on the implementation all that much.
  • Variable names matter: again, nothing new. Notice, though, how the eye goes back to the variable definition and assignments. We constantly look for reminders of the state of the variable.
  • Loops are the source of all evil: well, that’s not entirely true, but they are worse than all other statements. Notice how figuring out the loop is the most time consuming bit of the code. It’s where most pitfalls are (Oh, the index should be smaller OR EQUAL. Right. I forgot). Commenting can help some, but just keeping the conditions simple and readable is key. Break complexity down around the loop.
  • Short code is easier to process, so get your refactoring tools out, everybody, it’s time to split these functions.

My favorite list of tips for readable code is uncle Bob’s guide to Clean Code: A Handbook of Agile Software Craftsmanship. Even if on some occasions it gets tedious and overzealous, it is still a great read for the practical coder, dealing with many issues of writing readable code and refactoring.

Scientific Side-note

The research certainly doesn’t prove much about the way we read code, as it was only tested on 5 (that’s right – five) people. To me it seems like more could have been done.

I mean, going through the lengths of creating a really awesome eye tracking device, carefully calibrated so the machine can tell which line of code is being inspected at any moment, and then test it only on 5 people? Is getting more people into the test room so much hard work? I’d love to be a test subject and learn about my code reading habits. Next time, pick me.

Be Sociable, Share!

    Also read...

    • sagivmalihi

      I once participated in such an experiment (not with code reading – but with eye tracking), and it is indeed really cool. I do understand why it’s hard to find candidates for this type of experiments, because first – people who read code usually have a more paying way of spending their time, and second because these kind of experiments have a big overhead of calibrating the (very uncomfortable) eye-tracking machinery to the specific subject.

      About readability – I think the real strategy is using readable languages, that have more readable building blocks (such as generators / list comprehensions in python, that are definitely better than ugly while loops). I heard Haskell is also in the right direction, although not a very readable language per-se, it’s strict-typing often times allows one to understand what function does directly from it’s type, without looking at the implementation.

    • http://www.thepursuitofquality.com Gavin Miller

      I remember seeing the eye study & graphic in Jason Cohen’s book Best Kept Secrets of Peer Code Review. You came to many of the same conclusions that he did such as loops are evil and short code is good.

      The paper also lays out other good foundations for code review such as slowing down on the first pass increases defect detection & that local variables should be visible on the screen where they’re used (IE not c style declaration at the top of a method.)

      Great article Omer!

    • http://muhammadghazali.web.id/ Muhammad Ghazali

      Great article for real! :) But, I think they should test it on more than 5 people. Btw, good explanation. Thank you.

    • http://kevinrodrigues.com/blog Kevin Rodrigues

      Maybe it is also like book reading. The more you read, the more comfortable you will be in further reading. And your reading patterns will also differ. So if the experiment is conducted it should be conducted among a range of programmers like freshers, intermediate, experienced code readers.

    • doppelhl

      very helpful article. thanks. but, Fixation num looks like too overstatement, i think. as Ghazali say, test should be performed on more than 5 people. but, this is very impressive article.

    • http://omergertel.com Omer Gertel

      @Kevin, You’re right. I’d love to see some data on how experience affects how you approach code. It’s a shame eye tracking is still so complicated that running this test is so difficult.

    • http://www.tobii.com Joakim Isaksson

      Very interesting! Though Eye Tracking is not necessarily complicated today; it all depends on what equipment you use. Modern systems take 15 minutes to set up and 15 seconds to calibrate each test subject. Recruiting and administering the subjects is much more time consuming.

    • tdwright

      As someone who regularly works with eye-tracking technology, I’d have to agree with some of the previous commenters: the technology isn’t that complicated. Most university psychology/neuroscience departments will have a rig.

      Moreover, with stimuli this messy, you couldn’t automate the quantification. Instead, you’d have to watch the recordings and categorise different types of saccade. (Preferably, you’d have more than one person do this.) Typically (in academic settings at least), eye-tracking experiments use much simpler stimuli. I suspect this is why they analysed so few people.

    • http://omergertel.com Omer Gertel

      @tdwright – Interesting point, but it still means the overall complexity of doing these tests is quite high.
      I wonder if a large bunch of test subjects combined with some data-mining algorithms could identify the main patterns. Also, heat maps are simple first-approximation of total focus (some display combining time and heat-map, perhaps?).

    • http://www.rickwagner.blogspot.com Rick

      Thanks for the good post. You have furthered our profession!

    • http://www.andrew-leer.com/ Andrew J. Leer

      I used to go to Vision Therapy (which I later found out the problem had more to do with my TMJ than it did my eyes), and they used a vision tracking system to watch how my eyes moved when I read something. The apparatus looked like a circuit board that fit around my eyes, it wasn’t bulky at all.

      I was really surprised when I looked at the results of how my eyes were scanning the page, I don’t think that I was even aware of the course they were taking.

    • Ralph

      The sad part is the code itself.

      Input is not limited to positive numbers – entering a negative number will give meaningless results.
      Todo: limit input to positive numbers, use unsigned int variables.

      If a rather large max value is use, the resulting sum will overflow – again giving meaningless results.
      Todo: limit input to largest number that will sum to maximum int value.

      If your loop is iterating through every value, use a for loop. If not, then use a while loop. The while loop here adds extra code that is not clarifying what the code is doing.

      Doesn’t matter where your eyes are going if you can’t fix these things!;-)

    • http://pl4n3.blogspot.com/ Pl4n3

      Great read! Though, splitting functions, not generally makes code readable to me. If new funcs after a split are called only once, i would keep it as code-block in the calling function. Otherwise stuff is too much spread and has misleadings semantics (a function is meant to be generally usable and to be called more than once).

    • http://www.civilized.com gary knott

      Why are we reading code? Isn’t the purpose of comments
      to help us avoid reading too much code?

      – See http://www.civilized.com/programming.html

    • http://omergertel.com Omer Gertel

      Actually, modern practice is not to use comments, but make the code self descriptive. This has a few good reasons:
      A) In modern languages code is much more readable. Think of python, ruby, Java and C#. Object oriented, high level languages are easier to read.
      B) Comments are usually not updated when code changes, which makes them worse than waste. They actually hurt understanding. Comments should really last resort.
      Contrary to previous comments, about a function being called only once, it is actually a great way to make the code readable. For example, if you have an if statement – you can create three functions to describe the if statement, and then you don’t need a comment at all:

      if (OrangeIsRipe(color, size)) {
      MoveToBoxing();
      } else {
      ThrowAway();
      }

    • http://www.technikhil.com technikhil

      There is one aspect of code reading that one must consider. In the real world you don’t generally have the luxury of reading self contained code snippets. Sometimes you get a large bunch of inter-connected code or an conditional statement that runs several pages or even a large class hierarchy.
      In such cases the more appropriate description of the activity you are doing become “code comprehension” – I write about this in more detail in my post – check it out – http://technikhil.wordpress.com/2010/07/06/how-to-read-code-a-primer/

    • nurnur

      Grrrreat article!! Thank you. I am implementing your tips right now. The book you recommended is also very good, I keep getting back to it for coding principles.