This post is part of the “Legacy Code to Testable Code” series. In the series we’ll talk about making refactoring steps before writing tests for legacy code, and how they make our life easier. Other posts include:
The Legacy Code To Testable Code Series
|General patterns||Accessibility||Dealing with dependencies||Advanced patterns|
|Introduction||Add setters||Extract method||Static constructors (initializers)|
|Renaming||More accessors||Extract class||More static constructors|
|Add overload||Introduce parameter||Instance constructors|
|Testable object||Conditionals to guard blocks|
Renaming is easy and is usually safe. Most IDEs have the functionality, and most languages (I’m not talking about you, C++) lend themselves to safe renaming.
Why start at renaming? It helps make the code more understandable. When we can understand the code better, the tests we write will be more effective. In other words: don’t write tests for code you don’t understand.
Renaming is an easy win on the way there.
Naming things is maybe the hardest thing in programming. Lots of code grows complex because we slap “Manager” as a class suffix. It’s like giving ourselves permission to make room for code we don’t know where to put. It doesn’t end with one class, though. Once there’s an
AccountManager class, soon
CustomerManager will appear. The same goes for a
getValidCustomer method that should really be a void method, but instead returning a success code. When we’re sloppy, we allow for generalized, confusing names to flourish in the code. When names are vague, all kinds of implementation pours in.
It doesn’t matter if I wrote the code, or somebody who doesn’t work here anymore did. Legacy code can always do with improvement.
One of our main goals in writing tests is to improve code. But improving code safely without effort is a bonus. Risk is key here. If the IDE can do the renaming safely, we are more likely to do it. If, on the other hand, we need to rely on manual changes, chances are we won’t.
Mostly, when we’re doing pre-test renaming, we’ll concentrate more on method names, and maybe variables in the code. These are usually small enough for picking good names (and if not enough, can be extracted). Renaming classes is usually harder, because they generally cover more ground (remember how that happened, kids?).
Renaming is a part of our familiarization with the code, before testing it. Even if I don’t know what to test, making the code readable helps me not only understand what it does, but also how to test it.
We usually name by scope, if at all. Making the distinction helps in making sense. If there’s already a convention in the code (like m_ prefix for fields), make sure that the convention is followed in the code you’re observing. If there isn’t a convention, start one.
Compare the type of the variable to the method and to their type. If it can be improved, rename it.
Acct a = BankManager.getAccount();
We can rename a to account, and the we wouldn’t need to remember what a is in the next 500 lines of our method. If the method returning the value seems confusing, its type can help you rename it.
Don’t skimp on vowels! It’s starts as a clever way to save screen space, but after the vowels go, we think about other options, and soon we’re left with: acct. Not only less readable, but also annoying. Make the code readable.
Apart from renaming, if you can tidy up the code, put the declarations into one area, the beginning of class or methods. If you find declaration spread around, clean it up.
Method are harder to rename because they tend to do more, because of the aforementioned sloppiness. We usually start with a simple name, and then find the method the best place to do a couple things more . We soon have a big method, with a name reminding us of what the method was back then.
This is confusing to the reader, and of course makes it harder to test. But we’re not there yet. For now, make the renaming simple: If the method returns something prefix it with get. If it does something, make sure it start with a verb like set or make or call.
Check out the last lines of the method, or the exit points. Usually (not always), from the structure you’ll see what is the purpose of the function. Try to make the name fit the purpose. It may not be always the case though, so be careful.
Don’t skimp on vowels! And don’t worry about the screen space. Make method names convey their purpose, and use the entire alphabet for it.
These are the hard ones to rename, and I usually recommend not to (at least not until you cut them down to size). We only see the types at declaration or creation time, so renaming them won’t bring us much benefit in terms of understanding.
It might be beneficial to identify a base or derived class in its name. Mostly it won’t, and lends itself to get nasty later, when adding a third hierarchy layer, for example. I still like an I prefix to an interface, although it may get me killed in some communities. And always remember kids:
Don’t skimp on vowels! Applies to classes too.
Now that we’re done with renaming, it’s extraction time. Up next.