Ruminations on Development
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] ------------------------------------------------------------------------
Posted at 04:49PM Apr 30, 2008 by Nelson "Nelz" Carpentier in General | Comments[0]
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
.
Posted at 12:06PM Apr 28, 2008 by Nelson "Nelz" Carpentier in General | Comments[0]
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!
Posted at 12:48PM Apr 23, 2008 by Nelson "Nelz" Carpentier in General | Comments[0]
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...")
Posted at 08:28AM Apr 22, 2008 by Nelson "Nelz" Carpentier in General | Comments[0]
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".
Posted at 10:36PM Apr 21, 2008 by Nelson "Nelz" Carpentier in General | Comments[0]
Ruffled My Feathers
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.
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.
Posted at 11:33AM Apr 21, 2008 by Nelson "Nelz" Carpentier in General | Comments[0]
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?
Posted at 09:35PM Apr 16, 2008 by Nelson "Nelz" Carpentier in Java | Comments[0]
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?
Posted at 09:33PM Apr 16, 2008 by Nelson "Nelz" Carpentier in General | Comments[0]
Random Techy Stuff
Ok... I've got a backlog of tech-ish tidbits to write about... Time to cleanse the salvos, eh?
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.
, 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!)
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! :-)
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
.
Posted at 03:17PM Apr 12, 2008 by Nelson "Nelz" Carpentier in General | Comments[0]
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!
Posted at 11:33AM Apr 11, 2008 by Nelson "Nelz" Carpentier in Java | Comments[0]