{ by david linsin }

February 23, 2009

JUG-Ka Stammtisch 2.0

The second Stammtisch of Java Users Group Karlsruhe will be held on Thursday 26th of February. We will meet up at Marktplatz around 8pm to find a suitable location. If you'd like to join the geek chat about Java, check out the Google Group for further details or drop me an email.

NOTE: Over the next few weeks, I'm moving my feed from feedburner back to blogspot so please subscribe to http://dlinsin.blogspot.com/feeds/posts/default/ instead!

February 18, 2009

An Aspect is Part of Your Implementation

When implementing parts of your application with AOP, you are magically applying additional behavior to your code. Although technically cool and in terms of reusability great, it might lead to a maintenance nightmare.

Think of an API, let's call it CustomerService. It defines CRUD methods to load and save Customer instances from some backend service. It might define methods like the following:

/**
* blah
*
* @throws CustomerServiceException with following causes:
* - IllegalArgumentException if anything is wrong with the passed Customer instance
* - NullPointerException if anything is wrong with a collaborator
* - FancyPersistenceException if anything is wrong your persistence service
*/
public Customer save(Customer argToSave) throws CustomerServiceException;


Note the standard Javadocs, which define precisely the causes of a CustomerServiceException, which the client of this API can expect. These defined causes as well as the CustomerServiceException are part of the contract defined by the interface. Clients can program against those causes e.g. display different error messages or inform another system.

An implementation of this interface might look as the following:

@Override
public Customer save(Customer argToSave) throws CustomerServiceException {
try {
// do some fancy stuff
} catch (IllegalArgumentException e) {

// do some logging here
throw new CustomerServiceException(e);

} catch (NullPointerException e) {

// this is programming error
throw new CustomerServiceException(e, "Dude where's your head?");

} catch (FancyPersistenceException e) {

// you might want to do some transaction handling stuff here
throw new CustomerServiceException(e);

} catch (Exception e) {
throw new CustomerServiceException();
}
}


This is pretty ugly isn't it? Especially because of the verbose Exception handling. However it's complying with the contract and a valid implementation.

In my current project we followed this pattern in every service class throughout the application. This works fine and provides a lot of consistency for clients of those APIs. However making a commitment like this requires not only a lot of discipline, when implementing those contracts, but also a lot of test code. You have to make sure that each implementation complies with the contracts promised in its interface.

A new member of the team immediately pointed out the drawbacks of our approach: a lot of test code to maintain, a lot of verbose Exception handling polluting the implementation methods and no centralized way to manage the same recurring code. His idea was to use AOP. You can refactor the Exception handling into an Aspect and thus get rid of all the drawbacks mentioned before.

The implementation of the CustomerService interface boils down to the following:


@Override
public Customer save(Customer argToSave) throws CustomerServiceException {
// do some fancy stuff
}


For a moment this might look like a perfect solution. The ugly technical Exception handling is gone and we are left with the code that actually gets the job done. That makes reading the code so much easier and don't think I'm the only fan of that.

Despite of all the drawbacks we go rid of, we silently introduced new ones. The fact that the implementation doesn't contain any hard reference to those Exceptions we claim to throw in the interface, makes understanding the implementation of the contract a lot harder. Not to mention the code for the Exception handling itself. Another drawback is refactoring the interface. Imagine someone unfamiliar with the code has to change one of the Exception causes. It is merely impossible to understand what's going on.

You have to consider the Aspect containing the logic to handle the Exception as of your implementation. Without it your implementation doesn't comply with the contract.

So what to do now? We have a great solution, which relieves us from all the drawbacks but brings along another bag of drawbacks. Should we gauge which drawbacks are easier to deal with? I remembered a solution I read in Applying UML and Patterns, which suggests a Singleton based centralized error handling. So I came up with the following solution:


public final class ExceptionHandler {
// private constructor
public static final <T extends BaseException> transform(Exception argCause, Class<T> argType) {
try {
if (argType.isAssignableFrom(argCause.getClass())) {
return (T) argCause;
} else if (argCause instanceof NullPointerException) {
return argType.getConstructor(Throwable.class, String.class).newInstance(argCause,"Dude where's your head?");
} else if (argCause instanceof FancyPersistenceException) {
return argType.getConstructor(Throwable.class).newInstance(argCause);
} else {
return argType.getConstructor(Throwable.class, String.class).newInstance(argCause,"Unkown!");
}
} catch (Exception e) {/** do some reflection error handling **/}
}
}


The implementation of the CustomeService interface using the centralized ExceptionHandler looks like this:


@Override
public Customer save(Customer argToSave) throws CustomerServiceException {
try {
// do some fancy stuff
} catch (Exception e) {
throw ExceptionHandler.transform(e, CustomerServiceException.class);
}
}


I believe this is a great trade-off. You have a single point in your code responsible for handling Exceptions. It's easy to test in isolation, which means the test code for your services decrease. The overhead in your service methods is minimal. You have to implement a try-catch block, but I think that's reasonable considering the benefits of this approach.

However, I think the biggest advantage of this solution is the fact that it works without any framework magic whatsoever. It's just plain old Java!

