A while ago, we have published this fun game we like to call
Spring API Bingo. It is a tribute and flattery to Spring’s immense creativeness when forming meaningful class names like
- FactoryAdvisorAdapterHandlerLoader
- ContainerPreTranslatorInfoDisposable
- BeanFactoryDestinationResolver
- LocalPersistenceManagerFactoryBean
Two of the above classes actually exist. Can you spot them? If no, play
Spring API Bingo!
Clearly, the Spring API suffers from having…
To name things
There are only two hard problems in computer science. Cache invalidation, naming things, and off-by-one errors
– Tim Bray quoting Phil Karlton
There are a couple of these prefixes or suffixes that are just hard to get rid of in Java software. Consider this recent discussion on Twitter, that inevitably lead to an
(very) interesting discussion:
Yes, the
Impl
suffix is an interesting topic. Why do we have it, and why do we keep naming things that way?
Specification vs. body
Java is a quirky language. At the time it was invented, object orientation was a hot topic. But procedural languages had interesting features as well.
One very interesting language at the time was Ada (and also PL/SQL, which was largely derived from Ada). Ada (like PL/SQL) reasonably organises procedures and functions in packages, which come in two flavours: specification and body. From the
wikipedia example:
-- Specification
package Example is
procedure Print_and_Increment (j: in out Number);
end Example;
-- Body
package body Example is
procedure Print_and_Increment (j: in out Number) is
begin
-- [...]
end Print_and_Increment;
begin
-- [...]
end Example;
You always have to do this, and the two things are named exactly the same:
Example
. And they’re stored in two different files called
Example.ads
(ad for Ada and s for specification) and
Example.adb
(b for body). PL/SQL followed suit and names package files
Example.pks
and
Example.pkb
with pk for Package.
Java went a different way mainly because of polymorphism and because of the way classes work:
- Classes are both specification AND body in one
- Interfaces cannot be named the same as their implementing classes (mostly, because there are many implementations, of course)
In particular, classes can be a hybrid of spec-only, with a partial body (when they’re abstract), and full spec and body (when they’re concrete).
How this translates to naming in Java
Not everyone appreciates clean separation of specs and body, and this can certainly be debated. But when you’re in that Ada-esque mind set, then you probably want one interface for every class, at least wherever API is exposed. We’re doing the same for
jOOQ, where we have established the following policy to name things:
*Impl
All implementations (bodies) that are in a 1:1 relationship with a corresponding interface are suffixed
Impl
. If ever possible, we try to keep those implementations package-private and thus sealed in the
org.jooq.impl
package. Examples are:
This strict naming scheme makes it immediately clear, which one is the interface (and thus public API), and which one is the implementation. We wish Java were more like Ada with this respect, but we have polymorphism, which is great, and…
Abstract*
… and it leads to reusing code in base classes. As we all know, common base classes should (almost) always be abstract. Simply because they’re most often
incomplete implementations (bodies) of their corresponding specification. Thus, we have a lot of partial implementations that are also in a 1:1 relationship with a corresponding interface, and we prefix them with
Abstract
. Most often, these partial implementations are also package-private and sealed in the
org.jooq.impl
package. Examples are:
In particular,
ResultQuery
is an interface that
extends Query
, and thus
AbstractResultQuery
is a partial implementation that
extends the
AbstractQuery
, which is also a partial implementation.
Having partial implementations makes perfect sense in our API, because our API is an
internal DSL (Domain-Specific Language) and thus has thousands of methods that are always the same, no matter what the concrete
Field
really does – e.g.
Substring
Default*
We do everything API related with interfaces. This has proven highly effective already in popular Java SE APIs, such as:
- Collections
- Streams
- JDBC
- DOM
We also do everything
SPI (Service Provider Interface) related with interfaces. There is one essential difference between APIs and SPIs in terms of API evolution:
- APIs are consumed by users, hardly implemented
- SPIs are implemented by users, hardly consumed
If you’re not developing the JDK (and thus don’t have
completely mad backwards-compatibility rules), you’re probably mostly safe adding new methods to
API interfaces. In fact, we do so in every minor release as we do not expect anyone to implement our DSL (who’d want to implement
Field
‘s 286 methods, or
DSL
‘s 677 methods. That’s mad!)
But SPIs are different. Whenever you provide your user with SPIs, such as anything suffixed
*Listener
or
*Provider
, you can’t just simply add new methods to them – at least not prior to Java 8, as that would break implementations, and there are many of them.
Well. We still do it, because we don’t have those JDK backwards-compatibility rules.
We have more relaxed ones. But we suggest our users do not implement the interfaces directly themselves, but extend a
Default
implementation instead, which is empty. For instance
ExecuteListener
and the corresponding
DefaultExecuteListener
:
public interface ExecuteListener {
void start(ExecuteContext ctx);
void renderStart(ExecuteContext ctx);
// [...]
}
public class DefaultExecuteListener
implements ExecuteListener {
@Override
public void start(ExecuteContext ctx) {}
@Override
public void renderStart(ExecuteContext ctx) {}
// [...]
}
So,
Default*
is a prefix that is commonly used to provide a single public implementation that API consumers can use and instantiate, or SPI implementors can extend – without risking backwards-compatibility issues. It’s pretty much a workaround for Java 6 / 7’s lack of interface default methods, which is why the prefix naming is even more appropriate.
Java 8 Version of this rule
In fact, this practice makes it evident that a “good” rule to specify Java-8 compatible SPIs is to use interfaces and to make
all methods
default with an empty body. If jOOQ didn’t support Java 6, we’d probably specify our
ExecuteListener
like this:
public interface ExecuteListener {
default void start(ExecuteContext ctx) {}
default void renderStart(ExecuteContext ctx) {}
// [...]
}
*Utils or *Helper
OK, so here’s one for the mock/testing/coverage experts and aficionados out there.
It’s TOTALLY OK to have a “dump” for all sorts of static utility methods.
Please. Don’t be “that guy”! :-)
So, there are various techniques of identifying utility classes. Ideally, you take a naming convention and then stick to it. E.g. *Utils.
From our perspective, ideally you’d even just dump all utility methods that are not stricly bound to a very specific domain in a single class, because frankly, when did you last appreciate having to go through millions of classes to find that utility method? Never. We have org.jooq.impl.Utils
. Why? Because it’ll allow you to do:
import static org.jooq.impl.Utils.*;
This then almost feels as if you had something like “top-level functions” throughout your application. “global” functions. Which we think is a nice thing. And we totally don’t buy the “we can’t mock this” argument, so don’t even try starting a discussion
Discussion
… or, in fact, let’s do start a discussion. What are your techniques, and why? Here are a couple of reactions to Tom Bujok’s original Tweet, to help get you started:
Let’s go ;-)Like this:
Like Loading...
I do not agree with the Util/Helper class as a “dump” for anything.
I am currently refactoring a very messy legacy codebase that has helpers, advisors, managers, brokers, addins, utils, helperadvisorbrokerutilsadinfinitum.
Classes, regardless of what they are named, should be concise and coherent. They shouldn’t be a dumping ground for static methods or they stand a strong chance of winding up a very messy incoherent jumbled dump of crap – just like in any other trash dump.
As for naming – the name of a class should be as close to what it does as possible. What is a helper? Helps do what? Devs tend to just throw anything and everything into these classes. Few have the discipline and patience to create something like Apache StringUtils with a coherent and concise interface.
And no – I don’t like *****Impl at all. I used to use it, and then decided it was redundant. I still use Abstract and sometimes Default, but sparingly.
Anymore an IDE along with a quick glance at the code, will tell you whether something is an interface or not. Ditto for Abstract classes too really. Default implementations – those are worth noting in the name.
I essentially agree with you on the criticism on helper dumps. The goal should be something like
StringUtils
. Two things should be considered:I don’t like ****Impl either, but when specs and implementation are in a 1:1 relationship, I haven’t found a better solution, so far.
I agree with most of your post, except the first paragraph. In my opinion Spring is far away from having a naming problem. I can see that many class names might sound like a black magic mix of general terms (adapter, factory, resolver, delegate, etc.). But if you are familiar with the concepts in Spring many of the class names become very self explaining.
Here are some examples that make some of the longest class names in Spring:
***HandlerMethodArgumentResolver:
In Spring’s web framework classes that handle web requests are called Handlers. Such an Handler typically has one or more methods that take incoming requests and generate some kind of response (=HandlerMethod).
Handler methods can have many different arguments which are passed by Spring once such a handler method is invoked. For example: If a handler methods defines a parameter of type Locale, Spring automatically passes the request locale. (see this for a full list of possible arguments: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html)
These arguments are resolved by an HandlerMethodArgumentResolver (pretty clear name, right?).
HandlerMethodArgumentResolver is an interface with a lot of different implementations. For example:
PathVariableMethodArgumentResolver – resolves path variables from the requested url
MatrixVariableMapMethodArgumentResolver – resolves matrix variables
ServletCookieValueMethodArgumentResolver – resolves cookie arguments
***BeanPostProcessor
A BeanPostProcessor can be used to implement custom modifications after a bean is created. This is used a lot by Spring itself to implement various features. Again, I think BeanPostProcessor is not the worst name for such an interface.
Implementation names are also very descriptive:
RequiredAnnotationBeanPostProcessor – processes @Required annotations in newly created beans
InitDestroyAnnotationBeanPostProcessor – responsible for calling init/destroy methods on created beans
PersistenceExceptionTranslationPostProcessor – translates exceptions of various persistence solutions into Springs DataAccessException.
More long names:
BufferedImageHttpMessageConverter:
An implementation of an HttpMessageConverter that can be used to read/write BufferedImage objects
QualifierAnnotationAutowireCandidateResolver:
An AutowireCanditateResolver that resolves canditates eligible for autowiring based on @Qualifier annotations.
JodaDateTimeFormatAnnotationFormatterFactory:
An AnnotationFormatterFactory for handling DateTimeFormat annotations using Joda-Time.
Jsr310DateTimeFormatAnnotationFormatterFactory:
An AnnotationFormatterFactory for handling DateTimeFormat annotations using JSR-310 Date/Time API
I have never heard of BeanFactoryDestinationResolver (your example). But I know for what Spring’s DestinationResolver interface is used. So it becomes very obvious what a BeanFactoryDestinationResolver might do.
While some names might be very long, you can often do a pretty good guess what a class does just by reading the class name. For a framework with >3K classes I think this is quite an accomplishment.
Two points (apart from the fact that that part was more of a “funny” rant than anything else):
1. I doubt that 2/3 of those types need to be part of any public API. I really doubt it
2. Subtype polymorphism is completely overused in Spring, where generic polymorphism would have been much better.
3. I personally doubt that 2/3 of Spring is really needed in general. I really don’t see the point of anything like a JodaDateTimeFormatAnnotationFormatterFactory. I’m sure, this can be written with a one-liner and
String.format()
or so. But that might just be me, trying to KISS ;-)