How to Make Renames Easy
- 4 minutes read - 690 wordsNames in software are hard. But what’s worse than a bad name? Sticking with it because you can’t change it. I want us all to be able to effortlessly and fearlessly fix bad names, and that’s the topic of this post.
What’s a bad name? Here’s a contrived example, a function called longName
:
function longName() {
if(useLongName) {
return `${this.firstName} ${this.lastName}`
} else {
return this.firstName[0]
}
}
A few issues I can raise with this name:
longName
is often not a correct description of what this function does. If configuration tells ususeLongName
is false, then we don’t return a long name, we return a short name (one letter).- What does ’long’ mean? “Li Po” is not a ’long’ name according to me, but that’s somebody’s full name. Couldn’t this be named ‘full name’?
I’m not sure what the best name might be because we don’t have much context. But longName
isn’t it.
Here’s why I think talking about this is worth our time, from ‘Pick a Good Name’:
“Bad names make it difficult to search through the code. They make it difficult to talk about the code, because the name confers inaccurate meaning, or no meaning. They make it difficult to refactor or change behavior, because the name becomes a handle. Like a handle on a basket, when you’ve mentally reached for it enough times in a certain way, you become trained to do that forever.”
So, what’s the solution? As Sandi Metz said: “You’ll never know less than you know right now.” Sometimes we don’t pick the perfect name the first time. And so we must be able to rename, effortlessly and fearlessly.
Every text editor needs a great search and replacement feature. We should be able to change every instance of a name in a file without much effort. When it’s hard or risky, people won’t do it.
In my Vim configuration, I have a mapping courtesy of my Hashrocket colleague Vidal. It takes the word under a cursor in visual mode and puts it into command mode in a replacement command.
vnoremap <c-r> "hy:%s/<c-r>h//gc<left><left><left>
So, if I have the word “longName” under my visual cursor and execute ctrl-r
,
I’ll enter command mode with my cursor on the replacement portion of the
command:
:%s/longName//gc
With this mapping, I almost effortlessly change names all the time. Goodbye, longName
.
Changing names across files is harder in Vim than in other editors. That’s why I try to do it as soon as I think I should, when the pain is small. Figure out how to do it in your editor, and do it.
Changing file names should be similarly easy. I use vim-eunuch to
apply the :Rename
command from Vim. This is one situation where good tests or
types are irreplaceable. If you change a filename that’s referenced by any of
your other files, your tooling should be screaming.
I lean more into names than many developers. A while ago, I decided that I wanted to use named JavaScript exports rather than default exports. So I started to change these:
// Example.js
export default Example = () => <div />
// other file
import Whatever from 'Example'
To this:
// Example.js
export const Example = () => <div />
// other file
import { Example } from 'Example'
I prefer this style because it:
- Makes searching and refactoring easier
- Makes it clearly what’s exported from a file (anything, rather than everything)
- Encourages me to choose good component names
- Allows me to jump to the component definition via Ctags
Is there a time when you can’t rename? Rarely. In highly coupled designs like microservices, renames can be painful. But I’ve noticed that often the folks opposing a rename aren’t in these unique cases. They’re afraid of breaking something or appearing to nitpick their or other developer’s previous decisions.
The more time bad names are allowed to remain, the more damage they do. Whenever you parse a bad name and figure out what it’s really doing, you’ve done hard work that you should pass on to future developers. Make renames one of the easy things, and you’ll be a programming hero.