Logo for NNM (Nemo Nisi Mors) Going for a ride (Florida, United States), January 2008 (Photo: Anders Gustafson) Logo for NNM (Nemo Nisi Mors)
Revised

Some examples of when it is good to walk that extra mile when programming. Sometimes you will avoid performance problems, sometimes you will minimize the risk of errors, sometimes you will just make the code more understandable for a human being.

Minimizing risks

Looping through the elements in an array can be achieved in many, many ways. Here are four examples with subtle differences. Sorted increasingly by risk of getting "off-by-one"-problems.

for (i = 0; i < arr.length; i++) {
    x = arr[i];
}

for (i = 0; i <= arr.length - 1; i++) {
    x = arr[i];
}

for (i = 1; i <= arr.length; i++) {
    x = arr[i - 1];
}

for (i = 1; i < arr.length + 1; i++) {
    x = arr[i - 1];
}

Note: Since I am a computer scientist, the indices of the arrays are of course zero-based in the examples.

Clarity for humans

Computer vs human

Human-readable code is an art. Compare these two code-blocks:

for(i=0;i<names.length;i++){name=names[i];print("name is "+name);}

and

for (i = 0; i < names.length; i++) {
    name = names[i];
    print("name is " + name);
}

Did you easily see that the blocks are identical?

A computer does not need redundant whitespaces to be able to read code. So extra spaces or newlines will not be helpful for a computer.

But, we as humans are not as good as computers when reading code. Hopefully you are programming and writing code for your colleagues and not mainly for the computer. As a great programmer you know that a large part of a programmer's life consists of making code readable for humans. The easy part is coding for your computer, the hard part is coding for your colleague. Great programmers know that striving for complex one-liners is not a good thing.

Programs must be written for people to read, and only incidentally for machines to execute.

Hal Abelson and Jerry Sussman

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

Martin Fowler

Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.

Martin Golding

Spacing

Using space in your code is the same as when writing ordinary texts. You need whitespaces, paragraphs, sections, chapters, etc, otherwise your readers will go mad. Do you think it would be fun to read a book with no chapters or paragraphs?

Use blank lines to divide your code, in the same way you use paragraphs when writing texts. Using blank lines have never harmed anyone, but not using blank lines surely have.

Indentation

One of the most important parts when programming is to indent your code correctly. Missing this will surely make your readers go mad and stop reading your code.

In some programming languages (eg Python), the logic may be completely changed if you indent incorrectly.

Dividing into lines

When having several attributes or parameters, you often benefit by placing them on separate lines. In this way your readers do not have to scan in two-dimensions.

Compare the following examples

<input type="range" id="volume" name="volume" min="0" max="100" value="30" step="5" />

function sendMail(mailRecipient: string, mailSubject: string, mailBody: string) {}

with the result when using separate lines

<input type="range"
       id="volume"
       name="volume"
       min="0"
       max="100"
       value="30"
       step="5" />

function sendMail(mailRecipient: string,
                  mailSubject: string,
                  mailBody: string) {}
Splitting objects with multiple properties over multiple lines is widely considered a good convention, because it's much easier to read.

Capital letters and punctuations

Use punctuation marks (the use of certain marks to clarify meaning of written material), so your code will be more understandable.

When writing comments, I advise to always write complete sentences, i.e. start with a capital letter and end with a full stop. This will make it easier to see that nothing is missing before the first word or after the last word.

In this first example, it is easy to see that the comment probably contains all the information that the author intended.

// Weight in kg at sea level.

In this second example, it is harder to see if the comment contains all the information that the author intended. You can not be sure that some things aren't missing.

// weight in kg at sea level

In this third example, you get really confused.

// eight in kg

In this last example, you actually are more convinced, still confused though, that this is the comment the author intended.

// Eight in kg.

Many programming languages need your semicolons to be syntactically correct so the code can be understandable for the computer. Why being lazy when writing for humans?

Commit messages

The same is also true for commit messages to version control systems. These texts will be written once, but read many, many times, so you as an author have to make the effort so the texts are clear and concise.

Naming

Yes, you can name all your variables and functions like a, b, c, ..., x, y, z, a1, b1, c1, ..., x1, y1, z1, a2, b2, c2, ..., and that will probably be syntactically correct. But why? You should instead be thankful that smart people have invented explicit naming so you are able to name your variables and functions in a better way.

Let us take a few easy examples:

The modern IDEs (integrated development environments) have no problems in helping you writing longer names.

