Four harmful Java idioms, and how to fix them

Rewrite convention and optimize your code for maintainability

1 2 Page 2
Page 2 of 2
  • It would likely not include a no-argument constructor, as such constructors carry no data. Does it make sense to model a database ResultSet by creating objects that by design can carry no data, even temporarily? Does a no-argument constructor suggest itself naturally to the mind for this domain? No, it doesn't. (It's true that data is often optional, but how often are all columns in a ResultSet optional?)

  • It would likely not have anything to say about events and listeners.

  • It would likely not force you to use mutable objects. In Web applications in particular, model objects often exist only for the duration of a single request. Such objects aren't long-lived, and don't need to change state in response to user actions.

  • It would likely define a data validation mechanism. Such validation is one of the most important features of database apps, and should be supported directly in the model. (Remember the first thing you learned about objects: an object encapsulates both data and operations on the data. In this case, the operations are the validations.)

  • The validation mechanism would allow for reporting errors to the end user.

The JavaBeans specification was created for a very particular problem domain: that of manipulating graphical widgets at design time. The specification makes absolutely no mention of databases, because it was not created with databases in mind. As a result, it's not surprising that JavaBeans aren't a very natural choice for the problem of modeling database records.

From a practical perspective, many widely-used frameworks require application programmers to use JavaBeans (or something similar) to model database records. This is deeply unfortunate, because it doesn't allow programmers to take advantage of the many positive qualities of immutable objects.

Private members: Why put them up front?

Old Hollywood movies usually start with the credits -- all of the credits. In a similar way, most Java classes place implementation details (the private members) first. Listing 3 shows a typical example of this style.

Listing 3. Private members, listed up front

public class OilWell implements EnergySource {
   private Long id;
   private String name;
   private String location;
   private Date discoveryDate;
   private Long totalReserves;
   private Long productionToDate;
   
   public Long getId() {
      return id;
   }
   public void setId(Long id) {
      this.id = id;
   }
   
  //..elided
}

However, placing private items last, not first, seems to show more compassion for the reader. When trying to understand something -- anything -- you should move from the general to the specific. More precisely, you should move from a higher to a lower level of abstraction. If you do the reverse, then initially the reader will likely not know the point of the whole thing, or grasp how things work together, and will be confused by trying to remember a number of potentially disconnected facts.

The whole point of abstraction is to allow you to ignore details. The higher the level of abstraction, the more details you can ignore. The more details the readers of a class can ignore, the happier they are. Holding many details in your head is painful, so fewer details are better. Thus, placing private items last seems more compassionate, as it puts off details that may not be necessary at all for the reader's current task (whatever that may be).

Originally, the C++ programming culture placed private items first, just as in Java. However, unlike the Java community, the C++ community quickly came to realize that this was an unhelpful convention, and it is now reversed. Here is a comment from a typical C++ style guide:

Notice that the public interface is placed first in the class, protected next, and private last. The reasons are:

  • programmers should care about a class's interface more than implementation
  • when programmers need to use a class they need the interface not the implementation

It makes sense then to have the interface first. Placing implementation, the private section, first, is a historical accident, as the first examples used the private-first layout. Over time emphasis has switched, de-emphasizing a class's interface over implementation details.

Similarly, the Imperial College London C++ Style Guide says, "By placing the public section first, everything that is of interest to a user is gathered in the beginning of the class definition. The protected section may be of interest to designers when considering inheriting from the class. The private section contains details that should have the least general interest."

One might object that that readers should use Javadoc when trying to understand a class, and not the source code. This argument doesn't hold, however, because Javadoc includes no information regarding implementation details. When maintaining a class, a programmer clearly needs access to the source code.

For all kinds of technical documentation, it's commonplace to put high-level information at the start -- the table of contents of a book, for instance, or the abstract of an academic paper. Why should a Java class be an exception to this rule? Placing private members first just seems like a bad habit waiting to be broken. The reason it exists in the first place is likely early coding style documents, such as the Coding Conventions published by Sun. As Joshua Bloch noted, "I wouldn't take that document [Sun's Coding Conventions] too seriously. It is not actively maintained or used at Sun."

It seems best to arrange code to imitate the same order used by Javadoc: first the constructors, then non-private methods, and finally private fields and methods. That's the only style in which the reader moves naturally from a higher to a lower level of abstraction.

Conclusion

I have argued in this article that four common Java idioms should be modified. The ultimate justification for such changes is that they will make code demonstrably easier to read, understand, and use -- and, in the process, they will exhibit more compassion for the mental experience of the reader. In the case of immutability and packaging style, they will also nudge you in the direction of improved design.

In summary, I suggest that the following idioms should be favored as the preferred style:

  • Use a naming convention to distinguish three kinds of data, not two: local variables, fields, and method arguments.
  • Prefer the package-by-feature style over package-by-layer.
  • Prefer immutable objects over JavaBeans.
  • Order items in a class in terms of decreasing scope, with private items appearing last.

If the arguments presented in this article are correct, then they lead to a question: Why do harmful idioms still persist in Java programming culture, after so many years? In answer to that question, I would offer the following speculation. Style guides and other tools published in the early years of Java didn't have the benefit of long experience. They got most things right, but a few things wrong. This is completely natural, and doesn't reflect poorly on their creators. Some of these items, which were published by Sun Microsystems, were very widely imitated. They had a very strong influence, and were often treated as authoritative. Perhaps they were treated with a little too much deference.

The few harmful idioms that were created in the early days of Java have persisted because they become popular, ingrained habits -- and perhaps because of a little bit of consensus trance or groupthink, wherein the fact that something is popular or treated as authoritative often overrides any opposing viewpoint.

Will Java programming culture gradually change these bad habits, or will they persist, in spite of their defects? My guess is that, unfortunately, they will remain a part of Java programming culture. But I would love to be proved wrong!

John O'Hanley is the author of javapractices.com, and the creator of the WEB4J framework. He has been programming for 10 years, and currently lives in Prince Edward Island, Canada.

Learn more about this topic

From the archives

More ...

1 2 Page 2
Page 2 of 2