Section 6.2 The rename refactoring
By far the most common and easier to explain refactoring is the "rename" refactoring:
The rename refactoring entails the consistent change of the name of a variable, class or function in every place where it is being used.
The reasons for applying the rename refactoring are a number of code smells related to the names of program elements, be they variables or functions. It’s not easy to choose a good name for something the first time through, it’s often something that you iterate a couple of times.
The code smell most worth mentioning is that of an explanatory comment needed. A line like
int a; // the age
should probably be replaced by simply int age;
.If a comment is needed to tell you what the variable is doing, change the variable’s name. Then remove the comment.
Subsection 6.2.1 Rules for naming
Let’s discuss some naming rules. These are more guidelines than laws, but I would suggest having a good reason before breaking them. First, we start with the rules for the Java language.
- Variables (fields, parameters etc) are always lowercased, and we typically use the "camelCase" approach of joining words together, starting each new word after the first with a capital letter.
- There is one exception to the above rule: Named constants are typically written in all capitals separated by underscores "SUCH_AS_THIS"
- Class names must start with a capital letter, and follow what is often called "PascalCase", i.e. words joined together like in camelCase, but with first word also capitalized
Next, we have rules that are related to choosing good names.
- Names should accurately describe the thing: Don’t misinform! Say what you mean, and mean what you say.
- Variables with small scope (e.g. local variables in a 3-4 line function) should have short names, while variables with longer scope (e.g. fields) should have longer names. If I cannot immediately look at the definition of a variable within the current code block, then its name better tell me all I need to know.
- On the other hand, functions/methods with small scope (e.g. private methods) should have longer names that describe what they do, while those with largest scope (e.g. public methods) should have shorter names.
- Parameters to functions, especially public functions and constructors, are a bit of a special case. Yes they have typically small scope, which would suggest using short names for them. On the other hand, most IDEs offer you completion hints when typing a function call, based on the parameter names, and at that point it is convenient to have a more reasonable name than a single letter.
item
is more understandable thani
orit
, andsymbol
is more understandable thans
. ButvalueToBeRoundedDown
is probably just a tad over the top. - Avoid needless abbreviations and type specifications in the name. For example an array containing nodes should be called just
nodes
, notnds
and notnodesArray
. - variable and class names should be nouns. The exception is variables that are booleans, which should be predicates like
isSaved
. - method names should typically start with the imperative form of a verb, indicating the action performed by the object when that method is called. For example
printToResults
orcreateGradeSummary
. The exception is methods that return booleans, which should be predicates likecontains(element)
,isEmpty()
,hasChildren()
,equals(other)
etc. - Most importantly, as a general rule that applies across the board: Follow whatever standard the project and the team use: If your style choice differs from those of the team or the project, then your choice is wrong, however much you may think it is right.
So let’s take a look at a renaming effort.
Subsection 6.2.2 Mechanics of renaming refactoring
To perform a renaming refactoring, if your IDE doesn’t provide it already, you need to do the following steps:
- Find the place where the variable or function is defined, and change to the new name.
- If you are renaming a method, find out if the method is declared/defined in a superclass, and make sure to also change that name.
- If you are in a language with static typing support, you can probably let the compiler guide you to all the old versions of the name, and change the all to the new version. Otherwise you need to do that yourself.
- If it is a local variable or parameter, your search can be restricted to the method in which those are defined. If it was a field, and it was not private, you must find usages of that field elsewhere in your code base and change those.
- If the field has getter and setter methods named after it, you will likely want to rename those methods as well, following the same steps for usages of those methods. And by this point you would wish your IDE had automatic refactoring for renaming and/or your language had static typing.
As a simple example, consider the code:
public int doTheThing(List<Integer> ns) {
int t = 0;
for (int i = 0; i < ns.size(); i++) {
t += ns.get(i);
}
return t;
}
Looking at this function for a second, it appears to take as input a list of numbers, then adds them up in a for loop, and returns the result. In order to improve on this code, we’ll first replace for loop with foreach loop, another refactoring that you can perform on for loops that loop over a collection and don’t really need the index, only the items. The steps of this refactoring would be:
- Replace the
int i = 0; ...
part in the loop withInteger n : ns
, which is the foreach syntax for traversing the items of a list. - Find places in the code where you were accessing the element at index
i
, and instead usen
.
In our example, this would change the lines 3-5, so the new code would say:
public int doTheThing(List<Integer> ns) {
int t = 0;
for (Integer n : ns) {
t += n;
}
return t;
}
Now that that is out of the way, let’s consider other changes. First of all, that’s a terrible function name. We might change it to something like
computeSum
or computeTotal
, and also search for all places where the function is being used and change those.Next, the parameter
ns
. It is "declared" in line 1, and then used in line 3. We will change it to numbers
in line 1 first, then in line 3.We should also use a better variable name than
t
. It has a short scope, so a short name is not bad in general, but total
or sum
would be also quite short and better explain what the variable does. We would need to make that change in three places: First in line 2 where the variable is declared, then in the two usages of the variable in lines 4 and 6.This is what the function would look like now:
public int computeSum(List<Integer> numbers) {
int sum = 0;
for (Integer n : numbers) {
sum += n;
}
return sum;
}
I will let you decide whether we should rename
n
to number
. I’m inclined not to. There’s only one usage of it, and it’s pretty clear.