Introduction
I like to name things. A lot. And I appreciate unambiguity like a compiler. In some of my previous jobs, both as an employee and as a contractor, I was responsible for naming (and renaming) a good part of the codebase wherever possible.
I've wanted to write about naming classes and methods for a long time. Remembering some rules and recommendations from Kent Beck's Smalltalk Best Practice Patterns (which are as valid as when they were published almost three decades ago) and some rules and conventions of my own I've been following since I started programming in Smalltalk at the beginning of this century.
But what finally moved me to write about this was reading Naming Things: The Hardest Problem in Software Engineering, because I thought that I hadn't seen much, if anything, written about this topic lately in the context of Smalltalk.
Parameter Naming Rule 0: anObject
In Smalltalk it is very common to name method parameters by using the most general expected class in the name of the parameter, in the form of indefinite article + class name, i.e. aString
or aDictionary
, the error-prone aStringOrNil
or the catch-all anObject
.
This is a community convention almost as old as the language itself that is characteristic of Smalltalk codebases and there's nothing wrong with it. It's useful and describes the class of the expected argument, given Smalltalk's late binding.
Some examples of selectors with that convention are printOn: aStream
, at: anObject ifAbsent: aBlock
, isKindOf: aClass
, where the paramenter name tells you what object you should pass as an argument when sending a message.
Parameter Naming Rule 1: Only name parameters after existing classes
There is a common practice that breaks the rule described in the introduction: naming a parameter after a class that doesn't exist.
E.g.accessor: aSelector
, where there is no Selector
class.
My rule here, which I think I read somewhere over ten years ago, is to avoid doing that, using one of the alternatives:
- Use the right class name:
accessor: aSymbol
- Use the semantic name, without article nor class name:
accessor: selector
Parameter Naming Rule 2: Clearly distinguish between multiple parameters of the same class
Sometimes a method has two or more parameters of the same class, which can look like from: anOrigin to: anExtent
or copyFrom: aSource to: aTarget
, start: objectA end: objectB
.
All these examples have one or more issues, the obvious now is violating the PNR1, but also not having any semantic meaning. These could be rewritten as follows:
-
from: originPoint to: extentPoint
orfrom: origin to: extent
-
copyFrom: source to: target
or, if applicable,copyFrom: sourceRepository to: targetRepository
start: startObject end: endObject
Naming dynamics
βWhat you must learn is that these rules are no different than the rules of a computer system. Some of them can be bent. Others can be broken.β - Morpheus, The Matrix
There are often times when naming a parameter without following PNR0 will cause a clash between the parameter name and some instance variable name (e.g. from: origin to: extent
will likely clash with the origin
and extent
instVar names). In such cases, you will have to get creative and add a prefix or suffix to the parameter name if necessary.
Follow up
I have some other rules and conventions I'd like to share with the development community. Including adding new ones to those originally published in this article. Stay tuned.
Top comments (3)
I like this very much and we have applied these rules since long ago.
However, the rule 0 says "..., where the paramenter name tells you what object you should pass..." and the extra n in parameter is disturbing when talking about names ;-)
Besides that, although I adhere to the rule of article + (existing) class name because we adopted that in the team, I would personally prefer using nouns indicating the role of the parameter. Smalltalk is not typed, why should we declare the types of the parameters? Specially when the type is not interesting, like aString or aPoint and telling the use of the parameter is more relevant.
I share the jealousy in removing improper levels of ambiguity and vagueness in naming things. Specially because I'm conscious that it might induce a reader engineer in the future to make a mistaken assumption and these things have costs (time or worst).
And I think is worth noticing that the prefix
a/an
denotes a reference to being an instance (of some class) so in your example foraSelector
, theaSymbol
alternative removes nurturing the intuition of the reader suggesting why it exists and forcing him to reverse engineer whileselector
on the other hand would preserve meaning.So it depends on how much the author cares about communicating meaning and nurturing the imagination of the next developer reading that code whenever that happens.
To conclude on this though, a couple of ideas I can reflect on:
What you value most, correctness or revealing intention?
Aren't compilers supposed to do their job and help on enabling/enforcing correctness so human engineers can communicate themselves on a higher more meaningful level between them across time?
What code you (and future-you) will prefer to read 10 years from now to maintain or add a feature to?
I value revealing intention,
aSelector
suggests an instance of Selector, and there is no such thing in the image (unless you happen to have a Selector class). So, I adhere to Rule 1 as much as possible.There is related rule violation for "conversion" methods, which is to call a method
asSelector
when there is noSelector
class either, but that will be subject of another post.