Nelz' Blog

Ruminations on Development


« Previous month (Mar 2008) | Main | Next page of month (Apr 2008) »
Wednesday Apr 30, 2008

Helpful Maven Command: "mvn dependency:tree"

Sometimes you need to peruse the dependencies (and transitive dependencies) within your Maven project. The "mvn site" command generates a pretty nice version of this in HTML. (Example: Jetty Maven Plugin - Depenencies Report.)

Well, the good news is that you don't need to go through the whole "mvn site" generation to find out this information, as the "dependency" plugin can provide this information to you via the command-line.

% mvn dependency:tree

Here is (a part) of the output from one of the projects I'm working on:

[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'dependency'.
[INFO] ------------------------------------------------------------------------
[INFO] Building SomeCompany :: Main Webapp
[INFO]    task-segment: [dependency:tree]
[INFO] ------------------------------------------------------------------------
[INFO] [dependency:tree]
[INFO] com.somecompany:somecompany:war:1.0-SNAPSHOT
[INFO] +- com.somecompany:backend:jar:1.0-SNAPSHOT:compile
[INFO] |  +- mysql:mysql-connector-java:jar:5.0.4:runtime
[INFO] |  +- antlr:antlr:jar:2.7.6:compile
[INFO] |  +- commons-codec:commons-codec:jar:1.3:compile
[INFO] |  +- commons-dbcp:commons-dbcp:jar:1.2.1:compile
[INFO] |  |  \- xml-apis:xml-apis:jar:1.0.b2:compile
[INFO] |  +- commons-httpclient:commons-httpclient:jar:3.0:compile
[INFO] |  |  \- junit:junit:jar:3.8.1:compile
[INFO] |  +- commons-lang:commons-lang:jar:2.3:compile
[INFO] |  +- commons-logging:commons-logging:jar:1.0.4:compile
[INFO] |  +- commons-pool:commons-pool:jar:1.3:compile
[INFO] |  +- dom4j:dom4j:jar:1.6:compile
[INFO] |  +- net.sf.ehcache:ehcache:jar:1.4.0:compile
[INFO] |  |  +- net.sf.jsr107cache:jsr107cache:jar:1.0:compile
[INFO] |  |  \- backport-util-concurrent:backport-util-concurrent:jar:3.1:compile
[INFO] |  +- org.hibernate:hibernate-annotations:jar:3.2.0.ga:compile
[INFO] |  |  +- org.hibernate:hibernate:jar:3.2.0.ga:compile
[INFO] |  |  |  +- javax.transaction:jta:jar:1.0.1B:compile
[INFO] |  |  |  +- asm:asm-attrs:jar:1.5.3:compile
[INFO] |  |  |  +- cglib:cglib:jar:2.1_3:compile
[INFO] |  |  |  \- asm:asm:jar:1.5.3:compile
[INFO] |  |  \- javax.persistence:persistence-api:jar:1.0:compile
[INFO] |  +- jdom:jdom:jar:1.0:compile
[INFO] |  +- ognl:ognl:jar:2.6.7:compile
[INFO] |  +- rome:rome:jar:0.9:compile
[INFO] |  +- org.springframework:spring:jar:1.2.7:compile
[INFO] |  +- net.sourceforge.stripes:stripes:jar:1.4.3:compile
[INFO] |  +- velocity:velocity:jar:1.5:compile
[INFO] |  |  \- oro:oro:jar:2.0.8:compile
[INFO] |  +- org.json:json:jar:20070829:compile
[INFO] |  +- org.htmlparser:htmlparser:jar:1.6:compile
[INFO] |  +- javax.mail:mail:jar:1.4:compile
[INFO] |  |  \- javax.activation:activation:jar:1.1:compile
[INFO] |  \- org.safehaus:jug:jar:2.0.0:compile
[INFO] +- javax.servlet:jstl:jar:1.1.2:compile
[INFO] +- taglibs:standard:jar:1.1.2:compile
[INFO] +- javax.servlet:servlet-api:jar:2.5:compile
[INFO] +- com.oreilly.servlet:cos:jar:1.0:compile
[INFO] +- c3p0:c3p0:jar:0.9.1.2:compile
[INFO] +- jaxen:jaxen:jar:1.1-beta-7:compile
[INFO] |  +- xerces:xmlParserAPIs:jar:2.6.2:compile
[INFO] |  +- xerces:xercesImpl:jar:2.6.2:compile
[INFO] |  \- xom:xom:jar:1.0b3:compile
[INFO] |     +- com.ibm.icu:icu4j:jar:2.6.1:compile
[INFO] |     +- xalan:xalan:jar:2.6.0:compile
[INFO] |     \- org.ccil.cowan.tagsoup:tagsoup:jar:0.9.7:compile
[INFO] +- javax.sql:jdbc-stdext:jar:2.0:compile
[INFO] +- org.apache.lucene:lucene-core:jar:1.9.1:compile
[INFO] +- quartz:quartz:jar:1.5.1:compile
[INFO] +- commons-collections:commons-collections:jar:3.2:compile
[INFO] +- org.apache.avalon.logkit:avalon-logkit:jar:2.2.1:compile
[INFO] +- jgroups:jgroups-all:jar:2.6.1:compile
[INFO] \- log4j:log4j:jar:1.2.11:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4 seconds
[INFO] Finished at: Wed Apr 30 16:40:42 PDT 2008
[INFO] Final Memory: 12M/508M
[INFO] ------------------------------------------------------------------------

Monday Apr 28, 2008

Leopard and the GIMP

On Friday, I spent the majority of the day banging my head against my laptop.

I wanted to install GIMP (the GNU Image Manipulation Program) to do some image creation for my new Widgetbox widget...

I tried several different ways to install the GIMP (and even GIMPshop), but it kept failing every time I tried to run it.

Eventually, I saw the cautionary warning on the site that hosts pre-built Mac OS X versions of the GIMP.

I will repeat the cautions here: The X11 package you can find on a OS X 10.5.0 install disk is too old to run GIMP (it will crash), and it can't be updated through software update.

There appears to be several different ways to address the problem, but the one that worked for me was to download and install the latest version of the XQuartz project.

Wednesday Apr 23, 2008

Blogging Works For Me!

I understand how a lot of people are opposed to personal blogging as an exercise in navel-gazing. But I am here to tell you that it works for me!

I have never been a journaler, because it also felt very navel-gazey to me. Writing on paper would be futile as I would lose the paper. "Engineers notebooks" are close, but when I tried that path, I felt I need automated searching capabilities to find things.

In regards to an online blog, with the possibility of my musings helping others I feel much more motivated to actually post. And, the secondary benefit is that I have an online repository of my own ideas. No less than 3 times in the last week have I been able to refer to one of my own previous blog posts as an aid for either work or community.

Blogging can be bad, no doubt about it... But, in some instances it can be really beneficial!

Tuesday Apr 22, 2008

Self Allowances as Code Smell

Lately, I've been noticing a theme in development. Sometimes, an organization will grab hold of an edge-case truism and run with it.

I think this is a big vector for code smell... If you give yourself a pass to violate good programming practices too early you are probably doing yourself a disservice, and you will probably suffer the headaches from it later.

According to Wikipedia, "an edge case is a problem or situation that occurs only at an extreme (maximum or minimum) operating parameter". If you are going to allow yourself to utilize an edge-case strategy, then you should make sure you are really seeing the 'extreme operating parameters'. If you end up using this edge-case strategy many times in your code, maybe you need to reevaluate your definition of 'extreme'.

(And, for those of you wondering, the statement that got me thinking along these lines is this: "sometimes you need to denormalize your data...")

Monday Apr 21, 2008

Live Code

First, let me make the following announcement:

Widgetbox.com's new homepage was released today!

Now, I have a confession to make... I realized that this is the first time in my (paid) career that I've had any code of mine out and in the wild for public consumption.

I've had side project code get released (like here or here or here), but never anything that I've worked on 'professionally'.

My pre-Web work at Eclipse Inc was a large application that you interacted with via (mostly) dumb terminals, with a whopping 24 X 80 character resolution. It was a hard-goods distribution application, which my grandmother would have no hope of ever accessing.

At ICAT, it was all web applications though they weren't for public consumption, just for internal or partner usage.

At PlanetOut/Gay.com we were rewriting Gay.com. My code there will be released into the wild soon, but it isn't scheduled to happen for at least another month or two.

So, this leaves Widgetbox. I got to write some of the code facilitating the different modules on the home page, such as the "Hidden Gems" or "New and Notable" or "Hottest Widgets".

It's pretty cool, because I think my Widgetbox stuff could pass the "Grandmother Test".

Ruffled My Feathers

Vendor Relations

The other day we met with a vendor who was proposing that we use their paradigm-shifted product. I'm okay with the vendor in general, and actually I kind of like their product.

But, I asked some questions that the Sales dude cast as tactical rather than strategic, and basically said I shouldn't worry about the tactical issues. After chewing on the conversation a bit, I'm gonna say "No!" Yeah, so my questions were tactical, but if the developers can't easily simulate a scaled-down version of the production environment, then your product actually does lose value to me. (In the end though, their product can easily scale down.)

Now, allow me to vent on another tangent... Hey "Sales Guys", I do not need you. Gimme a "Sales Engineer" any day... (One that is actually technical, BTW...) I can talk to those people. However, when a "Sales Guy" comes in with hyper-tanned leathery skin and mega-sun-bleached hair, talkin' all smarmy-like... I just wanna kick them in the shins and tell them to get out of my face. In my experience, "Sales Guys" like this are nothing but liars and over-promisers, to both the customers and to the actual engineers he is representing.

Framework Support

I've had a question posted to the Spring Framework Support Forums for a couple of weeks now. Yet, no authoritative member has responded... The only traffic at this point is myself and another guy who is also trying to figure out the same stuff.

I think I came up with a viable solution and posted it on that thread... But, it will (probably) be a couple of months before I get to experiment with it directly at work... But when I do, I'll try to remember to post my findings.

Wednesday Apr 16, 2008

Java 5 FOREACH Syntax

For those that don't currently use the new Java 5 "foreach" syntax, you are missing out.

I got to a point today where I wanted to verify that the construct is doing the intelligent thing, so I wrote the following unit test:

	@Test
	public void forEachLoop() {
		for (String str : doHeavyWeigthMethod()) {
			System.out.println(str);
		}
 	}

	private List<String> doHeavyWeigthMethod() {
		System.out.println("heavyMethod");
		final List<String> results = new ArrayList<String>();
		results.add("one");
		results.add("two");
		results.add("three");
		return results;
	}

I was psyched to see the output:

heavyMethod
one
two
three

Basically, this shows that the foreach construct only evaluates the collection once and caches the value to be used in each iteration.

However, the construct is not without some pitfalls. I would have expected the new construct to be programmed more defensively, but it is still susceptible to NullPointerException. Running the following throws the NPE:

	@Test
	public void forEachLoop() {
		for (String str : doHeavyWeigthMethod()) {
			System.out.println(str);
		}
 	}

	private List<String> doHeavyWeigthMethod() {
		return null;
	}

So, unless you know you are in control of the method you are calling in the expression part of the "foreach" construct, you still need to defensively check for null. And, we all know how much I love that, right?

History Meme

I found a new meme spreading amongst the technorati... The "history" meme. (See previous examples here, here, and here.)

Basically, you run a script to show what commands you frequently use.

Here's my output:

$ history|awk '{a[$2]++} END{for(i in a){printf "%5d\t%s \n",a[i],i}}'|sort -rn|head
  102   svn 
  100   ls 
   74   cd 
   49   wget 
   31   ruby 
   28   rm 
   13   exit 
   10   gem 
    9   which 
    8   mv 

What is yours?

Saturday Apr 12, 2008

Random Techy Stuff

Ok... I've got a backlog of tech-ish tidbits to write about... Time to cleanse the salvos, eh?

Roller restart

I use Roller software to publish this blog. Last week I had to take down the application server (Tomcat), and when I brought it back up, Google Reader said that I had published every single post again that day. This sounds like a bug to me, but I'm asking up the chain starting with the Roller users' mailing list.

CLI Theme for WordPress

As I said above, I use Roller as my blogging tool. However, if I were running WordPress, I would run the fun "CLI Theme" as published by Rod McFarland and demonstrated on his site http://thrind.xamai.ca/. (All the programming geeks I showed this theme to loved it!)

Text Ads

So, I think I've ranted about this before, but I don't use this site to make any money. I basically use it just as a public journal of my travels through the digital and technical landscapes.

The other day I got an email offer from someone who wants to place text link ads on my blog. The email was suspiciously form-letter-ish, and I KNOW they weren't actually reading my blog because they said they were "enthralled" while reading it.

Even if I did sell out, I wouldn't make much money at all, because I KNOW I get very little traffic. I've seen my stats (heck, you can too: http://nelz.net/stats), and I'm sure that besides all the spiders, I am my own biggest consumer.

Though, this email did encourage me to re-set up my Google Analytics on this blog which I lost when I changed themes a couple of weeks ago. So, now I am watching my traffic. To those 4 or 5 of you who actually read this blog on a regular basis: Thank you! :-)

Netgear Router WGR614 v7 = FAIL!

No, my apartment is not all that big. But, having one less hard-line connection to my laptop is a nice convenience. This is why I bought a wireless router. Well, I can tell you that this router is SHYTE!

I had it running for only about a week before it started going flaky on me. It would drop, come back up, block my traffic, fail, drop, come back up, and just generally work intermittently. Most of the time, I could move my laptop closer and plug in to a hard-line and it worked swimmingly. So, as a NON-wireless router, this wireless router works pretty well, I guess.

I had originally set it up as an open hotspot. (I was convinced to do this by Bruce Schneier in his "Steal This Wi-Fi" post.) When the flakiness hit, I then turned up the security, only allowing my laptop's MAC address connect, but it still couldn't handle the load.

If I were a receipt-saver, I might try to get a refund, but I'm not so I'll just wait until I get pissed off enough to replace the damned thing. The word on the street is that I should buy myself a nice Linksys.

Friday Apr 11, 2008

Heavyweight Syntax

Method chaining seems like such a good idea. And Java supports it, always has. However, if you have been bitten in the butt too often by code you can't (or don't) control, you learn the value of defensive programming.

