Write Code In English Part I
15 April 2021
Most written communication is in natural language, so why wouldn’t we want to try to mirror that in our code?
This series will present small concrete examples that might help your code read less like code, today's topic is...
For Loop Identifiers
Selecting good identifier names is ubiquitously included in style guides. Here’s a few examples:
- Avoid single letter names. Be descriptive with your naming. Airbnb
- Give as descriptive a name as possible, within reason. Do not worry about saving horizontal space as it is far more important to make your code immediately understandable by a new reader - Google
- DO favor readability over brevity. - Microsoft
The aforementioned maxims are often disregarded when new variables are declared as part of a for loop. It is all too easy to pick i as a loop indexer without much thought, though there are many examples where giving any loops identifiers meaningful names (as we would for any other variable) can make the code read more like natural language.
Here’s a simple code example, listing all the factors of a given number.
We might describe the process in natural language as "Step through all of the possible factors below the number to factorise, saving any possible factor that we've determined IS a factor". There's already a disconnect between the natural language description and the code - there's no reference to the 'possible factors'- they are masquerading inside i.
As soon as one extra layer of complexity is added into the mix (multiple numbers to factorise), the code becomes harder to read:
There's a bug! Did you spot it? allFactors should contain factors, not the numbers to factorise. If we rewrite the above example with less vague identifiers the code becomes easier to read and bugs become clearer to see (keeping the bug in) :
We want allFactors to contain factors, so why the heck would we add the numbers that we’re factorising? The correction is to push the possible factors: allFactors.push(possibleFactor).
The identifiers number and i contain next to no contextual information about what they hold, in isolation they are just some number. When we rename to numberToFactorise and possibleFactor their meanings become clearer and the bug becomes more apparent.
The same principles can be applied when using higher order functions like JavaScript’s foreach, C#’s LINQ expressions - parameters to lambda/arrow functions deserve good names too!
Even for loop identifiers which are such a part of our code can have a big, important job - so why not give them a big, important name to match?