Skip to main content

Are singletons just misunderstood?

In around 2002 I read the Gang of Four [GangOfFour] and discovered the Singleton Pattern [SingletonPattern]. The gang of four describe the intent of the singleton pattern as:

Ensure a class only has one instance, and provide a global point of access.

Like most green developers I thought it was brilliant and used it to hold the database connection for my application as it was expensive to create, I didn’t want to create it until it was needed and I used it everywhere (my application was poorly abstracted).

I’d been a member of the ACCU [ACCU] for a little while and had made quite a few friends there who all told me Singletons were bad. I couldn’t see the problem and continued using it happily and didn’t think the extra compile and link time (I was using C++) when I modified the singleton was a problem. Until one day, when we introduced a second database for the application and I needed another version of the same singleton.  I didn’t see at the time that I could have used one singleton to serve up both database connections, but if I had I would have soon found just how tightly coupled to the singleton’s access function my code was.

The tones of “we told you so” are still resonating eleven years later and I have avoided singletons like the plague in favour of Kevlin Henney’s Parameterise From Above [PfA], where you create an object once in one place (for example in the main method) and then pass it around your code to every other object that needs it. Of course this doesn’t ensure that there is only one instance, it relies on the understanding and discipline of the developer.  It’s served me well for many years, but there have been a few isolated occasions since where the language or library I was using has restrictions where only a singleton would allow me to achieve what I needed to achieve. Happily this has mostly been in integration test code.

At a recent Norfolk Developers [NorfolkDevelopers] I chaired a BBC Question Time like panel on software development. The questions were very much based on my own views and prejudices about software engineering, so naturally there was a question on singletons. This was the first time we’d tried this, so I assembled a panel of what I thought were safe hands and asked this question to one of the safe pair of hands accordingly. We’ll call him Richard, mostly because that was his name. Much to my surprise, what I got back was advocacy of singletons!

I discovered a long time ago that understanding context is one of the most important parts of life, especially when it comes to understanding why people say and believe the things that they do. I think back to a memory from when I was a child, of a piece of film where you see a punk barging an old man out of the way; and then you see it again from another angle and realise he’s saving the old man from a heavy falling object.

When the panel was asked: “Are singletons evil or just misunderstood?” I read out something I had prepared previously, to give a little more context, explaining that Singletons lead to tight coupling; can be difficult to instantiate in threaded environments; and that it was difficult to know when to destroy them. Richard picked up on this and asked me to read it again, which I did.

Richard explained that all of these issues, and more, can be mitigated with the use of modern techniques such as dependency injection [DependencyInjection]. Dependency injection is a method of coupling objects at runtime, rather than at compile time.  As Kevlin Henney pointed out to me dependency injection is a classic, although sometimes verbose and poorly cohesive, application of parameterise from above.

For example, an option pricing engine may get its instrument prices from a number of different sources. You might have one class that retrieves Reuters’ prices and another that retrieves Bloomberg’s prices. They share a common interface, so, the pricing class doesn’t need to know which it is using; it just needs to know about the interface. In traditional systems, determining which object to use at runtime would be done within the code.

In recent years Inversion of Control (IoC) [IoC] containers have become popular.  The main concept behind IoC is, that, the responsibility for creating objects is taken away (inverted!) from the developer and the code; and delegated to a library which constructs objects on demand.  The IoC container knows about (through its configuration) dependency chains and supplies objects with appropriate dependencies for the entire object graph being created through dependency injection. IoC containers do more than construct objects however, they manage the entire object lifecycle and clean up and destroy out of scope objects.

So, in our example, when the IoC container creates the pricing object it will see that it has a dependency on an instrument object and look at its configuration to see which instruments object it needs to create and injects into the pricing object using dependency injection.

Creating an instruments object for Reuters or Bloomberg might be an expensive and time consuming operation and it makes sense to only do it once and then inject it into other objects that need to use it. Enter the managed singleton! One of the configuration parameters you can give to an object managed by an IoC container is: singleton. This means that the container will only ever create one instance of that object.  This doesn’t of course stop someone creating another instance of the object outside of the IoC container, so it doesn’t enforce a single instance programmatically, as with the Gang of Four singleton. However, it does remove tight coupling between the singletons and their dependants.

IoC containers can usually create singletons in a thread-safe manner, which is not the same as making the singletons thread safe. The IoC also container manages the lifetime of the singletons - in fact using an IoC container seems like a pretty good solution to many of the issues associated with singletons.
Richard had changed my mind, so I decided to write about it as I felt this was quite profound, for me at least. However, now that I have written about it I am no longer convinced. I started off describing Gang of Four singletons and then how I favoured parameterise from above.

