I've Moved!

At long last, I finally have combined my personal web site and my blog into one site, which is now hosted on WordPress. This will be my final post at this Blogger site. To continue the conversation, jump on over to http://www.mattstine.com!

The Manifesto for Software Craftsmanship

So as I'm sitting here thumbing through my InfoQ feed on Google Reader, I come across the following posting: Software Craftsmanship Manifesto: A Call to Arms. It seems that a group of "programming patriots" has struck again (see the Manifesto for Agile Software Development - circa 2001), complete with a "founding document" look and feel. Clicking through the source link, one finds the following:

As aspiring Software Craftsmen we are raising the bar of professional software development by practicing it and helping others learn the craft. Through this work we have come to value:

  • Not only working software, but also well-crafted software

  • Not only responding to change, but also steadily adding value

  • Not only individuals and interactions, but also a community of professionals

  • Not only customer collaboration,but also productive partnerships

That is, in pursuit of the items on the left we have found the items on the right to be indispensable.

© 2009, the undersigned. this statement may be freely copied in any form, but only in its entirety through this notice.

You can't even imagine my excitement in reading this. This statement of values is something that I have been trying to get across without having the needed words for quite some time.

The motivation, says the InfoQ article, is right on target:

The members of the manifesto group answered two key questions: “How will it help solve the problems of crap code?” and “What will motivate "The developer just churning out code" to become a craftsman?” - the distinction is between the developer who is just getting it done vs the one getting it done right.

I have felt for a long time that the elements of craftsmanship are something sorely missing from our field. We, as programmers, are often so consumed with getting the job done that we do often neglect getting it done right. In our haste to move on to the next exciting project and/or technology, we neglect the tenets of simple design, test-driven development, merciless refactoring, clean code, etc. We're often quite satisfied with the "hacky solution here" and the "quick and dirty solution there."

Quite frankly, I've had enough of that. I'm not satisfied when the contractor building my house cuts corners. I'm quite irritable when my mechanic does a less than thorough job with my car. Why should I expect my clients to settle for software built like that?

