Friday, October 13, 2006

Road to Test Driven Developement:Part-I

Test Driven Development or TDD! A well framed buzz spawned by some agile programmers advocating extreme programming or a reality? I think it needs to be evaluated and then absorbed.Write Test, Run Test, Write Some Code, Run Tests Again, the process seems very exaggerating, over used.

Many programmers including me(though i don't write much) will be haunted by the idea of writing tests for the code we write and developing a final piece out of tests, even more dreadful.We always have cared about writing down the logic, we are just a gang of logical master minds, we don't care about documentation, beauty of the code, its maintainability.And when some body finds a bug in our system, we just yell out "How the hell it can happen"! May be its the right time for people like us to grow up..Nothing is there in this world not worth of giving a try.So I fix my head towards the road to TDD.

Writing software is like telling a good story, you design every character and every situation very carefully so that the story can go on without loosing its root( backward compatibility) and off course grow.Alike, every piece of code, every method, the flow of a project should be designed wisely.Test driven Developement is a way or we can call it a style of developing a software , it is not just how we write code but how we assemble many small pieces of code to make a complete running software that will bring smile to the customer.

TDD has been around since 2000, but it could not reach the heart of development process.Many companies still place testing after the design and development phase.Result? they pay high price for refactoring even for a small change.Some have incoorporated the style but not promoting it.We need a lion's share of the developer community to get TDD in to the main stream.

Verifying and scrutinizing the work we do plays a crucial role, we have been verified and scrutinized right from early school days.Without testing, the code which seems to work fine today may give you nightmare tomorrow and why? you will spend another week to find out.So the best and safest corner in the town is, go for "Test,Code, Test" until you succeed.But again why?

Tests saves your time, not during writing the tests but during regression period.A small change in code may break some major part.If you follow fine grained testing strategy, you can just run your unit tests and see which block busted.Refactoring you cannot avoid because customers are never happy.TDD gives you the edge, its a programming technique which ensures that your code is properly unit tested.

The most important and striking outcome that you get following test driven coding is confidence. The developers are more confident when they check in their code at the last moment of product release.Why? because they have had tested their code right to the method level for all possible disaster.Developers follow more cohesive, loosely coupled component architecture which can be easily tested with the side effect that the components can grow of their own and they can be integrated to a larger system.

And the most important things, the managers saves money! Developing a software from scratch is cheaper than refactoring it afterwards. So you pay little now or you pay huge later.

In the next part, I will try talk something useful about the approach to be taken for TDD.




Tuesday, September 19, 2006

Something about Memory Leaks:Part-II

In my last post, I talked about how WeakHashMap can be used to avoid subtle memory leaks and believe me, I did not discover anything, its all there, all know about it and still I wrote just to refresh myself and all those who are like me.So!WeakHashMap can be useful but overuse can be problematic.And infact,improper use can lead to memory leak (beginners in java like me can often make such improper use).So let us use WeakHashMap in an improper way.

Suppose we want to keep record of all the ArrayList classes that will be created during a program run, so what we do is, we register the ArrayList class with our Registry implementation whenever a new instance of ArrayList class is created. And we also want to sort the ArrayList instances according to their size in the Registry.This can be very easily done by adding an instance initializer block in the java.util.ArrayList class as below:

public class ArrayList extends AbstractList

implements List, RandomAccess, Cloneable, java.io.Serializable

{

{

Registry.register(this);

}

private static final long serialVersionUID = 8683452581122892189L;

While running the program, we can prepend this modified ArrayList class in the bootclasspath (-Xbootclasspath/p:classfilelocation), thus the java program will use this class instead of the ArrayList class in the rt.jar.We will also have to override the hashCode() and equals() methods so that equals() method now checks for reference equality and hashcode can return the System.identityhashCode().

Ok!so our Registry class will somewhat look like:

import java.util.*;

public class Registry {

public static Map collectionRegistry = new WeakHashMap();

public static void registerCollection(Collection c) {

synchronized (collectionRegistry) {

collectionRegistry.put(c, null);//we are not interested in value

}
}


public static Set getCollectionRegistrySet() {

TreeSet cSet = new TreeSet(new CollectionComparator());

synchronized (collectionRegistry) {

cSet.addAll(collectionRegistry.keySet());

}

return cSet;

}

}

Here the Collection comparator will compare according to the size of the Collections .Thus getCollectionSet() will return a TreeSet of all the ArrayList instances created so far sorted according to the size of the ArrayLists.

And we are happy using the registry and we know all about the ArrayLists created.But if we look carefully,in the getCollectionSet() method we are doing cSet.addAll(Collection c) which copies all the elements in the collection c to cSet and we are returning this TreeSet.If we look in to the WeakHashMap implementation, it makes strong references of the keys while giving the keySet so that the keys don't disappear between hasNext and next call.And the end result is cSet holds strong references to all the keys of the WeakHashMap.The code which is using this Registry has to explicitly call getCollectionSet().clear() to release the strong references.

The moral of the story is if we are using WeakHashMap.keySet() and copying it somewhere else, we loose the whole essence of weak references .The design should be strong enough to avoid such situations( Don't think of using the WeakHashMap.keySet() directly, in multithreaded environment, you will mess everything up).

One more situation I can think of but I really doubt if someone can ever use such thing .I am talking about using String literals as Map keys .Look at the code below:

public class Test

{

public static void main(String[]args)

{

WeakHashMap map = new WeakHashMap();

1: String key1= "key1";

2: String key2=new String("key2");

3: map.put(key1,null);

4: map.put(key2,null);

5: key1=null;

6: System.gc();

7: int size=map.size();

8: key2=null;

9: System.gc();

10: int newSize=map.size();

}

}

We might expect that size should be 1 in line 7 and newSize should be 0 in line 10.But what we will actually get is size=2 in line 7 and newSize=1 in line 10.How? Key1 has been nullified and we explicitly ran Full GC? Then how it is 2? The problem is not with WeakHashMap but the way Strings has been designed and implemented.Key1 in line is a compile time constant, the String object is created during compilation and the JVM keeps a Strong reference to it by keeping it in an internally maintained String pool in the class file .Thus even though key1 has been nullified, JVM still holds a strong reference to it and GC cannot collect it .But key2 will be created at runtime,so GC will reclaim the memory after nullification and WeakHashMap will remove the mapping automatically .Also, had we used key2.intern(), the effect would have been the same as for key1.So we should never use String literals as keys to a WeakHashMap and also as referent to Reference Objects.


Monday, September 18, 2006

Something about Memory Leaks:Part-I

One of the best features of java has been automatic memory management. Unlike C++, where memory has to be released manually and memory management has always been a part of program logic, java frees the programmer from this hasle.But we must understand that JVM is not so much like the Oracle of The Matrix who knows everything and every intension of the programmer .The JVM takes the responsibility to free the memory which is not in use by the program anymore but off course,when it finds so .The programmer is solely responsible to discard all the references to an object when the need expires. Thus the logical lifetime and the actual lifetime of an object must be equal. An object is created on the heap and during the execution of the program, many references are created which point to that same object,but unless and until all the references has been discarded by the program, JVM can not interfere to release the memory space although the object has no use. The leaky code below is one of such situations:


import java.util.*;

public class Registry

{

private static HashMap registry= new HashMap();

public static synchronized void register(Listener listner,Action action)

{

registry.put(listener,action);

}

public static synchronized void deRegister(Listener listener)

{

registry.remove(listener);

}

public static synchronized void broadcast()

{

Iterator itr=map.keySet().iterator();

while(itr.hasNext())

{

Listener listener=(Listener)itr.next;

listener.recieveAction(map.get(listener));

}

}

}

public class AnotherClass

{

public void doSomeWork()

{

Listener listener = new Listener();

Registry.register(listener,new Action("do something"));

Registry.broadcast();

}

public static void main(String[]args)

{

AnotherClass another = new AnotherClass();

another.doSomeWork();

}

}

In the above code, the scope of the Listener object is method level, as the method doSomeWork() completes, the Listener object should ideally become garbage collected but it will not be so.Why? Because, the Registry still has a reference to this Listener object, so if it is indeed intended that the Listener object should become garbage collected after broadcasting, the Listener should deregister itself from Registry. In other words, the programmer has to manually manage the memory allocation and deallocation of Listener object, the JVM will just guaranty that after deregistration, the object will definitely be wiped off the Heap.


This type of unintentional object retention can be quite troublesome . A common workaround for such situations is to use WeakHashMap of java's collection package.WeakHashMap keeps the keys as weak references, thus the garbage collector can claim the memory space held by an object when the only reference to the object is the key of the WeakHashMap.The above leaky code can be fixed by just replacing HashMap with WeakHashMap in the Registry class, so even if AnotherClass does not call deRegister() method, the memory can be freed as the only reference left will be the key of the WeakHashMap of the Registry Class.