Clean Coders

Table of Contents

The only way to stay fast, in the short term OR the long term, is to keep your code clean – Uncle Bob Martin

Episode 2: Names

Intent

The name of a thing (variable/function etc) should reveal its intent. If a comment is required to reveal the intent, you need to choose a better name.

Code should strive to be self documenting. For example, instead of

// You could do this
const d; // elapsed time in days

// But why not just have the name of your variable reveal its intent
const elapsedTimeInDays;

While this may end up being a bit more to write, you'll thank yourself as your code becomes easier to reason about, especially as you're jumping between files.

Put simply, a name should say what it means, and mean what it says. If the meaning has changed, the name should be changed to reflect the new intent of the code.

Prefixes

It used to be popular to have prefixes that indicate types such as IAccount or m_Product and there were often good uses for them. Nowadays, modern IDEs can infer types automatically making their usage for the human coder somewhat redundant. It's more down to personal taste.

Parts of Speech

Classes and variables are nouns while methods are verbs.

You should try to avoid "flavour" terms like Manager, Processor, Data or Info as they are vague and generic.

# Booleans should be predicates
if isLoading:
    print("I am loading")

if not isEmpty:
    print("I'm not empty!")

"""
Regular methods should be verbs.
Methods that returna boolean should be a predicate
as they will likely be used within an if statement.
"""
if payment.isPostable():
    postPayment(payment)
    price = getPrice()

The overall idea is to format code as if it were part of the English language and we can achieve this by using an appropriate mix of nouns, verbs and predicates.

Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer’s intent but rather is full of crisp abstractions and straightforward lines of control.

Grady Booch, author of Object Oriented Analysis and Design with Applications Scopes

The above is all good and well but it should be applied in moderation. It wouldn't make sense to call a function tryOpenFileAndIfErrorThrowException when it's going to be used often. Just calling it open is sufficient. Inside such a function, you might find longer, more descriptive names however.

function open(filename) {
    try {
        return getPropertiesOfFile(filename)
    catch(error) {
        logFailureToOpenFile(filename)
        throw error
    }
}

The actual purpose of the function isn't important, the level of usage is what matters here. For something used often, it's good to keep a name short and concise. Internally, the getPropertiesOfFile function is likely to be used rarely, if not only once. We can then give it a much longer, descriptive name since it won't be exposed outside of the open function.

The same principle applies to the distance, or scope, of a function. Let's take a typed example to make things more clear

#+begin_src js const e = document.querySelector('body')

// 20 lines later

function appendName(n: string) { e.append(n) }

You'll have to use your imagination here but if you were in a 50 line file, seeing e with no context would be mighty frustrating. You'd need to look up, and possibly even scroll up, to find where e is defined, perhaps even among a number of other declarations.

Given the distance between the initial assignment of e, and its uses, we should give it a much more descriptive name like element.

Inversely, the appendName function only receives a single argument called n. At first, you might be tempted to upgrade it to name or firstName but there's no particular need. The reader can see a clear relationship between where it is created and used as the distance is only one line.

You can consider there to be a relationship between the creation of a variable and the distance it covers. If it's used across a number of lines throughout a file, the name should be longer and more descriptive. If it's usage sits right next to its initialization, having shorter code is more beneficial than long, verbose names.

Consider this to be the X axis of our relationship model which depicts a variable and how far away its uses are. The Y axis is what we discussed earlier, the level of usage that a method gets which should inform how long or short its name should be.

The larger the scope, the shorter the name. The shorter the scope, the longer the name.

Ottinger's Rules for Variable and Class Naming

Episode 3: Functions