Monday, 10 October 2011

You know what I like? Throwing code away.

I had a hard look today at some of the coding being done in one of the apps I'm involved with.
A maven project with dozens of sub-projects each having different versions of dependencies in their POMs.
Many of the sub-projects have dependencies on other sub-projects and the web is immense.
I did a "mvn dependency:tree" - HA! That should be "mvn dependency:omg".
Two minutes of tree screaming past (or was that me?).
Boy oh boy.
What a load of...
And there was more...
One class will package up a bunch of data into a DTO to pass it to another project which then picks it apart to make another DTO to pass it...
Wha?
This is silly.
I tried to do a plain old "mvn clean install" on one of the sub-projects and it looked like an explosion in a stack trace factory.
Pages and pages of gumpf roaring up the screen.
How would you ever know if anything was out of whack?
I'm not talking about unit tests.
You wouldn't know if the dto->data->dto->data->dto stuff is going on.
Wasteful.
Acres of jars in the .m2 folders.
Builds taking forever.
This is silly.
So I took one of the projects and tore it to pieces.
I broke it down into single units of work.
So I have a load of little dinky jars that don't change from build to build and do exactly one thing.
For example, one project has dozens and dozens of try/catch->log.error() stuff going on.
You know what I mean, methodA throws the Exception to caller methodB which throws the Exception all the way up to this:

    try {
      // call methodZ
    } catch (SomeException) {
      // Uh oh. What's the context? Oh well...
      log.error(ex.getMessage());
      log.error(StackDump.getTrace(ex));
      // Do we continue? Or die?
      // Oh well... Just keep on Truckin' Hope it works...
    }

So I created a jar project that makes a RESTful call asynchronously to a web site to report exceptions.
It looks for a config file of the same name as the jar which tells it what to do (including time outs, distributed whatever).
It doesn't care what the site(s) does with the exception, it just sends a bunch of basic information and the stack trace to where it's told to.
But this jar now has exactly one class.
And it's as dumb as a box of hammers.
So now, any project anywhere can do something like this:

    try {
      // something that might break
    } catch (SomeException ex) {
      // do anything that may be needed in the project context
      new ReportException("ServerName","Module","SubModule",ex).send();
      // crash, burn, rethrow, use a default, use a config option, continue - whatever
    }

And exception handling becomes easy enough that programmers won't do this:

    try {
      // something that might break
    } catch (SomeException ex) {}

Because it's now easy to report it.
And that exception is sent to a central (or distributed depending on the config file) site(s).
That site is another dinky project that does one thing.
It has one Resource which responds to PUT on one path.
It has a simple Config file which tells it whether to log to MongoDB, send email, post to an IssueTracker or whatever.
It depends on several small project jars that do one thing each: log to MongoDB, SendEmail, PostToBugZilla and so on.
So now we have several tiny jars and 1 tiny war that don't change.
And tons and tons of Exception handling in multiple sub-projects can be thrown away and better monitored.
Moreover, the store where the exceptions are saved (MongoDB, MySQL, Cassandra whatever) can now be monitored by Nagios.
And all those sub-projects have a load of dependencies reduced.
And the app-build is quicker.
I like(+1) throwing code away.

No comments:

Post a comment