Whereas, I want to write code like this:

    public String getDeepString(ComplexObjectA a) {
    	return a.getComplexObjectB().toString();
    }

... I can't. Or at least it's not a good idea to write it like that. To protect myself, or classes that utilize my method, I have to write it like this:

    public String getDeepString(ComplexObjectA a) {
    	String result = null;
    	if (a != null) {
    		ComplexObjectB b = a.getComplexObjectB();
    		if (b != null) {
    			result = b.toString();
    		}
    	}
    	return result;
    }

Wash. Rinse. Repeat. Over and over and over, I'm checking for null. And, I'm getting kind of tired of it.

But wait, what light over yon hill breaks? Is it Groovy?!? Groovy provides a fantastic "?." construct, which can reduce the above noisy code to nearly what I was hoping for in my first example:

    public String getDeepString(ComplexObjectA a) {
    	return a?.getComplexObjectB()?.toString();
    }

I showed the "Unadulterated Java is so groovy" post to some of my coworkers, and the "?." construct is the single most talked about benefit of potentially adopting Groovy.

No, we haven't adopted Groovy yet. We've got some work to do, including moving toward a Maven (2) build system. But from what I hear the Groovy plugins to Maven and IntelliJ make dropping in Groovy transparent and easy. We may become a Groovy shop yet!