One of these annoying challenges when coding is finding proper names for your classes. There are some tools available making fun of our inability to come up with proper names. But while I enjoy these kind of gags I think there is some serious problem hiding.
The problem is: Classes should be some kind of abstraction. I should only have one abstraction for a single purpose. But if my classes are unique abstractions it should be easy to name them, right?
You just have to look into the average code base to see it isn't easy. Lets have a look at a couple of common anti patterns.
AbstractAnything: Often you have a possibly large set of classes that share lots of common stuff. In many cases you find an abstract class at the top of their inheritance tree named AbstractWhatever. Obviously that name is technical correct but not very helpfull. After all, the class itself is telling me it is abstract, no need to put it in the name. But apart from being picky about the name a couple of serious design problem come with these classes. They tend to gather functionality common to their subclasses. The problem is: Just because all (or even worse many) of the subclasses need a feature or function it shouldn't be embedded in their superclass. The features are often mostly independent and therefore should go in separate classes. Lets take the example of an AbstractEditor which is intended to be the base class for models for editors in a Swing application. You might find things in an AbstractEditor like
- a save method, setting the cursor to its wait state before calling an abstract real save method.
- a boolean property telling you if this editor needs saving
- the class and id of the entity being edited
- Some property change handling infrastructure
- infrastructure code for validating inputs
- code that handles the process of asking the user if he wants to save changes when he tries to close the editor
and so on. Of course these features depend on each others, but when they are lumped into a single class the dependencies become muddled. If a new need for a feature occurs there is hardly an option anymore but to put it in the same class and after some time the class looks almost like this example. Note that some developers try to hide the application of this anti pattern by renaming the class to BaseSomething. Doesn't help though.
AnythingDo, AnythingTo, AnythingBs With this antipattern you have a properly named class and lots of very similar classes with various suffixes. These suffixes often are very short and denote different layers of the application. On the boundaries of these layers data gets copied from one object into the other with barely any logic.
The problem with this antipattern is that while there might be valid reasons for these classes to exists the seamingly determinism to construct one out of the other often runs against the purpose of these classes. An example: You might have a Person class which represents a Person in your system. You might also have a PersonHe (He like Hibernate Entity) which is mapped to a database table using Hibernate.
The Person class is intended be used in all the business logic stuff, but since at the boundary to the persistence layer it is just copied over to the Hibernate Entity it has to be handled in the way Hibernate expects things. For example you have to move the complete Person Object around even if you just want to change a single attribute (e.g. the marriage status), because if you just leave fields empty, Hibernate will store these empty fields in the database and you end up with Persons that don't have any useful property anymore except being married. Although this actually describes reality pretty good in some cases it normally isn't what you want.
Instead consider a design where in case of a marriage you actually create a Marriage object in your business logic, which does not have any direct relationship inside the database. You would do all kind of checks and logic in your business layer (without having code like)
if (oldPerson.married != newPerson.married && newPerson.married) ...
And only when you store it you put the information from the Marriage into Hibernate Person Entities. There is no MarriageHe or anything.
This kind of design makes for way more expressive code. But developers don't realize this option and often it is incredibly hard to force it into the existing infrastructur/architecture, because everything assumes there is a 1:1 relationship between Person and PersoneHe and all the other Person classes.
AnythingImpl This one is annoying. And most people actually feel that they do something wrong when they have an interface X and a single implementation XImpl. It is bad because the Impl suffix basically tells us nothing. JavaDoc already tells us its the implementation of the interface, no need to put that fact into the class name. It also suggests there will always be only one implementation. At least I hope you don't have classes ending in Impl2 and Impl3 in your code base. But if you have only one implementation in the first place why do you have an interface? I doesn't make sense. Lets think hard about what other implementations there are (or might be).
A classical exammple is the PersonDao interface and PersonDaoImpl. Here are some possible implementation alternatives I would come up with:
- one implementation could use Hibernate to store and retrieve stuff.
- one implementation could use a map or similar in memory structure to store stuff. Very usefull for testing
- one implementation might use special Oracle features
Which one is PersonDaoImpl?
And by contrast which one is OraclePersonDao, HibernatePersonDao and InMemoryPersonDao? If nothing else consider ProductionPersonDao to distinguish it from the implementation used for testing.
The next time you have a good class or interface name and you feel like slapping some kind of standard suffix or prefix onto it in order to create the name for another class, think twice. You might be creating a useless class name, or you might be screwing up your software design.
Wan't to meet me in person to tell me how stupid I am? You can find me at the following events: