Simplify your API – Can Singletons be used for Good, not Evil?

I recently wrote an article about singletons in java. The only thing I wanted to cover was that if you really want a singleton, I recommend you use the enum pattern. This post was motivated after more interesting comments were raised about testability when you see the “static” keyword.

When you type “static” a little alarm bell should ring in your head to warn you that there could be trouble ahead. As Dan correctly pointed out, a reference to the static member INSTANCE will tightly couple the caller to Elvis. This is not good if testing with Elvis will cause you problems. For example, if Elvis is slow, or accesses a database or something like that which would be better tested with a mock implementation.

However, sometimes the static keyword makes sense because it is an implementation detail that you are not concerned with. By you I mean a client of the code. Why muddy an API so that you can pass around objects that will never change. To illustrate my point, I wrote a very simple bit of code that hopefully isn’t too contrived.

Imagine you have to write a computer system for a Blackpool nightclub called “Elvis Live!”. This club has a different Elvis impersonator on every night. The system has to manage the bookings of the different Elvis impersonators and print the posters which list which impersonators are performing each night.

In my very simple implementation I wrote a class to represent the club:
ElvisClub.java

package uk.co.mattburns.elvis;
import java.util.Map;
import org.joda.time.LocalDate;
import com.google.common.collect.Maps;

public class ElvisClub {

    private final Map bookings = Maps
            .newTreeMap();

    public boolean bookImpersonator(LocalDate date,
            ElvisImpersonator impersonator) {
        if (bookings.containsKey(date)) {
            return false;
        } else {
            bookings.put(date, impersonator);
            return true;
        }
    }

    public ElvisImpersonator getImpersonatorOnDate(LocalDate date) {
        return bookings.get(date);
    }

    public String getPosterTitle() {
        return "Keeping The King Alive since " + Elvis.INSTANCE.died();
    }

    public String getPosterBody() {
        StringBuilder stringBuilder = new StringBuilder();
        for (LocalDate date : bookings.keySet()) {
            ElvisImpersonator act = bookings.get(date);
            stringBuilder.append(date.toString() + " : See " + act.name());
            stringBuilder.append(" who was born " + act.yearsBornAfterElvis()
                    + " years after Elvis");
        }
        return stringBuilder.toString();
    }
}

A simple pojo to represent a performer at the club:
ElvisImpersonator.java

package uk.co.mattburns.elvis;
import org.joda.time.LocalDate;

public class ElvisImpersonator {

    private final String name;
    private final LocalDate birthdate;

    public ElvisImpersonator(String name, LocalDate birthdate) {
        this.name = name;
        this.birthdate = birthdate;
    }

    public String name() {
        return name;
    }

    public LocalDate birthdate() {
        return birthdate;
    }

    public int yearsBornAfterElvis() {
        return birthdate().getYear() - Elvis.INSTANCE.born().getYear();
    }
}

Crucially, both of these classes have a dependency on Elvis. I decided to make Elvis a singleton:
Elvis.java

package uk.co.mattburns.elvis;
import org.joda.time.LocalDate;

public enum Elvis {
    INSTANCE;
    private final LocalDate born = new LocalDate(1935, 1, 8);
    private final LocalDate died = new LocalDate(1977, 8, 16);

    public LocalDate born() {
        return born;
    }

    public LocalDate died() {
        return died;
    }
}

You can browse all the source code here. Or better still, checkout the code and simply import the project into eclipse:

svn checkout http://elvis-club.googlecode.com/svn/trunk/ elvis-club-read-only

 

I already know what you’re thinking:

Elvis.java should be an interface: Celebrity.java. Then I could have a concrete Elvis to pass around which implements Celebrity.

ElvisImpersonator.java should be an interface: Impersonator.java. Then I could write a CelebrityImpersonator.java which would take a Celebrity on construction.

That is one way of solving it, and it’s not a bad way. I agree that you should expect change, embrace it, marry it, have its babies, but don’t start writing code for it before it’s happened. One day the club may have a Marilyn Monroe night and in that case you anticipated change beautifully luckily. What if it changes into a comedy club? How about a restaurant?

What’s really important is writing code that’s easy for programmers to read, and therefore, easy for programmers to change.

Here is a snippet from some of my test code which gives you an idea of what I mean:

ElvisClub theClub = new ElvisClub();
LocalDate today = new LocalDate();
LocalDate brianBorn = new LocalDate(1970, 1, 1);
ElvisImpersonator brian = new ElvisImpersonator("Brian", brianBorn);
theClub.bookImpersonator(today, brian);

A similar snippet, without using the Elvis singleton would look something like this:

LocalDate brianBorn = new LocalDate(1970, 1, 1);
LocalDate elvisBorn = new LocalDate(1935, 1, 8);
LocalDate elvisDied = new LocalDate(1977, 8, 16);

Celebrity realElvis = new CelebrityImpl("Elvis", elvisBorn, elvisDied);
Impersonator brian = new CelebrityImpersonator("Brian", realElvis, brianBorn);
Club theClub = new Club(realElvis);
theClub.bookImpersonator(today, brian);

There’s not a massive difference but I still think the constructors are a bit “noisy”. In a real-world application, you would probably expect references to a more complex set of collaborating objects.

I haven’t sacrificed any testibility of my code. If anything, I’ve reduced the amount of code I need to test. My way, there can only be Elvis and so I only need to test that the club handles things to do with Elvis. If I wrote a more generic version I would have to test that it handles Celebrities that are still alive, that they were born before they died, and so on.

I think I’m right but I’ve changed software design views pretty frequently over the last 10 years. If you think I’m wrong, I challenge you to convince me why…

2 thoughts on “Simplify your API – Can Singletons be used for Good, not Evil?”

  1. I’m wary of saying one should *never* do X, as doing so often far better demonstrates your own limitations than any real problems with X. Nevertheless I have to say that I’ve lived quite happily without singletons for several years now and I’m afraid that neither this nor the last post have made me long for them again.

    There’s even a delicious irony in that, over the two articles, you’ve tried to press gang an enum into service as a singleton, only to end up with a singleton that looks really rather like an enum! Your Elvis object is an excellent representation of the real thing: like the real Elvis it has some attributes that will never change and like the real Elvis it doesn’t do a lot because the real Elvis is, well, dead. I regularly write enums that do much the same (that is to say, they just store a bit of state, not that they die). If this is a singleton then I don’t have any problem with it.

    I do have a problems with what you might call behavioural singletons, however. Once you’ve hooked up with a singleton that does things, you’ll be doing things his way forever after. Want to unit-test the code that depends on that database singleton? Well you’d better have a database handy then. Want to run those tests as part of an overnight build? Brace yourself for a lot of spurious test failures every time the database has a bilious attack. Want your code to get its data from somewhere other than that miserable, stinking database? Ha – forget it!

    As you say, the moment you try to unit test a piece of code like this, you’ll most likely realise that the singleton’s giving you gyp and remove it. But this only leaves me wondering why you’d use the bloody thing in the first place. Have we hit the limits of singletons with Elvis, or do you think there’s life in the old goat yet?

  2. I know I’m on shaky ground but you haven’t convinced me yet. Like you I also lived without singletons for years and didn’t miss them. Since reading the Effective Java book I questioned why I thought singletons were bad and concluded I could use them again without feeling guilty.

    Just to clear up the terminology a bit, you mention you use enums to “store a bit of state”. By which I assume you mean that they have attributes. It’s important to note that a singleton that has a “state” in the sense that that state could change, would suck. No, let’s make it clear, a singleton that is mutable would be pure evil. If Elvis had methods called “startDancing()” and “stopDancing()” or even any references to mutable objects then you can expect trouble ahead. A singleton that has references to a database is obviously a bad design.

    Here’s a post from the Google testing blog that largely agrees with your point but does briefly mention that the real trouble with singletons comes when you allow mutability.

    Elvis is allowed to have behaviour, methods that do stuff, just not methods that change Elvis’ state. For example, this would be ok:

    Elvis theKing = Elvis.INSTANCE;
    SimilarityScore briansScore = theKing.rateImpersonator(brian);
    

    A common argument against the use of singletons is that you do not declare your dependence on the singleton in your API. If an object requires an Elvis then the argument is that it should be declared in the constructor. Clients of your object then know that you need an Elvis to work. My argument is that sometimes, the use of the singleton in none of the API’s beeswax, it’s an implementation detail. You wouldn’t expect an object to be constructed with pi.

    I think the singleton is a good way to represent something that exists only once in the universe, and never changes. Like Elvis.

Leave a Reply

Your email address will not be published. Required fields are marked *