Often in programming lectures you hear things like: Let us call it val, standing for value, Let us call it ses, standing for session, Let us call it el, standing for element or Let us call it e, standing for event. Why not call the variables value, session, element and event then? That would be much easier and you would not have to explain what your variables stand for all the time. As soon as you have to explain what your variables stand for, you have failed.

Note: An example of bad variable names are cat and cats, representing category and categories. When the lecturer also started to use the variable catLength in his code (representing "length of array containing category names", i.e. "number of categories"), I was lost.

There are tools you can use if you must obfuscate or minimize your code, but please do not be a programmer that writes obfuscated or minimized code directly from your keyboard.

Single character variables

Sometimes it may be okay to use single character variables. Loop variables may be denoted i, j, k. Integer variables may be denoted m, n, especially when accompanied by documented formulas or algorithms. It is the same with floating point variables denoted by x, y, z.

Abbreviations and acronyms

There are not many occasions when using unestablished abbreviations or acronyms are a good choice. Yes, HTML, XML, FTP, HTTP, API and the likes, are probably good choices to use.

But if you have domain-specific things like CarColorFactory and NativeNodeModule, it may not be a good choice to abbreviate these like CCF and NNM everywhere in your code, since people non-fluent in your domain-specific language will have a hard time understanding the code. Remember that most people, including your colleagues, are non-fluent in domain-specific languages in the beginning.

Do not use random characters in your variables either. If you want a variable denoting a number, use number or n, but variants like nbr, num or no are just confusing.

The autocompletion in editors make the cost of writing longer names very low, while the clarity they provide is invaluable. Uncommon abbreviations, in particular, should always be avoided.

Function parameters

Say that you have the following function.

function sendMail(
  mailRecipient, 
  mailSubject, 
  mailBody
) {
  console.log(`${mailRecipient} - ${mailSubject} - ${mailBody}`);
}

sendMail(
  "john.doe@example.com",
  "Planning for coming week",
  "Lorem ipsum"
);

By making a subtle change to the function signature and encapsulating several parameters into an option parameter, you may make the code clearer, less error-prone and easier to follow. Especially for the ones calling your function, since they will not mix the passed arguments up.

function sendMail({
  mailRecipient,
  mailSubject,
  mailBody
}) {
  console.log(`${mailRecipient} - ${mailSubject} - ${mailBody}`);
}

sendMail({
  mailRecipient: "john.doe@example.com",
  mailSubject: "Planning for coming week",
  mailBody: "Lorem ipsum"
});

Working with units

It is important to always specify a unit when needed. When a number denotes the length of a list or similar, you do not need any unit (because there is no unit). But if the number denotes the length of a road, the temperature in a car, the mass of a person, etc, you must define a unit also. Either you have to have an extra variable containing the unit or your variable name must inform about the unit used (eg temperatureInKelvin or massInKilograms). It is not enough to say that the temperature is 15° or that your mass is 80.

The only mitigating circumstances may be if SI-units are used.

Boolean algebra

When using variables that represent boolean values, use show, enable, etc and not hide, disable. Your code will be much easier to understand. It is easier to reason about and get correct boolean logic if variables have names like showAddress, enableDropdown, isActive, success, hasPermission (instead of hideAddress, disableDropdown, isInactive, failure, lacksPermission).

For example, if the HTML attribute disabled instead would have been enabled, I really think that there would be fewer bugs out there.

Parentheses

In boolean (and mathematical) expressions, use explicit parentheses to clarify your intentions. Do not assume that everyone are as good as you in understanding the operator precedences. Also, different programming languages may work differently when it comes to operator precedence.

As soon as you've got two different operators in an expression, it is always a good idea to add parentheses. If all the operators are the same, it may be safe to skip parentheses.

So instead of writing

hasAccess = isSuperUser || isAdmin && hasExtraPrivileges

use either of the following rows to explicitly define your intentions

hasAccess = isSuperUser || (isAdmin && hasExtraPrivileges)
hasAccess = (isSuperUser || isAdmin) && hasExtraPrivileges

The persons reading your code will be thankful and there will also be fewer bugs in your code.

And as you know now, writing the line above as

acc = su || adm && ep

should always be avoided.

Review your code

The most important part is to always review your code before leaving it. Ask yourself, "Does this code make sense to others?", and if the answer is "No", take the time to refactor the code.

First published by Anders Gustafson 2019-07-23
Logo for NNM
NNM Logo
Friends in need
CCF Cheetah Conservation Fund
NNM Clock
Random quote
Astronomy is science, astrology is nonsense.
Anders Gustafson