Managed singletons, as I hope I’ve clearly explained, are very different. They don’t ensure a class has only one instance and do they really provide a global access point? Ironically, in at least one IoC container implementation I know of the container itself is a Gang of Four singleton and has a static access method that must be used if you want to use an object managed by the container outside of the container. Dependency injection too is a form of ‘parameterise from above’.

Maybe common thinking has shifted from considering Gang of Four singletons alone and now managed singletons (or similar) are considered singletons too. Personally, I don’t buy this. Singletons are still dangerous and should be handled with care. Remember, always parameterise from above.

Acknowledgements

Thanks to Geraint Williams, Kevlin Henney and Richard Featherstone for their contributions to the article.

 [GangOfFour] Design patterns: elements of reusable object-oriented software by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. ISBN-13: 978-0201633610

[SingletonPattern] http://en.wikipedia.org/wiki/Singleton_pattern

[ACCU] ACCU: http://www.accu.org/

[PfA] Paramaterise from Above: http://accu.org/index.php/journals/1411, http://accu.org/index.php/journals/1327

[NorfolkDevelopers] Norfolk Developers: http://norfolkdevelopers.com

[DependencyInjection] Dependency Injection: http://martinfowler.com/articles/injection.html

[IoC] Inversion of Control: http://martinfowler.com/articles/injection.html


Comments

  1. Gang of Four was 1994 in the Smalltalk and C++ object-oriented world of the time. Many of the patterns are as valid now as then, many are not. Someone needs to write the replacement book to provide Java, Kotlin, Ceylon, Scala, Rust, C++, D, Go, Python, Ruby, Groovy, Clojure, etc. contexts.

    ReplyDelete

Post a Comment

Popular posts from this blog

Write Your Own Load Balancer: A worked Example

I was out walking with a techie friend of mine I’d not seen for a while and he asked me if I’d written anything recently. I hadn’t, other than an article on data sharing a few months before and I realised I was missing it. Well, not the writing itself, but the end result. In the last few weeks, another friend of mine, John Cricket , has been setting weekly code challenges via linkedin and his new website, https://codingchallenges.fyi/ . They were all quite interesting, but one in particular on writing load balancers appealed, so I thought I’d kill two birds with one stone and write up a worked example. You’ll find my worked example below. The challenge itself is italics and voice is that of John Crickets. The Coding Challenge https://codingchallenges.fyi/challenges/challenge-load-balancer/ Write Your Own Load Balancer This challenge is to build your own application layer load balancer. A load balancer sits in front of a group of servers and routes client requests across all of the serv...

Catalina-Ant for Tomcat 7

I recently upgraded from Tomcat 6 to Tomcat 7 and all of my Ant deployment scripts stopped working. I eventually worked out why and made the necessary changes, but there doesn’t seem to be a complete description of how to use Catalina-Ant for Tomcat 7 on the web so I thought I'd write one. To start with, make sure Tomcat manager is configured for use by Catalina-Ant. Make sure that manager-script is included in the roles for one of the users in TOMCAT_HOME/conf/tomcat-users.xml . For example: <tomcat-users> <user name="admin" password="s3cr£t" roles="manager-gui, manager-script "/> </tomcat-users> Catalina-Ant for Tomcat 6 was encapsulated within a single JAR file. Catalina-Ant for Tomcat 7 requires four JAR files. One from TOMCAT_HOME/bin : tomcat-juli.jar and three from TOMCAT_HOME/lib: catalina-ant.jar tomcat-coyote.jar tomcat-util.jar There are at least three ways of making the JARs available to Ant: Copy the JARs into th...

RESTful Behaviour Guide

I’ve used a lot of existing Representational State Transfer (REST) APIs and have created several of my own. I see a lot of inconsistency, not just between REST APIs but often within a single REST API. I think most developers understand, at a high level, what a REST API is for and how it should work, but lack a detailed understanding. I think the first thing they forget to consider is that REST APIs allow you to identify and manipulate resources on the web. Here I want to look briefly at what a REST API is and offer some advice on how to structure one, how it should behave and what should be considered when building it. I know this isn’t emacs vs vi, but it can be quite contentious. So, as  Barbossa from Pirates of the Caribbean said, this “...is more what you’d call ‘guidelines’ than actual rules.” Resources & Identifiers In their book, Rest in Practice - Hypermedia and Systems Architecture (‎ISBN: 978-0596805821), Jim Webber, Savas Parastatidis and Ian Robinson describe resour...