Lessons learned in Software Development (2) – Abstraction

Long ago during our weekly tech meeting @ Therap, we had this intriguing discussion, “What is the most crucial skill for a software developer?”. It was quite interesting to see how different people at different skill level had different opinion about the topic. I remember my answer was “Algorithm” (Back then I was into solving ACM style problem). Other inputs were “Language”, “Communication”, “Optimization”, “Clean Code” etc. However, we all agreed finally that it was “Design skills” that matters most.

My view on this topic also changed from time to time as I grew older and played different roles. I tried to master java (with two java certification under my belt) when I thought language was the most important, I memorized all design patterns from GOF books and tried to apply them when I thought design was the most important one.

Well now a days, I feel like I got the bigger picture. I think it is the power of “Abstraction” that can turn you from a good Software engineer to a Great one. You can find the importance of abstraction everywhere. When we were tought object oriented design at our schools, we first relate the word “Abstraction” as one of the three attributes of Object Oriented Programming. Well, it has much bigger meaning than that. Abstraction is not only part of  detailed design or Object design, Its the most important part when you want to architect big systems.

When I started my career, I used to get overwhelmed by big problems, big tasks, big projects. I tried to address them all together and made a mess of things. Now a days, I try to apply abstraction in such scenarios. Whenever I get big problems, I try to divide them into smaller pieces. “Divide and conquer”–Thats the trick. If you can abstract away the smaller problems and focus on the big picture, at the end of the day, you are going to achieve the big goal. If you are working in a team, you can put your team members to work with each of the abstractions.

I am not going to talk about the Abstraction @ code level. There are enough materials on them. But here is the key, If you can abstract away the components/responsibility/code, you will always be safe from big disaster and achieve the bigger goal.

Domain Driven Design : Sample Application Released!

If you haven’t heard about Domain Driven Design, dude! Its high time you catch up. If you liked the concept, and wonder how to implement it in your spring app, here comes the Sample Application implementing the famous Cargo application from the DDD Book. And the best part is, the DDD guru Eric Evans is the main developer! I have been looking for it for a long time and can’t wait for my maven to finish compiling the code!

Thinking in Objects

Long ago, I had to write some code which do this:

Given two list 1. oldList 2. newList you have to find out:
1. The elements which are common in both list.
2. The elements which are new in the newList (means they were added)
3. The elements which are in oldList and not in newList (means they were deleted)

Definitely not the hardest kind of problem! I quickly grabbed my keyboard and wrote something like this :

public class CollectionModificationHelper {
public static List getCommonElements(List oldCollection, List newCollection) {
//iterate on oldCollection and find the common elements
}
public static List getNewElements(List oldCollection, List newCollection) {
//iterate on newCollection and find the new elements
}
public static List getRemovedElements(List oldCollection, List newCollection) {
//iterate on oldCollection and find the deleted elements
}
}

Simple solution and works fine. Only problem is, its iterates over the same collection again and again to find the old/common/new elements, not a big deal if you are not worried about performance.

Yesterday, I had to write the same code! Almost 4 years after I wrote the first version, seeing a hell lot of code, reading a hell lot of materials about Object Oriented Programming and design, this is what I wrote:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

import org.apache.commons.collections.CollectionUtils;

public class CollectionModificationHelper<T> {
	private Collection<T> oldCollection;
	private Collection<T> newCollection;
	
	private Collection<T> newElements = new ArrayList<T>();
	private Collection<T> commonElements = new ArrayList<T>();
	private Collection<T> removedElements = new ArrayList<T>();
	
	public CollectionModificationHelper(Collection<T> oldCollection,
			Collection<T> newCollection) {
		super();
		this.oldCollection = oldCollection;
		this.newCollection = newCollection;
		
		init();
	}
	
	public CollectionModificationHelper(T[] oldArray, T[] newArray) {
		this((oldArray ==  null ? null : Arrays.asList(oldArray)), (newArray == null ? null : Arrays.asList(newArray)));
	}

	private void init() {
		if(CollectionUtils.isEmpty(oldCollection) && CollectionUtils.isEmpty(newCollection)) {
			//nothing to do!
		} else if(CollectionUtils.isEmpty(oldCollection)) {
			if(!CollectionUtils.isEmpty(newCollection)) {
				this.newElements = new ArrayList<T>(newCollection);
			}
		} else if(CollectionUtils.isEmpty(newCollection)) {
			if(!CollectionUtils.isEmpty(oldCollection)) {
				this.removedElements = new ArrayList<T>(oldCollection);
			}
		} else { 
			
			for(T item : oldCollection) {
				if(newCollection.contains(item)) {
					commonElements.add(item);
				} else {
					removedElements.add(item);
				}
			}
			
			newElements.addAll(newCollection); //first add all new Collection in new element. 
			newElements.removeAll(commonElements); //then remove the common elements.
		}
	}

	public Collection<T> getCommonElements() {
		return commonElements;
	}

	public Collection<T> getNewElements() {
		return newElements;
	}

	public Collection<T> getRemovedElements() {
		return removedElements;
	}
}

Its interesting to see how your thought process changes over time. As far as I my opinion goes, the 2nd solution is much elegant than the first one! In the first one, I was just not thinking in Objects!

Over the years, as you are involved in serious development, you will surely learn many technologies, tricks, techniques. But I think you must thrive to learn how to think in Objects. Once you can achieve that, you will find a whole new world of idea about how the objects/components should interact. Once you are there, you will love it. I am not saying I am there already, but I sure did come a long way from where I started and trying to master it everyday. How do you prepare yourself? Practice & Read. My two best guru in this area are both named “Martin”! “Robert C. Martin” & “Martin Fowler” 🙂 Do have a look at their work if you haven’t already.

Lastly, what code is good code without some unit tests!


import java.util.Collection;

import junit.framework.TestCase;

public class CollectionModificationHelperTest extends TestCase { public void testWithNullCollections() {  Integer[] old = null;  Integer[] newC = null;

  CollectionModificationHelper&lt;Integer&gt; collectionModificationHelper = new CollectionModificationHelper&lt;Integer&gt;( old, newC);

  assertEquals(0, collectionModificationHelper.getCommonElements().size());  assertEquals(0, collectionModificationHelper.getNewElements().size());  assertEquals(0, collectionModificationHelper.getRemovedElements().size());

  old = new Integer[]{1,2,3,4};  newC = null;

  collectionModificationHelper = new CollectionModificationHelper&lt;Integer&gt;( old, newC);  assertEquals(0, collectionModificationHelper.getCommonElements().size());  assertEquals(0, collectionModificationHelper.getNewElements().size());  assertEquals(old.length, collectionModificationHelper.getRemovedElements().size());

  old = null;  newC = new Integer[]{1,2,3,4};

  collectionModificationHelper = new CollectionModificationHelper&lt;Integer&gt;( old, newC);  assertEquals(0, collectionModificationHelper.getCommonElements().size());  assertEquals(newC.length, collectionModificationHelper.getNewElements().size());  assertEquals(0, collectionModificationHelper.getRemovedElements().size()); }

 public void testCollectionModificationHelper() {  Integer[] old = new Integer[]{1,2,3,4,5,6,7};  Integer[] newC = new Integer[]{1,4,10,11,12,13};

  CollectionModificationHelper&lt;Integer&gt; collectionModificationHelper = new CollectionModificationHelper&lt;Integer&gt;( old, newC);

  Collection&lt;Integer&gt; commonElements = collectionModificationHelper.getCommonElements();  Collection&lt;Integer&gt; newElements = collectionModificationHelper.getNewElements();  Collection&lt;Integer&gt; removedElements = collectionModificationHelper.getRemovedElements();

  System.out.println("commonElements: "   commonElements);  System.out.println("newElements: "   newElements);  System.out.println("removedElements: "   removedElements);

  assertEquals(2, commonElements.size());  assertEquals(4, newElements.size());  assertEquals(5, removedElements.size()); }}