NOTE: Over the next few weeks, I'm moving my feed from feedburner back to blogspot so please subscribe to http://dlinsin.blogspot.com/feeds/posts/default/ instead!

February 16, 2009

Spring Integration in 10 minutes

SpringSource's Mark Fisher posted a tutorial on Spring Integration a couple of days ago. I followed the tutorial step-by-step and thought I'd share my IDEA project with you. I also added a maven POM file so you can also import it into Eclipse or use the command line.

NOTE: Over the next few weeks, I'm moving my feed from feedburner back to blogspot so please subscribe to http://dlinsin.blogspot.com/feeds/posts/default/ instead!

February 10, 2009

Heinz Kabutz @ JUG-Ka

Im really excited about this Wednesday's meeting of the Java Users Group Karlsruhe. Dr Heinz Kabutz is giving a to talk on "The Secrets of Concurrency".

You might know the The Java(tm) Specialists' Newsletter, which is most famous for a series of laws, explaining how to best write concurrent code in Java. Heinz is the mastermind behind those laws and the newsletter.

The talk takes place at University of Karlsruhe and it starts at 7:15pm. Sign up for our Google Group or join us on XING to get the latest updates on what's happing at the Java Users Group Karlsruhe.

NOTE: Over the next few weeks, I'm moving my feed from feedburner back to blogspot so please subscribe to http://dlinsin.blogspot.com/feeds/posts/default/ instead!

February 09, 2009

Got Burned, Changing my feed!!

My current feed is run by FeedBurner. That means most of you are getting this feed from http://feeds.feedburner.com/dlinsin and thanks to FeedBurner you see stuff like "Digg This!" or "Submit to Reddit" at the bottom of each post.

FeedBurner was acquired by Google and is moving all accounts to Google Adsense by the end of this month. Since Google doesn't want me to use Adsense, I can only switch back to my old feed. So if you want to keep reading my stuff, simply switch to http://dlinsin.blogspot.com/feeds/posts/default/. However, the FeedBurner feed will still be alive for the next couple of weeks.

February 02, 2009

Do You Write Unit Tests For Yourself?

A couple of days ago I listened to the stackoverflow podcast with Jeff Atwood and Joel Spolsky. They were talking about when it is appropriate to write unit tests for your code.

Joel:
"Changing a parameter in some function call from 37 to a 9 is not really gonna fail or introduce a bug"
"It's great if you use TDD for your encryption library or compiler, but that's a very finite number of apps that are like that"
"For a team of good programmers the prescriptions are probably gonna be different than from a team of mediocre programmers"


Jeff:
"With stackoverflow there are very few cases where I feel like: okay I'm gonna sit down and write a unit test and this is gonna result in a measurably better experience."


Of course I cannot quote the whole discussion here, so this might sound very harsh on testing for you. Jeff kind of put their statements into perspective by saying that he is pro testing, but just doesn't do it on stackoverflow. However, I still have this feeling that they turned their backs on unit testing too easily.

First off, let me tell you that I love unit tests. I write a lot of them and I care about code coverage quite a bit. You might even say that I am a little religious or dogmatic about it. I only have good experience with unit testing, so I tend to believe that I am not that far off. On my current project we are about 8 people working on our code base, so you can imagine there is a lot going on. It's easy to break something and believe me we are breaking stuff all the time. Although each developer has his domain, you are constantly working with code that was not written by yourself.

Fortunately our test coverage is pretty good. In case a test fails and something seems to be broken, you are being notified by the continuous integration server. Personally that gives me the confidence to do refactorings and changes without the fear of introducing major bugs. The biggest downside, which was also mentioned by Joel, is the "bang for the bucks". You need a big investment to get to this degree of test coverage. You really need to gauge, whether it's worth the time invested to write a unit test for a piece of code.

As mentioned before there is a lot of stuff breaking during development of new features. This is mainly due to not knowing all of the code base. However, I think working with other developers, you are bound to have unit tests. At least for the parts of your code that might be extended or maintained by others. It is worth to invest in a unit test, if you want to make life easier for your fellow developers. At least they can change your code with confidence. You are basically giving them a guideline, which helps to get their work done faster and more reliable. In the long run, I think that will increase the quality of your application and hopefully leaves an impression of your code on your fellow team members.

So what if you are working on a small team or almost alone on your project? Do you still need unit tests? That's when I want to come back to the discussion Joel and Jeff had. The stackoverflow team is quite small. I think Jeff probably thinks, that if you are working alone on a project it might not be worth the investment to write unit tests.

I kind of disagree, because I've been there myself. As the only developer of an application and working on various features at the same time, I found myself breaking my own features over and over again. I started writing unit tests and setup a continuous integration server, which helped me automate my builds and improved quality dramatically. By the time a second developer started working on the project the test coverage was reasonable enough, so he could change my code without the fear of breaking anything.

Maybe I'm just not that good of a developer and I need to write unit tests for myself. However, I do think it's worth the investment, because sooner or later another developer will have to work with your code. Go and make his life a little easier and provide some unit tests.

com_channels

  • mail(dlinsin@gmail.com)
  • jabber(dlinsin@gmail.com)
  • skype(dlinsin)

recent_postings

loading...