So, to make this a practical rant, I thought I'd share a couple of the things that we're doing in our team to move us in the right direction:

  1. First of all, we started a weekly "brown bag lunch/workshop," inspired by Andy Hunt and Venkat Subramaniam's discussion in Practices of an Agile Developer.

  2. Second, we selected books to read as a team that will point us in the right direction. Our first two titles were The Pragmatic Programmer: From Journeyman to Master (see, there's craftsmanship right away!) and Clean Code: A Handbook of Agile Software Craftsmanship (sense a pattern yet?).

  3. Third, we make a point of our weekly discussions to look at ways we can integrate the principles and practices that we're learning into our daily work. An example: We're working to integrate peer code review into our development process. The principles, patterns, and practices that we're picking up from Clean Code will be informing us as we review code and look for possible improvements.

So, with that said, tonight I became a signatory of the manifesto. Why don't you join me and fight the fight against crappy code!

Grails+Dojo Ajax File Upload

I'm currently working on a Grails application with a requirement for uploading product images, which are subsequently resized into thumbnails of various sizes for different shopping screens. Since it took a bit of doing to get this done, I thought I'd post my solution here in case anyone could benefit from it.

First, to set the stage, I've upgraded the application all the way to the newly released Grails 1.1.

To start off, I naively attempted to use the built-in Prototype library to do the upload with a simple <g:submitRemote/> tag. You might have guessed that this didn't work at all. Continuing to learn the hard way (without reading the manual I might add), I submitted this as a bug to the Grails project. Graeme ever so politely informed me that this was known and expected behavior, as Prototype doesn't support such a thing. However, it was Graeme that also tipped me off to try Dojo.

So, continuing down this path, I proceeded to install the Grails Dojo plugin. Once this is done, a <g:javascript library="dojo"/> is supposedly all that is required to convert your Ajax calls from Prototype to Dojo. This turned out to not be the case for me, with Javascript errors popping up all over the place, not the least of which was that dojo.js seemed to be installed in an unexpected location via the plugin. The hacker in me simply copied this to the expected location and moved along. However, as I attempted to work with Dojo's file upload support, I discovered that the version of Dojo shipped with the plugin seemed at first glance to be way behind. Frustrated by this, I went ahead and stripped the Dojo plugin out and installed the latest version available (at this writing 1.2.3), and set about to develop my solution.

Here goes:

1. Add the necessary Dojo dependencies to your GSP:


<script type="text/javascript" src="${createLinkTo(dir: 'js/dojo', file: 'dojo.js')}"
djConfig="parseOnLoad:true, isDebug:true"></script>
<g:javascript>
dojo.require("dojo.io.iframe");
</g:javascript>


2. Write a function using dojo.io.iframe to send the form:


function submitForm() {
dojo.io.iframe.send({
form: 'uploadProductImageForm',
load: function (data) {
dojo.byId('productImage').innerHTML = data;
}
});
}


3. Create the file upload form:


<g:form name="uploadProductImageForm" method="post" action="uploadProductImage" enctype="multipart/form-data">
<input type="hidden" name="id" value="${productInstance?.id}"/>
<input type="file" name="newProductImage"/>
<span class="button"><input class="add" type="button" name="uploadImage" value="Upload Image" onclick="submitForm()"/></span>
</g:form>


4. Create the controller method:


def uploadProductImage = {
def f = request.getFile('newProductImage')
if (!f.empty) {

def imagePath = grailsApplication.config.store.productImages.location

//Create unique name for this image set based on current timestamp
def name = "image" + new Date().getTime()

//Store the file
def file = new File("${imagePath}/${originalFilename}")
f.transferTo(file)

//Do some image processing (resizing, etc.)
...

//Dojo requires returning the result nested in an HTML document containing a body and textarea tag. Do this with
//Groovy's built-in MarkupBuilder

def writer = new StringWriter()
def xml = new MarkupBuilder(writer)

xml.html {
body {
textarea {
img(src: resource(dir: grailsApplication.config.store.productImages.webPath, file: product.mediumImage.name), width: '250')
}
}
}

render writer.toString()
}
else {
flash.message = 'file cannot be empty'
redirect(action: show)
}
}


And there you have it. Let me know what you think of this solution. It definitely works for me. You will notice that I didn't include an upload progress bar - I'll be doing this in a future iteration of the project. Cheers!

I'm speaking at the March Memphis JUG meeting

I learned a great deal about JMS from Mark Richards at last weekend's NFJS Gateway Software Symposium, and I thought I'd share it with the Memphis Java community. Take a look at http://www.memphisjug.org for details!

My iPod is on rice

Let me set the stage for you. I'm driving home happily listening to Ted Neward discuss the merits of Scala on the Javaworld podcast. As I pull into the driveway I see my wife waving frantically in the window. As geek brain struggles to process this, home brain kicks into gear. She needs me in the house now! I jump out of the car and slam the door shut, leaving all of the belongings I typically carry in the house.

I enter the house to find that a wasp has some how gotten in and is terrorizing the family. What ensues is roughly 15 minutes of wasp hunting. Wasp dead - end of story. Or so I thought.

As I'm driving my iPod (attached to the iTrip FM transmitter/charger) typically sits in my lap (for some reason I get the least FM interference that way). What I didn't notice in my hasty departure from the vehicle is that my iPod nano flew out of the vehicle and was hanging by the iTrip cable. Unaware of this, I slammed the door on the cable and walked away.

This in and of itself wasn't a huge problem. Leaving it that way for approximately 24 hours - most of which included rather steady rainfall - was.

So, a quick Google search finds that the consensus approach seems to be sticking the iPod in a cup of dry rice to soak up the moisture. So there you have it - my iPod is on rice. I hope it works. Stay tuned.

It's been a long time...

...since I actively spent any time blogging. What you don't know is that it has been a long time since I've done any writing whatsoever. The last two posts on this blog revolved around the birth of my first son, Grant Dawson, on May 16, 2009. This was one of several events that took place almost a year ago that sent me directly into a whirlwind of activity that found me barely keeping my head above water.

It was also about this time that I found myself newly promoted into front-line management. The team that I entered first in 2000 as a Bioinformatics Intern during my last summer as an undergraduate, and then as a Software Engineer/Web Developer I following graduation in 2001, was now mine to lead. After doing this job now for nearly a year, I can safely say that my career as a developer has both prepared me for this role and left me completely bankrupt when faced with the responsibilities that are now mine. More on this to come.

Another event that transpired in May was the sale of our first home. It had been on the market since March, and we "paused" the showings as Grant's arrival became imminent. It was near the end of May that we received both our first and our last post-Grant showing phone call. I remarked to Wendy - "these folks are going to buy the house." And buy it they did. Unfortunately for us, we had no idea whatsoever where we were going to move. What ensued was a chaotic whirlwind of house hunting which ended with us making an offer on a house that wasn't even on the market. And that's the house I'm sitting in while I write this first entry of 2009. Ask me to tell you the story sometime - it's a good one.

So, why I'm I here? Why not just leave the blogging task. After all, isn't blogging passe at this point?

I credit my return to the blogosphere to an incredible book by Jared Richardson and Matthew Bass - Career 2.0: Take Control of Your Life. The basic premise of this book is to "Actively manage your career." One of the ways by which the authors share how to do this is writing - sharing what you know with the community at-large. Of course what they shared was no surprise to me. I already knew all too well the career benefits associated with blogging. What I needed was a proverbial "kick in the pants." And that's what Career 2.0 did for me. If you're in the software industry - take that back, I don't care what industry you're in (these principles are transcendent) - do yourself a favor and read this book. It will change something about your life, guaranteed.

So, with that, let's start the conversation again. I'm looking forward to where it might lead. Cheers!