Tags

Some Golden Rules for object-oriented Java

September 3rd, 2006

There are millions of programmers and trillons of lines of code out there that use Java, but as Java is an All-purpose language, most of the code produced is procedural redump of what people did when they used C or Fortran.

I came up with a short-list of sanity checks that I use to benchmark my designs.

  1. No public method shall return null, this applies also to protected methods of non-final classes
  2. Never pass this as an argument
  3. Getters and Setters are evil
  4. A public method shall be declared by an interface (sometimes an abstract class is sufficient and more convenient)
  5. No switch / if-else if on class invariants (this includes instanceof)
  6. A class shall be either (conceptually)final or abstract
  7. No method declares a foreign exception (I am OK with some checked exceptions from the java* packages)
  8. An object that can be passed back to the API shall be immutable or a Builder
  9. Prefer delegation over inheritance (this makes 6. reasonable)
  10. The class skeleton shall fit on a single page, as do all methods (including the private methods that are used by a single method only)
  11. The number of ctors shall be much smaller than the number of instance methods
  12. All statics are in enums

This is no style-guide (most of them are a waste of time with as little impact as knowledge is required to contribute), this is what I distilled out of code that pleases me and that really works and has been proven to be maintainable and easy to integrate.
To be continued / comments and suggestions are welcome.

Actually I know of style-guide that focussed on more than indentation and the placement of whitespace: JSF air vehicle C++ coding standards

Update: I started some explainatory notes on each topic (1-6,10,11 for the moment) under Design Rules

