Learn to Stop Worrying and Love the Singleton
Posted on 28. Jan, 2011 by Admin in Intermediate, Phone Calls
Dependency injection and early validation is crucial for an enterprise application, and Spring is a boon in this regard. But do not fool yourself, Spring is good, but it is not a universal cure. Especially not in mobile space where startup times, low memory consumption, and avoiding interfaces are virtues.
The bottleneck in an enterprise application is most probably the database, spending a few extra milliseconds here and there seldom matters. On much less performant mobile device those clock cycles are not only time the user has to spend waiting, it will drain the battery. A simple thing as using an interface instead of an abstract superclass will perform at least twice as slow. Even passing an extra argument in the constructors a few nestings deep will have an impact.
Lazy Singeltons by Choice
Class loading in Java is lazy, the Java VM will not load classes until they are referenced. Odds are that the user will not trigger a full coverage of all classes in your app for a short time running mobile app. If the user just checks for incoming messages and quits, then every class involved in composing messages do not need to be loaded. Early dependency injection breaks this, as all classes will be referenced at startup. Most components will be initialized in vain, as they are never actually used.
So what we should do in mobile application is to work more like the Java VM, and less like Spring. If possible do not create a component until it is requested. The best way to do this is using a singleton pattern. Not a normal enforced singleton pattern, but rather a singleton by choice. Let the constructor be public, trust your users, and name the getter getSharedFoo(), not getInstance(). Let me show you using a example of an URL cache component:
public class URLCache {
private static URLCache sharedCache;
public static URLCache getSharedURLCache() {
synchronized (URLCache.class) {
if (sharedCache == null) {
sharedCache = new URLCache();
}
}
return sharedCache;
}
public URLCache() {
// More code...
}
// Allot more code here...
}
Using this shared URL cache component from our imaginary HTTP provider would then be super easy, but not mandatory:
public class HTTPProvider {
public InputStream inputStreamForURL(String url) {
URLCache cache = URLCache.getSharedURLCache();
// Use the cache...
}
}
The big win here is that if the code path of this run of the application never tries to open an input stream then the URL cache never has to be created. Saving several hundred milliseconds of reading cache indexes, validation, etc.
But What About Testing?
Are not singletons bad for unit tests and mocking components? They used to be. These days we have PowerMock, you really should use it. Turns out that not even PowerMock is really required, if we just change our singleton pattern very slightly, and allows the outside to set the shared component as well:
public class URLCache {
private static URLCache sharedCache;
public static void setSharedURLCache(URLCache cache) {
synchronized (URLCache.class) {
sharedCache = cache;
}
}
public static URLCache getSharedURLCache() {
synchronized (URLCache.class) {
if (sharedCache == null) {
sharedCache = new URLCache();
}
}
return sharedCache;
}
// Allot more code here...
}
This small addition allows us for setup up our own mock cache in the setup of our unit tests. With something as simple as this:
public class SomeTest extends TestCase {
public void setUp() {
URLCache.setSharedURLCache(new NoOpURLCache());
}
public void testRemoteResource() {
assertNotNull(HTTPProvider.getSharedHTTPProvider().inputStreamForURL(TEST_URL));
}
}
It also allows us for explicitly override a singleton if our application has special needs, perhaps a more aggressive cache on a low bandwidth mobile data connection, or special implementation on a buggy Java ME platform. But most importantly for the normal case it will not waste time creating the component until it is actually needed, vastly improving the user experience for your mobile users.
Take Aways
Do not fear singletons, it is a great way of lazy creations that will greatly improve startup times and memory consumption on mobile applications.
Avoid using interfaces, they are at least twice as slow as classes, and can not have static methods for acquiring the lazy created components.
Do not enforce the singleton pattern, always use singleton by choice. To allow for testing and easy implementation of special cases.




