Beginner mistakes and lazy solutions
Quick development or code from juniors could often lead to an implementation of the required functionality, but with terrible names. In a first draft/POC of the code, that is not a problem, but when the code is approaching the ‘done’ phase, and is used by team members, it is important to think about naming. The reason for this, is that a good name decreases the amounts of hours you have to spent reading the code to figure out what it does.
Naming is considered one of the more difficult things in programming. I do not fully agree. One of the reasons, I believe, that it is considered difficult, is because there is not enough effort put in application design. Naming code based on what it represents instead of what it does. That is one of the key mental shifts.
One of the easiest and fastest ways to spot bad or incomplete naming, is looking for the following words. Naming any piece of code with these words, is usually a sign that the code is doing too much, too little, or is mix and matching different abstractions and functionality together. Placing everything related to Azure in an Azure-helper, for example, instead of thinking about different Azure resources and types of interactions. Instead of being lazy and using one of these, think about what the code (or part of the code) represents.
* Helper(s)
* Manager / Management
* Info(rmation)
* Data
* Processor / Processing
* Executor / Executing / Execution
* …
Whole names and fluent reading
The idea of ‘whole’ names, is to name a piece of code by its purpose, what it represents. A tip for this, is using a lot more XML code documentation on public members and start your summary with Represents... and try to capture the purpose in a single sentence (without cheating).
Members with small names like Execute, Process, usually are not ‘whole’, but are hiding a lot of functionality. The reason why they are small, is because if the full purpose would be included in the name, it would be unreadable.
Names that represent the purpose of the code are – I believe – not so hard to find. The key is to think in different ways to read the code. Fluent reading can help with this. Think of the hidden purpose behind the obscure names, and use that for the new name. Functional programming is probably a lot easier to write whole names, because the functions are usually a lot smaller. Functionality is build by composition by its core, which means that the fluent reading is your code itself. In writing object-oriented code, we have to force to think in smaller pieces so that new names pop up.
Design patterns and application conventions
What can help with finding new names, is to look for existing names and metaphors. When something needs to be created requires several actions, you could use the factory pattern; if that same something needs options for its creation, maybe a builder pattern is order. If something is disposable, like a test fixture, you could start the name with Temporary.... There are already so many already names out there in the wild.
Another thing of good names, is using the same conventions throughout the application. If repositories use Add... to append a new item to a backend storage, then another repository in that same application should not use `Create…` for the same kind of action. Do not mix Get, Obtain, Read, is another example. The same goes for other, less obvious, names.
If you use existing metaphors for your functionality, code reading becomes less of a struggle.
Conclusion
Of course there are exceptions. Sometimes you work with a library that already forces bad naming upon your own code, sometimes the legacy system is too big to start renaming everything in one go.
The common-feeling that naming is hard, is not something that I can relate to often. Usually, when testing and design comes first in a project, names comes automatically when you talk about certain pieces of functionality. Do not fall for the trap of using a non-name like ‘helper’ or ‘info’ for something that is clearly representing something else. Everything can be considered a ‘helper’, every piece of transferred data is ‘information’. We already know that, the purpose of the name is to go beyond the obvious and describe what it represents.
Is it creating something? Is it sending something? Is it loading something? Names span entire applications and single variable names. Naming those and everything in between is a matter of thinking in patterns, conventions, and of what purpose it plays within the larger system.
Thanks for reading!
Stijn