loading...
Cover image for Long names are a code smell

Long names are a code smell

karolmajewski profile image Karol Majewski ・2 min read

How do you feel when you read this?

function getPropertyFromDictionaryOptionCurried<T extends object, K extends keyof T>(object: T): Option<T[K]>

If you believe everything is okay, then this article is not for you.

Feeling irritated? Tread on.

The problem

Long names such as getPropertyFromDictionaryOptionCurried are not bad because they make use of full words. They are bad because they reveal too much.

You may feel tempted to make a busy name compact by replacing words with single letters. However, if single letters read more naturally than full words, then this would be an improvement:

getPropertyFromDictionaryOptionC

Still looks scary. Let’s shorten it some more.

getPropertyFromDictOC

Instead of neutralizing the problem, we have created another one. We have shortened the name, but we have also obscured what the function is doing.

The solution

Let's start from the beginning.

getPropertyFromDictionaryOptionCurried

We already know that this function accepts a Dictionary. The type signature indicates it. There is no need to repeat ourselves.

getPropertyOptionCurried

The same goes for the Option it returns. That's what types are for.

We arrive at:

getPropertyCurried

Using curried as the suffix suggests that currying is something extraordinary.

Suffixes are often used to indicate that something unusual is taking place. For example, a synchronous function in an asynchronous-first environment might be suffixed with the word sync.

However, currying is hardly unusual in the JavaScript world.

Instead, let's ask a question: what is this function in its nature?

This function reads from an object. That's all it does. Let's find a more suitable name.

getProperty

The fact you can call this function in more than one way is a detail, not the dominant characteristic. We can communicate it by adding an overload.

A working example:

function getProperty<T extends object>(obj: T): <K extends keyof T>(key: K) => Option<T[K]>;
function getProperty<T extends object, K extends keyof T>(key: K, obj: T): Option<T[K]>;
function getProperty<T extends object, K extends keyof T>(obj: any, key?: any): any {
    switch (key) {
        case undefined:
          return (key: K) => Option.fromNullable(obj[key]);
        default:
          return Option.fromNullable(obj[key])
    }
}

Takeaways

  1. “If you don't want people to use something, give it a longer name” — Dan Abramov
  2. Using single letters instead of full words hardly ever makes things better. (Exception: type parameters)
  3. If your function is general-purpose, yet its name sounds specialized, then a simple name combined with overloads is likely a better choice.

Bonus 1

The simple, the punchy, the easily remembered will be more effective in the long run than some long name that says it all, but in a such a way that no one wants to say it at all.

— Kevlin Henney in Giving code a good name

Bonus 2

The Inverse Scope Law of Function Names

Bonus 3

Posted on by:

karolmajewski profile

Karol Majewski

@karolmajewski

Product engineer working with React, TypeScript, Node.js, and AWS. Running @WrocTypeScript.

Discussion

pic
Editor guide
 

Naming things takes the most effort actually. I think ultimately, readability is not being fully verbose, and definitely not being terse. Like you pointed out, it’s about being concise, and leveraging sensible mechanisms like overloading. Thanks!