As a follow up to my last post here are some more common Java prefixes/suffixes.
By the way, have you subscribed to the new blog location yet? http://blog.joda.org/feeds/posts/default
More common Java prefixes and suffixes
The last post focussed on class names in the presence of an interface. AbstractFoo
BaseFoo
, DefaultFoo
and SimpleFoo
were my choices, with BasicFoo
, StandardFoo
, GenericFoo
, IFoo
and FooImpl
being ones I rejected. But there are lots of other common naming patterns used in Java.
The purpose of these naming patterns is to increase the readability of the codebase as a whole. This is very similar in concept to other coding standards like "no tabs" or "braces at end of line". Its also part of my belief in doing the best we can when writing long-lived code to help those in the future who will read, use and maintain the code.
So, here are some additional naming patterns:
Foo - The basic named concept should always have the best name (for this blog, it could be a class or interface).
FooUtils - A set of utilities that support usage of Foo. This is particularly common with interfaces, but does not have to be limited to them. In some cases, particularly in a hierarchy or group of classes, it can make sense to separate out common utilities, leaving just static factory methods on the main class. I'll note that a Javadoc annotation to mark a method as a factory is long overdue.
FooBuilder - An implementation of the builder pattern that is used to create an object in a fluent manner. This is especially useful for large, complex objects, particularly when the end result is immutable. Sadly in Java, a builder is quite a lot of effort to write well.
FooManager - I prefer manager to FooFactory
because I generally find that a factory does more than just creation, for example registering a lookup. However, I tend to avoid explicit managers/factories. For classes, I would prefer to see the manager/factory as static methods on the class itself, so this would most often be used for interfaces. However, I tend to find that most of my interfaces either require the user to pick the concrete class or are injected by IoC.
DelegatingFoo - A class that exists as an abstract base to wrap a Foo and add some behaviour by delegation. Most of the time I would say that it is not worth creating the decorating abstract base class, and only having the concrete version as it makes each class simpler to understand in isolation.
FooProxy - A class that stands in for the complete set of data as part of a lazy loading strategy. I believe that this is sometimes used for the delegation case, but I find that confusing.
Fooable - This would be used for an interface where the implementations are in some way related to Foo
. An example would be Identifier
and Identifiable
. In this case, the -able suffix implies that the implementing class "can be identified". In code terms that usually means a single getFoo()
or toFoo()
method.
Note that I haven't covered every last prefix/suffix - there are many more. Sometimes a computer name list or thesaurus is useful.
Some other possibilities are:
FooUtil - I find FooUtils
to be a much nicer name.
Foos - I use FooUtils
, as I would see the plural suffix as a JDK style, as in Collections
.
FooFactory - As discussed above I find when I do need a separate factory it is usually more of a FooManager
than just a factory.
ForwardingFoo - An alternative to DelegatingFoo
notably used by Google Guava, mostly a matter of preference as to which to choose, but be consistent.
DecoratingFoo - Another alternative to DelegatingFoo
.
I should just note that both this and the last post are quite Java focussed. Other languages have different "styles" of coding that naturally result in different naming patterns.
I should also note that most of the time class names should express what makes them distinctive. However, it is sometimes more useful to have a naming convention as it aids learning of the system.
Summary
Again, there are no cast-iron certainties in class naming or coding standards in general. However, it is useful to have a common starting point at least within one project.
Opinions welcome as always.
FooProxy would have a different meaning in the networked world: there you would expect the FooProxy to implement Foo, but be doing RMI &c. inside of itself (thus implying network costs).
ReplyDeleteIf the intent is to denote lazy loading, perhaps LazyFoo would be a more direct convention?
Why is Foos JDK style but FooUtils non-JDK style? Are you advocating in general that non-JDK authors stay away from JDK styles of naming? That doesn't seem right. Or do you just not like Foos? Or do you want to avoid Foos in case the JDK adds one later (like Strings or Files)?
ReplyDeleteI always switch back and forth between FooUtils and FooUtil, though I can't defend the latter at the moment.
James, you are right about the meaning. I guess Proxy could be used in different ways - just generally a placeholder.
ReplyDeleteLawrence, FooUtils vs Foos is a tricky one, but I'm simply noting that most OSS projects I've seen choose FooUtils rather than Foos. I guess there is nothing rationale in that as an explanation, but there you go.
Steven, it seems to me that you're talking out of both sides of your mouth. Just recently you were taking Kotlin to task because of its "reversed" type declarations, and now you seem to be completely blase about these name modifiers being either at the end or at the beginning.
ReplyDeleteSo I think the first question to get out of the way, is, does it matter? I.e., should these name modifiers always be in one place or the other? My inclination is to have them at the beginning, but then FactoryFoo looks a bit weird. I think it's what some people commented about on your Kotlin entry; it's just something that you get used to after a while. Nevertheless, I am inclined to think that the name modifiers should all either go at the beginning or the end.
Lumpynose, I don't think there is an inconsistency here. There were two driving points in the recent blog - the overpowering colons and the problem of default params - which combine to make it less readable, particularly wrt the return type on the right. But the key point is readability. With all sensible type names, the letters in the name form a single visual blob, usually surrounded by spaces or other punctuation. So, picking out that something is a type, as opposed to a variable name or other syntactic element is relatively easy. The visual parsing of the type name itself is something where I always find I have to read the whole thing anyway, thus PrefixFoo and FooSuffix becomes a detail, which can be driven by other concerns.
ReplyDeleteGreat topic, and good coverage, thank you, Stephen.
ReplyDelete@lumpynose: I advocate using both prefixes and suffixes as "name modifiers," but with a very clear heuristic to determine which is correct for a given type: a name prefix should generally be an adjective implying a "narrowing" or refinement in the specification of the role of the type (eg, BlueFoo). A prefixed Foo is a more specific kind of Foo.
By this same rule, a name suffix isn't really a suffix at all, but instead implies a type whose role is RELATED to Foos in some manner (FooFactory, FooPrinter, BlueFooFrobbler). A suffixed Foo is NOT a Foo, but it operates on Foos somehow -- the "Foo" is actually a prefix.
Adhering to this rule has the benefit of suggesting good names for variables of the given type: the developer (or, more often, his IDE) can just truncate prefixes from the front of the type name until arriving at the shortest possible name that uniquely identifies the variable's meaning: a BlueFoo variable may just be 'foo', or it may be blueFoo if a RedFoo is also in scope. (And when 'foo' isn't specific enough, context-specific adjectives can be prefixed on variable names as well: 'BlueFoo smallFoo')
Similarly, the BlueFooFrobbler variable would likely just be named 'frobbler'.
Finally, regarding FooUtils: I'd suggest that the need for such bundles of global functions is generally a bad smell; there's likely a natural refactoring that would lead to a non-static home for those methods. The only case where I find myself needing Utils any more is when dealing with third-party libs (eg, the JDK) which, unfortunately, cannot be extended in our draconian java type-system.
Bitsucker, I think that your explanation of why prefix/suffix is excellent.
ReplyDeleteOn FooUtils, I find I mostly use it for interfaces these days, where there isn't necessarily an obvious alternative home for the method.