Last week we looked at a number of simple rules of thumb for naming identifiers. This week we’ll look at a few other rules, especially those dealing with Hungarian notation, abbreviations and units.
Hungarian Notation
Many years ago, it was considered best practice to use “Hungarian notation” when naming variables. We prefixed every variable name with one or more alphabetic characters specifying the data type that the variable contained. This resulted in variable names like the following:
boolean bIsValid;
char chKey;
int iSpeed;
float fpPrice;
String strName;
The names got even worse in C/C++ when we brought in pointers, arrays and signed versus unsigned numbers!
This was a good idea when we were working with low-level languages. It was important to be aware of the exact type implementations we were using in order to avoid compile and runtime errors.
Doing clean object-oriented design removes the need for Hungarian notation. Better compilers and runtime type checking by the Java VM catch the vast number of the errors that Hungarian notation was supposed to solve.
That’s why Hungarian Notation has almost entirely disappeared from modern OO development. Our code should not need to know the implementation details of the types used. This causes unnecessary coupling between the names and the types. It also wastes time in refactoring code if we ever need to change the type at a later stage.
Imagine that we created a boolean variable representing a gender and called it bGender
. Later we decide to change the type to an int
or a String
and even better a class called Gender
. Not only would we have to change the type wherever a gender was used, we’d also have to change all the identifier names to reflect the new type.
Avoid Abbreviations If Possible
I read about a programmer who was maintaining some old code and noticed there was a variable with a very odd name of “feet”. When investigating it further, the programmer found out that the original name was “legacyHandles”. Someone had abbreviated it to “legHands” which then eventually ended up as “feet”.
Similarly, if there was a class called Class173Z
in some code, you would have no clue what the class would be used for.
Use Units In Identifier Names
It’s considered good practice to use units in identifiers if those identifiers refer to something that has a unit in real life.
Let’s say we have a sleep()
method that takes a length of time to sleep, as follows:
void sleep(long length) { /* code */ }
We should probably change the parameter name to make it obvious what unit the length of time refers to, say
void sleep(long lengthSeconds) { /* code */ }
It’s even better to create a type to model these units. Java has the java.util.concurrent.TimeUnit
enum that represents time units. The enum also contains utility methods to convert between time units, and to do timing and delay functions in those units.
public enum TimeUnit {
NANOSECONDS,
MICROSECONDS,
MILLISECONDS,
SECONDS,
MINUTES,
HOURS,
DAYS;
// lots and lots of omitted code
}
We could refactor our previous sleep()
method to take an extra parameter of type TimeUnit
as follows:
void sleep(long length, TimeUnit unit) { /* code */ }
This example has used units of time, but just as obviously we need to appropriately name parameters of distance, mass, speed, voltage, current, etc.
Conclusion
Next week we’ll look at the remaining rules, especially those dealing with classes and interfaces, and types in names.
Do you use Hungarian notation? And abbreviations? (Please say no!) Have you used the TimeUnit
enum? Would you like to read a blog post about it? Please share your comments.