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
- “If you don't want people to use something, give it a longer name” — Dan Abramov
- Using single letters instead of full words hardly ever makes things better. (Exception: type parameters)
- 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
Top comments (1)
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!