Intro
This question deals with the nuances of naming a class within an interpreted language to avoid association with native data structures, in this case, Python.
Background
I am currently refactoring existing infrastructure. We have a class ComplexList
whose naming leads me to inherently associate it with a mutable Python list
. However, its underlying implementation and usage are more intricate (described below).
What it actually is: a quasi-immutable "master" dict
mapping to address locations within a packed binary struct, including metadata for knowing bit-positions of flags within bit vectors.
Within the class is a list
of keys mapping back to the master dict
. This is why it is called ComplexList
: because as input, it takes a list of keys that can be used to retrieve items from the master dict
.
The master dict
mapping is made quasi-immutable by having its definition stored in a protected method, _create_master_dict()
.
This method is used to regenerate the master dict
any time a new entry is added to ComplexList
, meaning even if a library user manually manipulated the protected variables storing the master dict
, their changes would get overwritten eventually.
We then use inheritance to allow child classes to extend the parent's _create_master_dict()
with their own additional mappings.
Hence why I say "quasi-immutable": of course it is not truly immutable, but by implementation, it should not be modified.
What might be a good name for such a class to avoid association with native Python data structures and methods?
Ideas
I have considered: ComplexMap
, ComplexListToDict
, things along these lines, but of course, map()
is again a native Python method, and using list
and dict
in a class name might serve to be even more confusing.
I've also considered something completely abstract like ComplexData
, but this seems a bit too obscure.
Answer Preferences
I'm not against switching to any of the ideas I mentioned above. I am also okay with keeping things as they are! It's entirely possible I am overthinking this.
This library will be used by many other people once it is adopted. I'm looking for ideas that are concise and seem intuitive. This could mean an answer that does not line up with my own intuition, so all feedback is welcome!
References
For reference, I have examined PEP 8, Google Python style guide, and numerous other StackOverflow articles, but I haven't stumbled across a question that discusses anything quite along these lines.
Many of the StackOverflow articles are limited to variable naming conventions or avoiding Hungarian notation in naming. There doesn't seem to be much literature discussing good ways of naming classes.
I hope that my explanation was not too long-winded and helps to elucidate the situation. Any thoughts and input would be greatly appreciated!
Standard Names
This gets so subjective but when aggregates/collections deviate considerably from standard collections interfaces, what I prefer is just make the name plural. If we have a collection of Control
with a very unusual interface that isn't like the standard containers at all, then I might name it Controls
.
That prevents that temptation/confusion to associate it with any existing interfaces in the standard library, and can somewhat fend off the zealots who might be tempted to make it conform to standard interfaces to generalize it in some way that has a lot of cost and little benefit for such a narrow and well-tested use case.
Standard Names = Standard Expectations
A practical realization to make is that if an interface does not conform to the canonical conventions associated with a name, it might confuse less and tempt less and call more attention for developers to check out the actual interface instead of assuming by simply naming it in a way that avoids such standard names in the first place. The main benefit I see of naming something in a fairly standard way is to communicate that it conforms to standard expectations. If it can't, then perhaps there is some argument that isn't too subjective to avoid the standard name outright since that actually detracts from the main benefit of having a standard name in the first place if it's going to be "overloaded" for cases which don't conform to the associated expectations.
Actually that's the only benefit I can think of is that if I named it something like ControlList
or ControlDict
or ControlMap
depending on the nature of the interface and underlying data structure instead of Controls
, then people might be tempted to raise these types of questions about why it doesn't conform to standard interfaces with a similar name (which has a simple answer but I'd rather the question not be raised at all).
The whole point of, say, the metric system naming conventions is that they conform to standard expectations. When we say something is seven "meters", it's clear what to expect. It's not clear if we overloaded the name where "meters" could sometimes mean "feet" or "yards" in some cases absent further clarification, and we actually dilute and convolute the whole metric system convention if we ever reused those names like "meters" in different contexts where the same standard name carries very different expectations.
An Argument For a Plural Name (When Practical)
So a plural version of a name is a very basic option you might explore, or not. Just practically speaking I don't think any class, and especially one named with an UpperCamelCase
convention which deviates from standard, should make people think it behaves like the interfaces found in standard containers which share a subset of the name. It's rather moot in my opinion. But when we're working with developers who base their whole livelihood and beliefs on what's right and wrong and need to believe in themselves to motivate themselves to do what they do with all kinds of fuzzy ideas there, "moot" isn't always "moot".
Sometimes you encounter developers who see a List
or Dict
or Map
or something like that as a prefix or suffix in some name and expect it to conform identically to the interface and behaviors of what's in the standard library and that can trip people up and sometimes get them on some tirade. I'm kind of a weird developer concerned with "human factors" and psychology like this for better or worse (more concerned with how a wide range of people tend to respond to code than the nature of how the code is written in some impersonal sense), and I've dealt with a wide range of developers (including some really extreme and interesting but brilliant and deeply-opinionated and difficult characters) to kind of work towards the kind of conventions I favor and sometimes impose on teams in some attempt to cause "minimal fuss".
So there might be some small merit to avoiding such names unless the interfaces conform to identical requirements. I just tend to favor plural names like Controls
instead of ControlList
or ControlSequence
or ControlMap
or anything of this sort when it deviates from standard expectations because it doesn't require so much thought and doesn't raise so many questions. I also have to admit that sometimes these interfaces do face unanticipated design changes (a map-like interface with key/value pairs might turn into a sequence-like interface), and this very basic sort of pluralized naming convention avoids the temptation to keep renaming the class and incur more code changes than necessary in those sub-optimal scenarios where the interface and potentially the underlying data structure is still a work in progress.
It's kind of common in my industry (Visual FX for films and games and so forth) to face these sub-optimal scenarios where interfaces might need to change along with huge aspects of the underlying implementation since yesterday's popular data structure and algorithm can become obsolete at any moment given how rapidly the industry changes when it comes to state-of-the-art computer graphics techniques, and you have to be pretty lucky or working with very high-level code to avoid any need to change interfaces at that point. Favoring pluralized aggregate conventions which don't even communicate the underlying data structure can be particularly beneficial to reduce the temptation to cause more code changes than minimally required in this extreme context.
My preferred style is that when we need to aggregate Foo
into some non-standard (in terms of interface design) collection/container which serves as the "primary aggregate", then call it Foos
. If I need some auxiliary, less-commonly-used containers like a map of Foo
to Bar
, then consider just utilizing the standard containers in those cases if possible without creating a new class/type. If not, then I might call the auxiliary container, less commonly used, like FooMap
or something of this sort, and in that case I'd seek to conform to the standard map/dictionary interface as much as possible unless it's not practical, at which point I shrug and just still call it FooMap
and try to resolve any ambiguities and confusion in the documentation. I can at least attest that favoring this style and imposing it has lead to what appears to be less fuss among developers, including some of the most dogmatic types I've ever worked with (funnily some of the most prolific developers I've worked with are also the most dogmatic, and it helps not to piss them off too much). Obviously that's very anecdotal and as a disclaimer I'd suggest to take any answers here with a grain of salt.