DEV Community

Cover image for Hard to Read: Coding, with Communication
Cole Turner
Cole Turner

Posted on • Originally published at cole.codes

Hard to Read: Coding, with Communication

Have you ever opened your pull request and then received this comment?

This is hard to read, could you change this?

Why has this happened to everyone?

Source code is just like any other kind of language: it's a construct of symbols and grammar that make up meaning. When people say "that's hard to read," what they mean is one of a few things:

  • It's hard to make sense of the symbols.
  • It's not easy to follow the grammar.
  • This is not something I have seen before.

Source code is a diverse language just like any verbal language. We each have our own code dialect. In JavaScript, we do our best to normalize the inputs through tools like ESLint, Prettier, and TypeScript. They establish a common language of symbols, grammar, and sometimes a dictionary and thesaurus. And we make sense of it all, through the use of symbols and grammar in the code.


Sense of Symbols

There's a great Cingular commercial from 2007, where a mom and her kid are communicating about their texting bill.

Watch Cingular Commercial - 'bff Jill'

If you immediately recognize the symbol idkmybffjill, then you might not find that hard to read. On the other hand, if you've never seen that symbol before or you recognize some of the contents, you will find that symbol hard to read.

Let's look at some code examples.

Hard to Read: Sense of Symbols - Variable Names

// https://davidwalsh.name/javascript-debounce-function
function db(f, w, i) {
    let t;
    return function() {
        let c = this, args = arguments;
        let l = function() {
            t = null;
            if (!i) f.apply(c, args);
        };
        const n = i && !t;
        clearTimeout(t);
        t = setTimeout(l, w);
        if (n) func.apply(c, args);
    };
};

This function is hard to read because all of the meaning has been obfuscated through obtuse variable names. All of the meaning is encoded in the implementation, without any content words. This confusion stems from a lack of recognition.

Did you guess that this function is a throttle? If so, then I'm sorry because I took this opportunity to trick you. This function is actually debounce.
I won't do that again! But I do want to share another example.

Hard to Read: Sense of Symbols - Unfamiliar Syntax

class Houseplant {
  // private fields
  #name = "Untitled";
  #species = "Unknown species";

  constructor(name, species) {
    this.#name = #name;
    this.#species = #species;
  }

  // from upcoming tc39/proposal-record-tuple
  toRecord() {
    return #{
      name: this.name,
      species: this.species
    };
  }
}

In the example above, I am referencing some unusual syntax, from a new class properties functionality called Private Fields. The toRecord function also makes use of a current proposal for Records and Tuples.

Both instances are making use of the # sign to represent different functionality. This is confusing, and potentially hard to read because it lacks familiarity.

Confusion by Sense of Symbols is primarily an issue for folks who are new to the industry or new to the language. Due to a lack of recognition or a lack of familiarity, they might find themselves saying "that's hard to read."


Sense of Grammar

Once a developer has become more familiar with a language, the struggle with code becomes a matter of grammar. It is the same struggle with learning any kind of verbal language, where the words start to make sense and the trouble becomes acclimating to the grammar.

Let's look at an example:

Hard to Read: Sense of Grammar - Overloaded Example

function pickColor() {
  return isTimeOfDay >= evening
    ? theme === 'light'
      ? Theme.colors.light
      : Theme.colors.dark || Theme.colors.default
    : theme === 'dark'
    ? Theme.colors.light
    : Theme.colors.dark || Theme.colors.default;
}

When the time of day evening, when the theme is light, what is the color?

For most people, it will take more than ten seconds to find the answer to that question. Most developers will say this code is hard to read and repeat a tactical answer about nesting ternaries, instead of highlighting the communicative issue at hand.

Confusion by Sense of Grammar is when the structure goes against the expected rules of grammar. What one developer thinks is "hard to read" is another developer's groove.


Who gets to decide?

Some might say Brendan Eich, who in 1995 invented the scripting language Mocha that would later be known as JavaScript. Others might say TC39, the committee that oversees the evolution of the language today. That is a view on linguistics called prescriptivism.

But we know that a language, even for programming, is defined through its usage. Languages we have today evolved because someone made a change. This is a view called descriptivism.

The answer is...

"It's harder to read code than to write it"

—Joel Spolsky, Things You Should Never Do, Part I

If you're soloing it, then what's easy to read is whatever choices make you feel more productive. When you're a part of a team or a community - the code language is the sum of all the inputs, that which makes the group feel more productive and effective.

If it cannot be enforced with tooling or documentation, then it's a matter of preference. That is where tools like ESLint, Prettier, and Typescript excel at what they do: enforcing consistency. They keep developers in their lanes. The code language then becomes "what made sense when we configured our tooling." Preferences aren't usually helpful to leave as a comment to someone else's work unless it can be expressed in terms of semantic and cognitive weights for our uses of symbols and grammar.

Most developers only talk about familiarity. What matters is how much effort is spent mentally following the code. For example, abstractions (moving the symbols away) can lead to disproportionate indirection (distributing the grammar), making it harder to follow the code. Symbols can be used in place of grammar. All of this adds up to code language fluency. This kind of feedback is something we need to grow away from, and trust in tooling and documentation.

We should be vulnerable and empathetic instead. It's on us to try to understand and trust the coder who already did the work. As reviewers, we can describe the impact it has on the semantic and cognitive weights. Saying "that's hard to read" is no different than telling someone their verbal language is difficult to understand. When working with others, we have to understand that the common language is the lowest common denominator among the group, not the average familiarity.

Codebase language is an evolving negotiation. Sometimes boilerplate is boilerplate. Other times it's keeping the semantic and cognitive weights balanced. It's important to understand that our familiarity with syntax, symbols, and grammar — isn't dictated by who wrote the code first. It is through the continued and evolving use amongst all using that codebase language.

Photo by Agence Olloweb.

Top comments (0)