7 Responses to “Some Golden Rules for object-oriented Java”

  1. Lou Zerr Says:

    Wow, that is a fantastic arbitrary list of OOisms. How about backing some of them up with you know, reasons and stuff?

  2. M Pufik Says:

    So, how about some *reasons* for each of these rules? That would be a bit more helpful.

  3. Tomas Says:

    Could you please elaborate on 1 and 2? For example, what is wrong with java.lang.Thread’s run method? It returns void.

  4. Ricky Clarkson Says:

    1. Why restrict this to public and protected methods? Null is a failure. You may as well remove it completely. If you really want a field to be null, try making it ‘nothing’ instead. I ported the Haskell ‘Maybe’ type to Java, see http://functionalpeas.googlecode.com/svn/trunk/src/fpeas/maybe/ - so I replace:

    private String s=null;

    with:

    private Maybe s=nothing();

    and later, s=something(”hello”);

    2. Passing ‘this’ as an argument is handy in the case of implementing the visitor design pattern, depending on how you are doing that.

    Typical implementation of accept: visitor.visit(this);

    3. Unfortunately with the profileration of beans everywhere, getters and setters are fairly necessary, I think. Maybe custom BeanInfo classes can help you get around that, but probably not easily. Personally I don’t use beans so I don’t run into this.

    I see more of a reason for getters than setters. Here is a typical value object:

    class Complex
    {
    final double real;
    final double imag;

    public Complex(double real,double imag)
    {
    this.real=real;
    this.imag=imag;
    }
    }

    This is not encapsulated. It does not pretend to be encapsulated. It is a value object, basically a tuple with named elements.

    Suppose I give this class out and people use it. Then someone (me?) wants to provide an alternative implementation that reads from a database, or lazily evaluates some mathematical expression. The original class needs changing. Changing a public API is expensive, usually more expensive than designing it to be extensible in the first place.

    Assume that requirements will change, and build in the extensibility.

    interface Complex
    {
    double real();
    double imag();
    }

    Now anyone can implement it however they choose, and I can provide an implementation too if I like. I have getters (getReal and getImag, though I didn’t say ‘get’ in the code).

    So getters are not evil, they are just a design for extensibility.

    I have my doubts as to how wise it is to expose mutable objects, or possibly even to have mutable objects at all, so I am not a fan of normal setters. However, a set method that does not change the original, but returns a new object, would be ok with me:

    interface Complex
    {
    double real();
    double imag();
    Complex setReal(double newReal);
    Complex setImag(double newImag);
    }

    setReal and setImag could go in a factory, of course, as Complex setReal(Complex original,double newReal). At first glance this looks hard to read, because you expect setReal to change the Complex number. You can get used to the idea of this not being the case though. You may choose instead to find ‘better’ names, such as withAlteredReal(double newReal).

    4. I agree with everything but the stuff in brackets: “(sometimes an abstract class is sufficient and more convenient)”

    Maybe you can come up with a rule for when you use an abstract class and when you use an interface. My rule is to always use an interface, because I find that more clear.

    5. I agree, but you probably need to stipulate what you would replace if/else/switch/instanceof with, e.g., a visitor, a strategy, for each case. Otherwise your code guide would be ignored. I know this from experience; before I knew much about OOP, I argued down a code guide at work, mainly because those promoting it couldn’t give useful alternatives. I was wrong in my conclusion, the code guide was ok, but it didn’t help me, it just told me stuff!

    7. I actually think exceptions are not very useful, as they relegate code paths to the level of an afterthought. I’d rather have something that I call instead, or in the case of the Maybe type, something that I return instead. This also helps to reduce the negative feeling about exceptions caused by the excessive syntax involved.

    E.g.,

    try
    {
    doSomething();
    }
    catch(SomeException e)
    {
    handle(e);
    }

    can be reduced to: doSomething(errorCaseHandler);

    8. The Builder itself could be immutable, and just return new objects when you call methods on it, even new instances of its own class.

    9. One problem with delegation in Java is that there is no tail-recursion optimisation, so if you have enough delegates-calling-delegates-calling-delegates, there will be a performance penalty, and possibly a StackOverflowError. I have heard vicious rumours that the IBM vms do this optimisation, but it cannot be guaranteed in normal Java. If I implemented getReal and getImag by delegating through to the original object, in the ‘Complex’ example earlier, then after, say, 20,000 ‘mutations’, I would get a StackOverflowError.

    In other languages, such as Haskell, OCaml, and probably common lisp, this would be optimised to iteration (O(n) time, O(1) space), or possibly even inlined (O(1) time, O(1) space).

    Care needs to be taken that you do not have unbounded recursion if you use composition in this way in Java.

    10. This is an arbitrary limit; you don’t even specify the length of a page.

    I used to keep lines to 80 columns, then realised that I was a) doing silly formatting tricks to keep that up, and b) avoiding useful constructs like anonymous classes.

    Code length itself isn’t that important; if you need an outline view, use the outline view in your IDE. In IDEA, it’s Alt-7 (Structure), in Eclipse it’s Window->View->Outline (or similar, I haven’t got Eclipse running right now).

    11. I actually don’t even use explicit constructors, I implement interfaces as anonymous classes. This is possibly more powerful, because I only bind as far as the name of the factory method; not even to the explicit name of the class, i.e., there is no hard binding necessary.

    12. This made me chuckle, and is probably the reason I responded!

    I hope you mean static fields. If you don’t, consider me still chuckling.

    Static methods belong in classes, rather than enums. You are only using an enum for static methods because it has a private constructor. If creating an instance of a statics-only class bothers you, you may as well add a private constructor to your class. Enums are meant for sets of values, this is clear. Personally it doesn’t bother me if someone instantiates my statics-only class, as they won’t exactly get very far with it.

    I’ve found that the more you appear to restrict someone the more they want to get around the restriction or resent you for it. For example, nobody tries to subclass an anonymous impementation of an interface, but people frequently complain about a final modifier on a named class. The results are the same, the appearance is different; that’s why I don’t bother with the private constructor. Plus, it doesn’t actually *gain* me anything, with the possible exception of clarity. I don’t like to write code that has no actual effect.

  5. Tomas Says:

    Sorry, I thought you said that no public methods should be void.

  6. Lestat Says:

    This is pretty useless without any reasons.

  7. carsten Says:

    As I prefer an active audience, I appreciate all comments, but obviously those that are constructive a bit more.

    Please note http://www.saager.org/design-rules/ that comes with some of the reasoning/examples that had been asked for. As I work full-time, I’ll complete it step by step. Latest rule elaborated at time of this writing is No. 3 (Those who cannot stand loud thinking, please skip the last paragraph there).

Leave a Reply