Write Code For Others

Continuing with the theme of interviewing, I’d like to talk a little bit about style. One of the things interviewers are looking for is your style of code. They have seen tons of people solve their question and they want to see not only if you can solve it, but how you solve it. Do you like to write really terse code? Can I read your code easily?

You: What!? In a 45 minute interview, they expect a solution written in nice code?

Yes, I’m afraid so. It’s a check on your habits. If you choose good variable names and structure your code well in an stressful interview situation, you’ll likely stick to these good habits when writing code at work. That, of course, is goal of the interview: what will it be like to work with you?

The interviewer cares very much about what you’ll be like as a colleague. They’ll be reading and modifying your code. They’ll be code reviewing and debugging your code. Their next feature will have to built on a library that you wrote. Can you be trusted with the team’s next product? And then what happens when you eventually leave? Will they be able to make heads or tails of your code? Will they love or loathe working on your code?

Let’s look at an example of good code vs. bad from a stand point of readability. I saw this question on /r/cscareerquestions about the classic FizzBuzz. In it, they offer two implementations, one of which is this:

int main() {
        int c;
        for (c = 1; c < 101; c++){
            if (!(c % 3)) printf("Fizz");
            if (!(c % 5)) printf("Buzz");
            if (c % 5 && c % 3) printf("%d",c);
            printf("\n");
        }
}

Somebody in the thread remarked, “I didn’t know !(c % 3) was a thing.” This exchange made my day.

First the explanation: !(c % 3) assumes that the language treats the integer zero as False. Thus, if the variable c is evenly divisible by three, and the not (!) operate is applied to it, the expression in the if statement will evaluate to True. This means the body of the if statement will execute and the program will print “Fizz”.

Why did this make my day? Because it’s unnecessarily clever. It makes the reader think. If the reader has to think, you’re probably doing it wrong. The whole point of having programming languages is so that we don’t have to speak to the computer directly in one’s and zero’s. The example above makes sense the computer, it doesn’t really care. However, you colleague is going to be annoyed.

Look at the other version provided:

int main() {
        int c;
        for (c = 1; c < 101; c++){
            if (c % 3 == 0 && c % 5 == 0){
                 printf("FizzBuzz\n");
            } else if (c % 3 == 0) {
                 printf("Fizz\n");
            } else if (c % 5 == 0) {
                 printf("Buzz\n");
            } else {
                 printf("%d\n",c);
            }
        }
}

This version can be read out loud to a human in English and they could follow the instructions.

You: but it’s so many more lines! It’s so verbose!

True, it’s not as “pretty” or “elegant”. but it does the same thing and it’s way easier to read and understand the first time through. Furthermore, engineers who write code in a different language are going to be able to read and understand this solution without issue.

The point here is not to focus on this example. Rather I want you to think about what it’s like to read your code. The person who is going to read your code the most is you. After that, it’ll will be somebody on your team. I know you care about these people, make their lives easier!

I’m not suggesting you write overly verbose code. I’m not saying your code should read like plain English. I’m saying, you need to be able to write code that is easy to read for humans and efficient for computers to execute. This is easier said than done, but that is goal.

How does one develop the judgment to write readable code? First, learn another language. In an ideal world, you can write all code in two, or more, different languages. This will allow you to compare and contrast approaches to problem solving. If you know how to write FizzBuzz in multiple languages, say Python and Java, think about what a Python developer would think of you Java solution and the other way around.

Here‘s a one-line version of FizzBuzz in Python

for i in range(1,101): print("Fizz"*(i%3==0) + "Buzz"*(i%5==0) or i)

A Java engineer would find this solution obnoxious. This solution relies on knowing  that, in Python, a string multiplied by False results in the empty string. I would hope even Python engineers would find this obnoxious. It’s clever, but it’s likely not worth it if you have to read it 5 times and look up language specific behavior to understand it.

