The hardest problem in programming is not proving correctness, but naming things. Frequently, I find myself looking at a new codebase, or a section of a larger codebase I haven’t been exposed to so far, and I have problems determining what this code is supposed to do.
Sometimes this is due to 400-line-functions that should have had their different code paths split up into separate functions ages ago, but other times, the code is well-structured and I’m familiar with the domain’s terminology, but the naming of the variables and functions and classes still actively hinders understanding. Why is that? How can this be?
Class of word
One thing I’ve seen is that identifier names don’t follow the grammar of a sentence or don’t use the proper class of word. If a method triggers an actual process, an action as the user would understand it, it should be a verb. setFoo: applies a change. If a method named commandProcessor actually runs a loop that processes commands, it should be renamed runCommandProcessingLoop instead. That way, when I read it somewhere, even if I haven’t read its contents yet, I have a general idea what it does.
If it doesn’t contain a verb, I’ll have to make up my own. What could it be? createCommandProcessor? resetCommandProcessor?
Of course, there are fuzzy spots. If NSViewController‘s view method implicitly loads and creates the view, shouldn’t it be called loadView instead? Or is this an implementation detail that I can leave out? In general, I tend to count caches and lazy-loading that happens as needed as implementation details. So your property does not have to be named as a verb.
Cases and modifiers
Another thing that I see a lot, particularly in codebases that have a lot of non-native English speakers working on them, are problems with cases. This can take the shape of reversed word-order that has the defining word of a compound at the wrong end, like ListChannel instead of ChannelList.
This can be very unfortunate, as in English, many verbs are identical to their nouns, and only differ in their position in the sentence. So when I see ListChannel I don’t just think this is a single channel that somehow contains or presents a list, but rather I might read it as a verb. When someone declares a variable of this type, my interpretation, in order of likelihood is therefore:
- A block or functor type that somehow lists channels.
- A channel that somehow lists something.
- A mis-named list of channels.
Where the right one, in our example, is the 3rd and least likely choice.
Another common mistake is excessive use of plurals, like MyChannelsList. This may look harmless at first, but can in some cases lead to ambiguity. E.g. if your project convention is to name typed arrays as the plural of your element type, this would be a list of Channels objects, which in turn are lists of Channel objects. Now, ignoring the (lack of) wisdom of having a one-character difference in names, excessive plurals like that make me mistrust the code and force me to check whether there is a reason for this extraneous plural or not.
The third class of bad names that I see in projects are “fuzzy” words. The most common case are class and file names that don’t have a clearly delineated meaning and therefore attract functionality like one of those magnetic cranes in a junk yard.
I’m sure you can come up with more examples, but they all have one thing in common: They are so generic that almost no method or function is off-topic for this file. And when you’re actually searching for a particular method or function in a foreign codebase, any of these files is probably a good candidate.
While Utilities.h is obviously a catch-all into which everyone can dump whatever they want when they are too lazy to add a new file to a project “just for this one function”, or want to avoid having to merge project files if someone else also just added another file to the project, the others are less obvious, but just as magnetic:
The network is a big place, with many layers. Is this just a wrapper to convert certain data types before they’re sent over a socket? Are these actual protocol implementations? URL string-formatting functions? So much could be valid for a class named NetworkExtras.
I worked on one project that contained a debug menu that scrolled for 3 screens, and where none of the menu items could be re-used in other projects easily because all the code for them was in the application delegate, causing that to need a recompile every time one of them changed.
So for the next project, I created a MYDebugMenuSection class whose +load method adds it to a list which is then used to build the debug menu. Each of these classes is one submenu. So I now have a generic MYViewsDebugMenuSection that turns on/off lots of view-related things (like drawing their frames, flashing updates etc.) or logs the view hierarchy. To every new project, we can just add that header and source file, and get the same debug features we have in every other app.
Then someone found that too onerous, and created an “Other” submenu, and shortly, another developer added another bunch of items to this menu instead of creating their own section for their submodule. All we gained was that you now had to navigate to a submenu before you were forced to scroll through your 3 screens full of items. So I split them, and renamed them, to avoid the magnetism of the fuzzy “Other”.
StringExtensions? Same problem. There are lots of things you do with strings. Name it StringURLFormattingExtensions, or be prepared to have to split the file every few weeks. Same with NSURL+Helpers.
Some of you may not believe me. And I don’t blame you, it’s easy to overshoot the target. To create headers that are too concrete and really only contain one function. I agree, that’s bad. Avoiding that requires common sense, too. But if you don’t believe that crap is magnetic, go to an underpass that is not publicly visible from the outside and has a big empty flat wall that has been freshly painted. Visit it regularly.
At first, it’ll be virginally white. Then, someone will paint a tag on it, or stick a sticker on it. Then it’ll stay like that for a while. Then the next person will come along, and she’ll think: “Hey, nobody removed the tag. Let’s put mine on there as well!” And then there’ll be more and more tags, until finally someone will slap a gorgeous graffiti over it. And then someone else will add another one, and a few taggers will tag in empty spots on the graffiti …
This even works with advertisements. Here in Munich, under the Heimeranplatz train overpass, there was an insurance advertisement that, as part of its picture, contained a few scrawls that, blown up to billboard size, looked just like tags. Within a month, the billboard had accumulated another dozen or two tags on “what was obviously a derelict billboard”.
It works with garbage: One person stuffs a paper cup in a hole in the wall, other people throw their trash there as well.
It works with code. Send the bin man round every few weeks. You’ll love your code’s fresh smell.