Controlling GC and Improving Unit Testing through Factories

October 13, 2008

So I was looking at design patterns and read across the factory pattern and the pooling pattern. I know what both of those do independently but never considered them together and as a result, my mind started racing with ideas. One of the many problems with applications in terms of performance is garbage collection. Pooling helps to solve this problem by reusing objects that have been released back to the pool. One of the big problems with unit testing is testing classes in pure isolation by properly injecting mock objects that are dependencies of the class under test. IoC helps to resolve this issue by injecting code into classes. However, you still have to at times use ‘new’ to create objects. This causes three big issues. First, the VM has to create a new object, initialize it, and add it to the stack. This is an expensive task. Second, you put dependency into the code. Further, if you utilize pooling you add yet another dependency (think coupling here). Third, using new does not allow you to truly run code in isolation as your class under test is not invoking code on another object without being able to use a mock instance.

So, how can you solve these problems, you ask, and what do they have to do with factory and pooling design patterns? Well, let’s go back to my initial remark on the factory and pooling design patterns. First, we will talk about the factory design pattern. A factory design pattern is simply a class that loads or creates other classes. That is exactly what we want to do. Further, this allows us to do a few things. First, it abstracts how an object is created and lets you add custom handling to any type of object by simply using a different factory. This helps to reduce other less performance-based solutions such as AOP or adapters and wrappers. Second, it removes the usage of the new operator so that you can easily mock the class under test in pure isolation by registering mock objects with the factory. Third, it promotes loose coupling by not having classes worry about pooling, initialization, etc. POJOs only depend on the Factory as a simple static object. With that said, let’s look at some examples to further clarify.

First, let’s create the Factory class to manage the handling of objects.

public final class Factory

{

private FactoryHandler _handler;

private Factory() { super(); }

public static <T> T create(Class<T> type, Object… params)

{

this._handler.create(type, params);

}

public void remove(Object object)

{

this._handler.remove(object);

}

}

Second, let’s define that FactoryHandler interface being used by the Factory class.

public interface FactoryHandler

{

boolean supports(Class<T> type);

<T> T create(Class<T> type, Object… params);

void remove(Object object);

}

Looking at this code, we have the following. First, Factory is a very simple class, which we ideally want. In practice static classes are seen as bad due to their unit testability and dependency handling. By reducing the amount of code, we can easily handle these issues by placing the real work in external delegate classes. So essentially, all the Factory does is delegate its work to an actual FactoryHandler. How is that handler initialized? We have two popular options: IoC and META-INF services. First, if you have a IoC container available (such as Spring), you can register the handlers within spring and inject into the factory via a static method invocation. As a result, production code can use spring IoC and unit tests can use a mock handler. The other option, if Spring is not available, is to use META-INF services or factory finder interfaces to locate a particular handler. This code would be used within Factory to access the service. Thus, production would register a production service and unit tests would register a mock service. In any sense, we keep the code in Factory to minimum with little dependencies. The handlers provide the actual work and can do any number of options.

As an example, the base handler would be a composite handler, as seen below, that would register a set of handlers. Whenever the composite handler is invoked, it would invoke the first matching handler for any object that supports the given class.

public void CompositeFactoryHandler implements FactoryHandler

{

private List<FactoryHandler> _handlers;

public <T> T create(Class<T> type, Object… params)

{

foreach (FactoryHandler handler : this._handlers)

{

if (handler.supports(type))

{

return handler.create(type);

}

}

return null;

}

}

Another example would be a chaining handler that chains together classes by passing each created instance to the next chain. Other examples would be a pooling handler that selectively creates pools for given classes or a caching handler that caches classes similar to a pool. We could even create a web service handler that accesses an instance through a web service. The limits are infinite, but yet the underlying code never changes. To the base code, it is just as simple as going from new Type(param) to Factory.create(Type.class, param).

Now that we have a factory and a method for registering custom handlers, how do we use it? The simple solution is just as easy as:

MyClass instance = Factory.create(MyClass.class, ‘str’, 5, true);

// do stuff with instance

Factory.remove(instance);

The remove statement is not explicitly required, unless a pooling handler is utilized in which case remove would return the object to the pool. However, note that other methods could be used such as an OpenFactoryPooledObject filter that returns all created instances during a particular request to the pool. Another idea would be to use SoftReferences to let the pool grow infinitely and then reduce when memory is needed. Also, one could use CGLIB proxies and include reference counting to know when to remove/return an object to the pool.

Using this type of method we can now change how any type of object gets created. For example, if we notice that we are creating too many objects of a particular type (thus affecting performance and GC), we can simply add a custom factory handler for that type to use the pooling service. The underlying code (including unit tests) do not change at all, only the adding of the plugin to the list of supported handlers. Often times, when using an IoC container, this is as simple as a configuration change.

So, we have talked about performance implications, let’s change gears to the second half of the discussion and talk about unit testing. So, how does this truly help unit testing: quite easily in fact. First, let’s define the ideal test environment. The ideal test is to invoke only methods on the class under test without indirectly invoking other dependent code. The reason for this is to really test individual units of code without impacts from other code/changes and to avoid the indirect class invocations from affecting code coverage numbers. To fully support pure isolation of class under tests, we utilize mock objects for the created instances. Thus, if we have code such as:

public void printHelloWorld()

{

return Factory.create(HelloWorld.class).print(System.out);

}

We can unit test that without having to actually create a HelloWorld by utilizing:

public void testPrintHelloWorld()

{

Mock<HelloWorld> mockHelloWorld = mock(HelloWorld.class);

mockHelloWorld.expects(once()).method(“print”);

Factory.register(HelloWorld.class, mockHelloWorld.proxy());

this._instance.printHelloWorld();

}

And just like that we have tested in pure isolation and changes to HelloWorld will not directly impact this unit test example. This is obviously a very simple example. However, consider a case where you want to use pooling. In a normal case, you would have the pooling code to borrow and return the object. To unit test that, you now have to mock the pooling code, not to mention the coupling to the pooling code. What if we also wanted to wrap that particular instance with an adapter? The code quickly becomes complex and forgets its original intent or purpose. By using the factory, we remove those dependencies, we let POJOs serve their specific purpose, and we can easily unit test code without having to worry about registering pools, plugins, etc.

There are prolly some who would say that using this type of methodology can be easily solved by using IoC everywhere and injecting every type of object. However, that is not always possible either because there is no IoC container available, the created object has a very short lifespan and IoC would only add uneeded complexity, etc. No matter how you look at it, you will find you need to directly create objects at some point, especially when it comes to pooling. In fact, I do not consider this a replacement for IoC. Rather, the two work seamlessly and powerfully together. By using IoC to inject the various factory handlers, we have simple factory code and leave the configuration to the spring config files and plugin classes. This design also supports AOP or CGLIB proxying by allowing objects to be proxied by a custom handler that instantiates and then wraps the target object.

Finally, in order for these solutions to really work, developers would need to ensure that (1) they do not use any static method invocations and (2) they do not use ‘new’ to instantiate objects. Instead, they use the single allowed Factory to instantiate objects. To automate this task in order to cause build failures, one could utilize PMD or Checkstyle to define a custom rule.

Thus, using this mechanism, we now have cleaner code, looser coupling/fewer dependencies, better unit testing, and improved performance capability by allowing handlers to be instantly added/removed such as pooling without affecting the code. The code is only written to perform the task it is meant to perform, rather than having to manage external dependencies such as pooling.

Comments are closed.