The second way to develop this judgment is to think about time complexity. This is  a massive topic, which we will cover bit by bit. However, for today, we’ll focus on FizzBuzz. Imagine how long it would take to print out the numbers of 1 to 1,000 instead of 1 to 100. All of them would take 10X times longer because there are 10X more numbers to evaluate. This means they are all equally efficient with regards to growing the size of the input. If they’re all equally efficient, then please chose the human-friendly implementation.

You: Yes, but then my code is generating so many more instructions and therefore it’s so inefficient.

You’re not wrong, but those kinds of optimization are likely irrelevant. Unless you’re optimizing for very specific genres of software, you do not need to worry about this kind of efficiency.

So next time you’re in an interview, do not try to impress anybody with terse code. Write code for yourself and for your team.

Were you keeping track of tools and holes? That’s ok, I was.

Tools:

  1. Learn another language. If you’re an expert in something like C# or Java, think about learning something more fluid like Python or Ruby. If your best language is Javascript, think about something like C#, Java, or even C! Having multiple languages in you tool box will allow you to pick the right language for the right job.
  2. Plain English check – If your possible implementations are have the same time complexity, choose the one that’s as close to spoken language as possible. You’ll be saving yourself and other humans who will deal with your code a lot of hassle.

Holes:

  1. Not knowing another language. This is going to stunt your growth as an engineer. Knowing multiple languages means you know multiple ways to solve problems. With only one perspective, you’re going to see the world through a single dimension.
  2. Time complexity – this is a huge topic. The aspect we looked at today was increasing the size of the input and measuring how much more work the code would need to do. Compare possible implementations by how much more time it would take to process 10 times the data set. If the answer is 10 times as long or less, you’ve likely got a winning implementation. Don’t worry, we’ll revisit this topic again and again.

Ever solved the same problem in two different languages? I would love to hear what you learned from the experience. Shoot me an email with your findings.

Bonus #1

This bit of Perl code became famous for being able to decrypt DVDs

#!/usr/bin/perl
# 472-byte qrpff, Keith Winstein and Marc Horowitz <sipb-iap-dvd@mit.edu>
# MPEG 2 PS VOB file -> descrambled output on stdout.
# usage: perl -I <k1>:<k2>:<k3>:<k4>:<k5> qrpff
# where k1..k5 are the title key bytes in least to most-significant order

s''$/=\2048;while(<>){G=29;R=142;if((@a=unqT="C*",_)[20]&48){D=89;_=unqb24,qT,@
b=map{ord qB8,unqb8,qT,_^$a[--D]}@INC;s/...$/1$&/;Q=unqV,qb25,_;H=73;O=$b[4]<<9
|256|$b[3];Q=Q>>8^(P=(E=255)&(Q>>12^Q>>4^Q/8^Q))<<17,O=O>>8^(E&(F=(S=O>>14&7^O)
^S*8^S<<6))<<9,_=(map{U=_%16orE^=R^=110&(S=(unqT,"\xb\ntd\xbz\x14d")[_/16%8]);E
^=(72,@z=(64,72,G^=12*(U-2?0:S&17)),H^=_%64?12:0,@z)[_%8]}(16..271))[_]^((D>>=8
)+=P+(~F&E))for@a[128..$#a]}print+qT,@a}';s/[D-HO-U_]/\$$&/g;s/q/pack+/g;eval

Bonus #2

There is a language called BrianF!@#. It was designed specifically to be unreadable.

One thought on “Write Code For Others”

  1. well written! totally true. and like lots of interview techniques, applies to normal work too.

    in general i’m with you on avoiding code that’s clever and less readable. more and more though, i have also come to appreciate concise, compact code just as much:

    programming-in-the-large consists of pouring a ton of stuff into your working memory and kneading it all around together, sometimes gently, sometimes forcibly. we use screens to physically edit code, of course, but i mostly see my screen as a kind of backing store where i can swap chunks of code in and out of my head. when code is concise, dense, and high level, i can fit more of it in both my working memory and on screen, which lets me work effectively across more of a codebase at a time.

Leave a Reply

Your email address will not be published. Required fields are marked *