console.blog( ,

Invisibilia: The Code Within

What's Important To You?

Think of your favorite programming language, or even just the last piece of code that you wrote. Was it Java? PHP? Python? Ruby? It doesn't really matter; imagine someone took a part of that code away or — in the case of an entire language — took away one part of the language. What would you miss the most?

For many, it would be the . (that's a period). Or maybe you're big into JavaScript and function would be pretty devastating. Almost anyone would agree that {} or () would be close to impossible to work without. Think about it for a minute.

While you think about that, here's another question: what are your code standards? If you work for a company, your department may have a set of universal code standards. Your standards could be something passed by word of mouth. You may not have official style standards at all. If you work freelance, or on contracts, or even if you're just the only developer at your company, you might define your own standards. Maybe you base them on what others say about the topic, or maybe they're just based on time spent figuring out what feels right or wrong.

You might put curly braces on their own line. When you make function calls, perhaps your parameter list starts with a space, or the space may be placed before the parenthesis. These are questions of code style, but the word style guides most people down the wrong path. Often discussions of which way to format code devolve into "Well, I prefer it this way" but rarely include any robust reasoning. Fortunately, discussions about code style are not just exercises in opinion, they're discussions about the underlying beliefs that we hold regarding source code, and it's important to talk about it.

At this point I may have stirred some skepticism. Perhaps you're wondering how the preceding four paragraphs have any cohesive idea behind them. Or maybe you disagree with my premise that code style is about our beliefs in code. That's alright, people disagree with me all the time.

The question, of course, is How does all of this tie together? Before we get into the heart of the matter, let's revisit question one: "What would you miss the most?" If you're sitting in front of one, look at your keyboard. If you aren't, imagine the keyboard you use the most often. What's there? Is there a clue about what you might miss the most if it were taken away?

Hello Darkness, My Old Friend

"The human eye is an organ that reacts to light". This is what my editor looks like. To avoid eye strain, I prefer a dark background with light characters on top. This lets my eye react to light only when it's important. Since my biology is tuned to light sources, I use that to my advantage and make the sources of light have meaning. When my eye notices a bright spot, that bright spot always carries syntactical purpose. The opposite case - where dark blobs on a completely lighted background carry meaning - forces the eye (which we've already established reacts to light, not dark) to search for the absence of the photons that would normally trigger biological responses. This goes against everything the human eye is made to do.

There's another benefit to playing to my biology: it's easier for me to see where the light ends and the darkness begins, and where the inverse occurs. Again, this goes back to the same point: my eye (and yours too, unless you're — like — an owl or something) are best suited to seeing light, and when the light stops, we see that more easily.

"So what? It's easier for my eye to pick up dark characters on a light background." Let's assume just for this moment that this statement is true (even though biology tells us it is not), the bottom line is that the places where there are no characters are just as important as the places where there are. If we accept the premise that blank places between characters are important, then we're in a good place. If you accept that it's easier for the human eye to see those spaces when they aren't photon-laden, we're in an even better place, but it's not a required premise.

Don't think whitespace is important? Think maybe it is, but you don't know why...

Whitespace Is The Invisible Code Inside Your Code

Let's revisit the first question one more time: "What would you miss the most?" I hope by now you're on the same page as me; it's likely that the most crucial character in your code is one you never even see — the space. I imagine a newline character is a close second, although most code will function without line breaks if it's constructed carefully.

So now let's look back at the second question: "What are your code standards?" Perhaps it's a little clearer now how the first paragraphs of this post go together: Code standards are almost always concerned with where and how much whitespace is placed.

Often, these standards are discussed at length in meetings with a few developers, and then they are written down and codified and distributed and they cause distress among developers who disagree but whether or not a developer agrees they're put into an IDE and forgotten about, never to be checked again.

Or they're ignored completely.

There are typically two reasons that code standards (or whitespace rules) are ignored or rarely thought about:

  1. "Standards are irrelevant to my actual work."
  2. "I disagree with these standards, and don't feel ownership of them. I will implement them in an automated way to satisfy my company and ignore them otherwise."

The second reason is a communication and respect problem that's massively outside the scope of this post, but it can be addressed. In fact, one of the ways to address a problem with developers feeling a lack of ownership is to agree on a baseline of purpose. Purposeless direction is one of the best ways to create an environment where developers feel a lack of ownership. It's very likely that by addressing point #1 above, you can create an environment where standards are as much a part of code as the non-whitespace is. Read on for how to subvert the idea in point #1 above. Remember, this is about subverting your closely-held beliefs about what code is, not subverting others'.

Whitespace Rules Reflect What We Believe About Code

Before we talk about what code is, we have to talk about what code is: the boring, dry syntax. As you read through the next five code examples and their accompanying text, you may have some sort of visceral reaction. This is good. It means you have an opinion about the details, which, to me, is one of the marks of a good programmer.*

var getThing = function (foo, bar)
{
    return foo + bar;
}

The code above probably feels very comfortable to many people. It also represents a fundamental misinterpretation of the language.^

Take a look at this example:

var thing = getThing (foo, bar);

This looks wrong to most people. That's because it is. Oddly, the syntax hasn't changed at all, but detail-oriented developers will usually balk to some degree at this latter syntax.

To understand why this is, we need to break this code into parts. I'll do it inline for reference, on the function definition first. You'll see that I've removed all whitespace. This isn't a mistake — it's so that we can talk about the language without style preferences intruding; nobody I know of likes their code without whitespace, so this will make nobody happy.

var getThing=function(foo,bar){return foo+bar;};
//           ^        ^        ^
//           |        |        |--function body statements
//           |        |
//           |        |--parameter list
//           |
//           |--function declaration

Note that — without any ambiguity — the parameter list ends at the second r, which returns the "syntactical context" to the function declaration for the characters ){. Similarly, the function body statements end at the first ; which returns syntactical context to the function declaration to finish out the line.

It's simple to verify the breakdown above, because the parameter list in a function declaration is optional, as are function body statements. Therefore, we can write the minimum possible functional declaration as such:

var getThing=function(){};

The only interesting thing we have here is a function declaration.

So now let's look at the second code example — the invocation.

var thing=getThing("this","that");

We can refer to the same breakdown as above, but we're missing the function body declaration in it's entirety — we don't include a body when we're invoking. The bottom line in this situation is that the parts of the line are the same, we just have fewer. There's no new names with what we're doing, we still write the function invocation (which directly replaces the function declaration) and the parameter list.

At this point, I suspect that there is not any contention about these facts. They are easy to verify, and they make sense conceptually.

Now that we've established which parts of the language we're dealing with, let's use the very first code example in this section and write out the parts of the code. But wait, we've also established that whitespace is good for the eye: it indicates where light stops and dark begins. This is a clue in our code of where things start and stop. So in this next exercise, we will mark every part of the code, and we will also mark what part of the code lies immediately after the whitespace.

var getThing = function (foo, bar)
//             ^        ^^       ^--function declaration
//             |        ||--parameter list
//             |        |--function declaration
//             |--function declaration
  {
//^--function declaration
    return foo + bar;
//  ^--function body statements
  }
//^--function declaration

Note above that I decided against marking what follows the whitespace in the parameter list. I can't think of anyone who sees a comma-separated list and wishes that there was no space following the commas. That doesn't — by any stretch of the imagination — mean that those people don't exist. However, it is likely that most people expect ,  when they encounter a list of any kind.

In this breakdown, we see five occurrences of the string function declaration. This should seem wrong. That's because it is. We have function declaration. We break function declaration up by inserting two items inside of it: parameter list and function body statements. Logically, we should see only three instances of function declaration, but instead we see five. This is exclusively due to the placement of whitespace in this example.

If we place the whitespace in a way that coincides with what parts of the language we are writing, we get the expected three.

var getThing = function( foo, bar ){
//             ^         ^        ^--function declaration
//             |         |--parameter list
//             |--function declaration
    return foo + bar;
//  ^--function body statements
  }
//^--function declaration

The response I usually hear at this point is one of either: "I don't care" or "It doesn't matter" which are variations on the same theme of "This is irrelevant to my actual work."

Whitespace Helps You Achieve Your Goals

  • "I want to spend more time reading code."
  • "I don't want it to be clear what my code is doing."
  • "I'm more efficient when I have to mentally deconstruct the file I'm looking at."

Seen above: things no programmer ever says.

Treat your code like poetry and take it to the edge of the bare minimum. Ilya Dorman

In the most basic sense, developers are language parsers. We're smart language parsers, though, in that we can inject new code whenever we want to. On the other hand, we're extremely inefficient language parsers: we're terrible at reading source code, because we have to do it visually. One thing that people see when they look at text is rivers. In typography, you try your very hardest to avoid rivers. They lead the eye to unintended places, and they distract from the actual content. In programming, it helps to have the eye guided to certain places. A river guiding you to ( or { isn't helpful. A river guiding you to foo or return is incredibly valuable.

As we develop, our goals are usually two-fold:

  1. Write functional software
  2. Write efficient software

We apply this to ourselves: most developers thrive where they are effective (functional) and efficient. We've already established that the eye works best by seeing light, not dark. We've established — if not incontrovertibly, at least arguably — that whitespace demarcates syntactical context shifts. We've established that developers are parsing code for efficiency and understanding, and that a visual clue like proper whitespace placement is helpful to guide the human eye.

In my mind, there's only one outcome: a developer accepts that writing code that guides the eye to important parts of code is crucial to improving maintainability, readability, and reducing bugs; or they accept that their habits are more important than those aspects of their software.

I don't think there's a real choice.

A Closing Note

I firmly believe that with a complete explanation, most developers find that following good whitespace rules like those outlined above (and I mean exactly like those above) leads to more easily understood code and — fundamentally — to writing better code.

That understanding de facto requires a complete understanding of the reasoning behind these whitespace rules. That said, it can sometimes be helpful to enforce the rules to promote discussion of why. Enforcement without discussion is worthless and fosters the lack of developer ownership I mentioned earlier.

Following good whitespace rules like those outlined above leads to more easily understood code and — fundamentally — to writing better code.

I offer here a small eslint file that enforces most of these rules. If you promise to discuss these rules and the why behind them with your peers, you can download it.

Carefully note: whitespace doesn't just demarcate syntactical context switches. It also demarcates logical context switches. As such, the rule this file is missing (and I can't polyfill without writing an eslint plugin) is enforcing a line break before the return statement newline-before-return has been added!. This is a massive contextual switch from function statements to a flow control handoff. Encourage structured whitespace at these kinds of logical breaks, too.

Updates

2016-03-21: This post was updated to point to a new, externally-updated location for the hosted .eslint file.

2016-04-24: This post was updated to indicate that the newline-before-return rule had been added.

2018-08-11: This post was updated to point to a new location for the eslint file. It also switched the dates in the Updates section from dd-mm-yyyy to yyyy-mm-dd.

* — Or at the very least a passionate programmer, who is almost always "good" in some sense of the word
^ — It's JavaScript, but it doesn't matter — the statement applies regardless