Towards fluency in JavaScript and other programming languages

JavaScript

The English language is endlessly amusing. For example, if the opposite of interior is exterior it surely follows that the opposite of increment must be excrement ... right?

Wrong!

For this and many other reasons I have been fascinated by language for as long as I can remember. At school in year 7 we were taught one lesson a week of Linguistics, which is essentially the study of language. In the end of year exam I scored 98%. It's fair to say, I have always been a linguistic nerd and I went on to study French and German at A-Level. So I know a little about learning languages.

Imagine a native English speaker learning German. In the early stages of the learning process, it's natural to think of a phrase in English and, in ones mind, systematically translate that phrase word-for-word into German.

That process...

  • think in English
  • translate the words to German
  • output the German phrase

...is inefficient and becomes a barrier to fluency. The only way to become fluent in a language is to think in that language. Then you can skip the first two steps in the clunky process above and jump straight to output the German phrase.

Fluency to that extent really only comes after interacting with a language day after day for an extended period.

The other day an email arrived from a mailing list that I subscribed to a few years ago. The email was part of a series aimed at junior software engineers preparing for technical interviews. It included an example of the kind of coding exercise that a junior engineer might face. In this case: write a function that takes a string as a parameter and determines whether that string is a pallindrome.

A pallindrome is a word, phrase or expression that reads the same backwards as it does forwards. So, if we assume the function is called isPallindrome():

isPallindrome('level'); // should return true isPallindrome('lever'); // should return false

The example solution in the email looked like this:

function isPallindrome(str) { let reversedString = ''; for (let i = str.length - 1; i >= 0; i--) { reversedString += str[i]; } if (reversedString === str) { return true; } else { return false; } }

This made me think about my own evolution as a programmer and the parallels that exist between the twin processes of learning a computer language (JavaScript in this example) and learning a spoken language.

The example solution shown here looks like something I might have written in the early days of my programming journey - the email that contained it was, after all, part of a series of emails aimed at junior software engineers. You can quite clearly discern three steps that line up quite accurately with the three steps in the translation process for a novice German speaker outlined above:

  • think through the logic
  • translate that flow of logic to steps in a program
  • write those steps in your chosen language

That step-by-step logic is most evident in the conditional statement that determines the returned value. The flow of logic runs something like this:

  • compare the two strings
  • if they are the same, the input must be a pallindrome, so we should return true
  • otherwise, the input is not a pallindrome, so we should return false

Translating that step-by-step into JavaScript yields this conditional statement:

if (a === b) { return true; } else { return false; }

Going back to the German language example above, I suggested that, in order to become fluent in German, it's necessary to be able to think in German. What that really means is you need to process language the way that a native German speaker processes language.

The same applies when writing a computer language. To become fluent we have to learn to process the language within the context of its built-in rules & structures.

Let's examine one of the most fundamental structures of any programming language: the comparison operator. There is one included in the conditional statement above.

The triple equals is a comparison operator and a === b is a comparison operation. It is asking JavaScript to:

  • compare the expression on the left of the comparison operator
  • with the expression on the right of the comparison operator
  • and let us know if they are the same

A comparison operation evaluates to either true or false, as this Node REPL output demonstrates:

comparison operator output

As an aside, there is a subtle difference in JavaScript between the double & triple equals comparison operators. That's not relevant to this post but you can read more about it in MDN Web Docs

Look again at what the comparison operator is asking JavaScript to do. And compare that to the step-by-step logic that was translated into the conditional statement. You will notice that they do the same thing. In that case, one of them must be redundant in the conditional statement set out above.

This tells us that we don't need to construct a conditional statement that returns a boolean because the comparison operation, that is a part of every conditional statement, already evaluates to a boolean.

So we can replace...

if (a === b) { return true; } else { return false; }

with...

return a === b;

'Word-for-word' translation might well get the job done. But the better understanding of the fundamental structures of a language that comes with experience and practice (otherwise known as fluency) enables us to produce more efficient, concise code.

The way that reversedString is determined in the example solution could be refactored a little too but I will leave you to ponder that one yourself.