magpiebrain

Sam Newman's site, a Consultant at ThoughtWorks

I’m currently writing a UI layer for Naked Objects. I’m using a TDD approach and have also used the development as an excuse to give “JMock”:http://www.jmock.org/ a go. It being my first experience using a proper Mock Objects API (I have used the very handy “MockRunner”:http://mockrunner.sourceforge.net/, which Mocks application frameworks rather than objects) its been slow going at the start. Things have now started to click into place mentally and JMock is at last making some sense.

Today however I hit a really annoying problem. I’m developing a simple @FrameFactory@, who when given a @NakedClass@ will return a window showing a list of instances. The code looks like this:


public class FrameFactory {
  public FrameFactory(FactoryDependancy dependancy) {
    ...
  }

  public Component makeInstanceList(NakedClass clazz) {
    //make an instance - this is what I want to test
  }
}


Creating the @FrameFactory@ is easy – its a simple matter of creating a @FactoryDependancy@ mock and setting some expected calls on it when @makeInstanceList@ is called like so:


Mock factoryDependancy = new Mock(FactoryDependancy.class, "factoryDependancy");
//specify that we expect one call to factoryDependancy.doStuff...
factoryDependancy.expects(once()).method("doStuff").withAnyArguments();

Now I would like to do something similar to create a @NakedClass@ mock – I’ll need a @NakedClass@ instance to pass into @makeInstanceList@ when testing it. The problem is however that @NakedClass@ is @final@, so I cannot create a Mock of it (as you cannot proxy @final@ classes) nor can I create a stub implementation. This means that I have to actually create a real instance and pass that in. Strictly speaking you shouldn’t be doing this in a unit test – you want to keep your test specific to your class. The moment you start creating other instances you can end up testing them as well as your own class (in extreme cases you unit tests can end up looking like integration or even functional tests).

In of itself this is annoying, but normally not the end of the world. However @NakedClass@ has no public constructor – in fact I have to create a @NakedObject@ implementation (which ends up being a stub class) and call a static method on @NakedClass@ itself to return the instance – suddenly a simple test becomes convoluted by having to create a chain of third party objects (it is in fact a whole lot worse than this due to some NakedObject strangeness, but I’ll leave that for another day).

As you can see, @final@ classes can make testing a real problem. Developers, please think twice before putting users of your API through this kind of rigmarole!

For me, the @final@ keyword (at least as in its use on methods and classes) is the ultimate example of the lack of trust the Java architects had in the ability of Java developers. It does nothing more than stop overiding of behaviour, and what it is really saying is “I don’t trust you to change this”. In fact I know that Joshua Bloch himself distrusts the majority of Java programmers (and uses this as an excuse for a strongly typed language) one infamously stating that apart from API designers the rest of us probably don’t know what we’re doing (for more on this see my previous post, “The league of dangerous languages”:http://www.magpiebrain.com/archives/2004/04/28/league). I happen to think many of us do know what we’re doing, and those that don’t are going to find other ways to mess up even if @final@ does exist.

Advertisements

4 Responses to “final – just say no?”

  1. Doug

    One place where final classes are needed is in creating immutable value types. If the class isn’t final, someone can create a mutable subtype. This is why java.lang.String, for example, is final… it’s the only way to put immutability into its contract.I do recommend, though, that any such value type implement an (immutable) interface so that the objects can be decorated. This should also allow mock objects to be substituted, although (at least offhand) it seems to me that mocking of value types would be rather unnecessary.

    Reply
  2. R.J.

    This almost sounds vaguely like an argument against encapsulation and API formality. Although using final is, indeed, a way to restrict the behavior of an individual who is extending your component, I don’t see how that is any different really that restricting an individual who is using your component (as, for example, composition is very similar to inheritance).
    Inheritance is just another tool in the OO developers toolbag, and final is just another way to ensure that behavior from point a to point b is correct. All things considered, Can’t the same be said for private variables, constructor initialized arguments, and whatever else? Why use anything but ‘public’ for that matter? I personally rarely use the ‘final’ keyword in regards to anything but variables; there aren’t a lot of cases in the software I develop where it is completely relevant. However, I do recognize its value in ensuring the correctness of operation in context to a framework.

    In some ways it can be said that the essense of most of the architectual concepts we have in Java (and other languages) are to solve 1 of 2 problems. 1.) Complexity. 2.) External code intrusion.

    Reply
  3. Sam Newman

    This is certainly not an argument against data encapsulation – in fact I find it hard to see how Data Encapsulation can be helped by final (if you don’t want data/methods accessed via a subclass or proxy, then make them private!). API formality is a concept I admit I know little about, unless you are talking about creation of well defined API’s – again I don’t see how final applies to this, except in a situation where you are using it to enforce an API invariants.

    Some would argue that everything _should_ be public – I would not go as far, however you are being incredibly restrictive if you don’t use final carefully. The fact that String is final has never been a problem – however my problems with NakedClass being final have been made worse by virtue of the problems associated with creating instances of this class.

    Reply
  4. R.J.

    I definitely agree that over-use of the final keyword can cause problems. However, that’s a product of bad design decisions, not the feature itself. The same could be said for use of the public keyword to continue that thread.

    The reason I brought up data encapsulation (and really, this wasn’t the best choice of words because encapsulation implies protecting data from OUTSIDE influences, and an inherited member is not truly outside…) is because all too often the situations which elicit the use of the final keyword are situations where an algorithm must perform a certain way for preconditions and postconditions to be ensured safely (often in conjunction with the template method pattern, or something of the sort). I can certainly see a possibility where a method being overriden that was never intended to be swapped out could cause data corruption, therefore producing similar effects to an API that can produce corrupt data.

    I don’t see the final keyword as being the issue; more-so bad uses of the keyword.

    Also, I’ve always found it to be a tenuous line to walk when balancing ease of testing and confidence of design. It seems like often times the two conflict (primarily because testing requires some degree of visibility to data).

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Basic HTML is allowed. Your email address will not be published.

Subscribe to this comment feed via RSS

%d bloggers like this: