Monday, May 11, 2015

Writing Scalable Code Using Inheritance in Java part 2

In my last post I mentioned a few simple rules on how to write maintainable code using inheritance:
  1. Reduce method and member scope
  2. Use final for methods and members
  3. Make make overridable methods abstract
  4. Don't make deep inheritance hierarchies
Today I want to show you how this affects maintainability.

Let's imagine we see a method like this in a class we know has many subclasses:

public final int getFoo() {...}

Here the presence of the final tells us that that we don't need to worry about anyone over-riding the behavior. Which is nice. 

public abstract int getFoo();

This one tells us sub classes *must* override this method. So we know that every sub class defines what we must do here. If we're in luck we'll be able to refactor this into a composition using the strategy pattern.

public int getFoo() {...}

This is problematic because we don't know whether there is subclass overriding this so we need to check all subclasses before we can modify its implementation. 

If we want to over-ride this method in a subclass we need to check the superclass to make sure that it doesn't have any side effects or being called at an unexpected time. Since it's a getXXX() method, it shouldn't be doing any side effects.

protected final int calculateFoo(...) {...}

This method can be accessed by itself and sub classes but not-over-ridden by sub classes. This method is probably part of an API offered to sub classes for them to call.

protected abstract int calculateFoo(...);

This method can be accessed by itself and sub classes and *must* be overridden by sub-classes. If we're in luck we'll be able to refactor this into a composition using the strategy pattern.

protected int calculateFoo(...) {...}

This is ambiguous. It might be a method that should be used as an API or it might define behavior like in the Strategy pattern. A third alternative is that it is meant to be over-ridden by sub-classes but provides a default implementation. Given the ambiguity I recommend adding a comment like this if it's the third case:

protected int calculateFoo(...) {
    /* Can be overriden by sub classes
     * default implementation: calculates foo using the bar algorythm 
     */
    ...
}

Although, again, using the strategy pattern with a default strategy is often the best way to go.

private something() {..}

It can only be called in this subclass and can't be overriden so we're good.

public int foo;

Don't do that unless it's final, the class is final and your object doesn't have any methods in it. Something like this:

public final class Foo {
  public final int foo;

  public Foo(int foo) { this.foo = foo }
}

This is a standard best practice.

protected final int foo;

Don't do this.

protected int foo;

Don't do this either.. but more so.

Next week: how to brush your teeth!

Sunday, May 10, 2015

Writing Scalable Code Using Inheritance in Java

Everyone should be familiar with the old advice that you should favor composition over inheritance. However, what if you find yourself in a situation where inheritance is the best tool for the job? There are a few things you can do to keep your code maintainable.

Before we get into that I should explain a little about why you should favor composition over inheritance. Imagine you're trying to understand a class called Smilly. This class is detailing the behavior of a computer sprite in the award winning (in my mind) game Space Smilies. You're trying to figure out how this is implemented. The class is many lines long so it's obviously doing something something fancy. You notice that it inherits from a class called EvilThing. EvilThing extends from ComplexComputerSprite. This class extends ComputerSprite which extends AbstractSprite. All member variables are accessible from all subclasses. Where to start?

Making a member variable protected means it's accessible to all sub-classes. Any one of these sub classes can read an write to them. You need to understand how the class and all the parent classes interact to create the desired behavior. Just as making a member as public is bad practice because to understand who is modifying that public variable you need to track down every piece of code that uses it, using protected members in a complex hierarchy is bad for the same reasons.

This also applies to protected, non-final protected and public methods but it worse from the point of view of modifying the parent class. In order to understand if modifying a public or protected method will accomplish the desired behavior you need to understand the entire object hierarchy because there's no telling if one of the sub-classes has over-ridden any one of the public or protected methods and many make assumptions about how the class operate. If you stomp on one of its assumptions you'll cause a bug.

Understanding the entire class hierarchy and how each class works with its parent is labor intensive to say the least.

Because any method can be over-ridden anywhere in the hierarchy and because any state variable can be used by any subclass it means you have to be meticulous about checking every class in the hierarchy for unexpected overrides. With inheritance it's very easy to create a hierarchy that's so interconnected that you need to understand how everything works before you can understand any part of it. You might have an object composed of many classes but the classes over-ride each other's behavior in such a way that it effectively creates one big coupled class out of many.

Composition, on the other hand, makes it easier to create and maintain encapsulation and lower coupling. It's easier to control which members and methods are accessed and there's no invisible over-riding of behavior to trip you up. Methods that are public make up the object's external interface. Simple as that. (Assuming the normal best practice of trying to hide your member variables and implementation inside by making them private).

Composition is not as powerful as inheritance, however, so you might not be able easily do what you want using only composition. Which goes back to our original question, what do you do if inheritance is the right tool for the job? What if you need the power?

Java has a few tools to help you out in the form of the keywords abstract, protected, private and final.

If you find yourself with a sprawling inheritance hierarchy you can help out yourself and any future maintainer by:


  1. Reducing scope: If it can be made private then make it private. If it can't be made private then make it protected.
  2. Adding final: If a method can be made final then make it final. It's one less method that can have sneaky override or one less variable that can be modified.
  3. Make methods that *should* be overridden abstract: In complex objects it's more explicit to have all your overridable methods marked abstract so that's it's clear that subclasses need to implement these.
  4. Don't make deep inheritance hierarchies. The rule I use is a class's true size includes all it's parent classes all the way up to java/lang.Object.

to be continued...