Matt RaibleMatt Raible is a Web Developer and Java Champion. Connect with him on LinkedIn.

The Angular Mini-Book The Angular Mini-Book is a guide to getting started with Angular. You'll learn how to develop a bare-bones application, test it, and deploy it. Then you'll move on to adding Bootstrap, Angular Material, continuous integration, and authentication.

Spring Boot is a popular framework for building REST APIs. You'll learn how to integrate Angular with Spring Boot and use security best practices like HTTPS and a content security policy.

For book updates, follow @angular_book on Twitter.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.
You searched this site for "grails". 129 entries found.

You can also try this same search on Google.

What would you like to see at TSSJS 2010?

The Venetian A couple months ago, I was asked by TheServerSide to speak at next year's TheServerSide Java Symposium in Las Vegas. In addition, they asked me to help them evaluate presentation proposals and suggest topics/speakers.

First of all, I think the biggest thing that TSSJS could do to improve is to host more networking events. With the JavaOne Party being over, I think there's a tremendous opportunity to fill a gap in the networking needs of the Java Community. When I first attended TSSJS in 2006, there were a fair amount of parties and everyone got to interact quite a bit. In 2008, there were no networking events. I believe having a strong networking story would attract a lot more attendees, companies and sponsors.

Secondly, I think it's possible that TSSJS has too many server-side related sessions. IMO, the server-side (and middleware in general) isn't that exciting. TechTarget appears to own TheClientSide, so why not add some more client-side stuff to the mix? For example, I'd love to see a Struts 1 app-makeover using different technologies (for example, Flex, GWT and jQuery). I think HTML5 and Google Wave's Architecture sessions would be interesting too. If adding client-side sessions is too far away from TheServerSide, maybe it should be renamed to TheServerSide JVM Symposium and there can be all kinds of sessions on JVM languages (e.g. Scala, JRuby, Groovy) and all the great things those languages can accomplish.

Lastly, I've been asked to send a couple session proposals. Currently, I'm thinking about a doing GWT vs. Flex Smackdown with James Ward, but I'm open to other ideas. It's been quite awhile since I did a "Comparing Web Frameworks" talk. Maybe "Hot Web Frameworks for 2010" is more appropriate? I also think it'd be interesting to do a somewhat philosophical talk on "The State of Web Frameworks" and where we're headed in the next year.

What would make you want to attend TSSJS next year? Let me know your thoughts and I'll do my best to make them a reality.

Update October 22, 2009: Whoo hoo! It looks like TheClientSide will be a part of TSSJS Vegas next year. Should be a great show.

Posted in Java at Oct 12 2009, 11:28:21 AM MDT 3 Comments

The 2009 Rich Web Experience

Rich Web Experience 2009 Late last year, I decided to take a year off from speaking at conferences. My reason was simple: I wanted to hunker down and do some learning. Ever since November 2007, I'd been interested in getting into developing SOFEA applications. This year, I was able to accomplish that and I've learned a lot about GWT and RESTful architectures in the process. Now I'm happy to announce I'll be sharing my experiences at this year's Rich Web Experience.

I look forward to speaking on the following topics:

The first one might look familiar since I used the same title at OSCON 2008. The difference is this time I plan to dive much deeper into the frameworks and help the audience learn more. I also plan to re-visit developing with Flex and Rails in the near future. If there's anything in particular you'd like to see covered in the above talks, please leave a comment.

This is sure to be a fun conference. First of all, it's pretty close to Disney World. A few years back, TSS hosted the "Java In Action" conference in Disney World and while the conference didn't do too well, it was awesome being there with my family. I plan on taking my kids and having some fun when I'm not speaking. Secondly, this conference is the first to offer all-inclusive pricing for attendees - registration, flight (continental U.S.) and 3 nights lodging. This should allow you to get approval without having to jump through the traditional travel hoops. Lastly, the JSF Summit will be held concurrently and you get access to it at no additional cost.

So come on down to Florida in December, listen to all the great speakers, have some fun with your family and look me up for a beer or two. You know it'll be a good time! ;-)

Posted in Java at Aug 11 2009, 10:16:24 PM MDT 1 Comment

JSON Parsing with JavaScript Overlay Types in GWT

A reader recently asked:

I would love to see a snippet of how to eval the JSON coming from RequestBuilder into the OverlayTypes. What is the mapping like? I used OverlayTypes to read in static data that I render into the head section of the hosted page, which is pretty easy and fast, but I don't know how to do this "reading" dynamically at runtime.

If you're not familiar with GWT's Overlay Types (added in 1.5), see Getting to really know GWT, Part 2: JavaScript Overlay Types. In our project, we're using Overlay Types to simplify JSON parsing and make our application lean-and-mean as possible.

First of all, we have a JSOModel class that acts as our overlay type:

import java.util.HashSet;
import java.util.Set;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.JsArrayString;

/**
 * Java overlay of a JavaScriptObject.
 */
public abstract class JSOModel extends JavaScriptObject {

    // Overlay types always have protected, zero-arg constructors
    protected JSOModel() {
    }

    /**
     * Create an empty instance.
     * 
     * @return new Object
     */
    public static native JSOModel create() /*-{
        return new Object();
    }-*/;

    /**
     * Convert a JSON encoded string into a JSOModel instance.
     * <p/>
     * Expects a JSON string structured like '{"foo":"bar","number":123}'
     *
     * @return a populated JSOModel object
     */
    public static native JSOModel fromJson(String jsonString) /*-{
        return eval('(' + jsonString + ')');
    }-*/;

    /**
     * Convert a JSON encoded string into an array of JSOModel instance.
     * <p/>
     * Expects a JSON string structured like '[{"foo":"bar","number":123}, {...}]'
     *
     * @return a populated JsArray
     */
    public static native JsArray<JSOModel> arrayFromJson(String jsonString) /*-{
        return eval('(' + jsonString + ')');
    }-*/;

    public final native boolean hasKey(String key) /*-{
        return this[key] != undefined;
    }-*/;

    public final native JsArrayString keys() /*-{
        var a = new Array();
        for (var p in this) { a.push(p); }
        return a;
    }-*/;

    @Deprecated
    public final Set<String> keySet() {
        JsArrayString array = keys();
        Set<String> set = new HashSet<String>();
        for (int i = 0; i < array.length(); i++) {
            set.add(array.get(i));
        }
        return set;
    }

    public final native String get(String key) /*-{
        return "" + this[key];
    }-*/;

    public final native String get(String key, String defaultValue) /*-{
        return this[key] ? ("" + this[key]) : defaultValue;
    }-*/;

    public final native void set(String key, String value) /*-{
        this[key] = value;
    }-*/;

    public final int getInt(String key) {
        return Integer.parseInt(get(key));
    }

    public final boolean getBoolean(String key) {
        return Boolean.parseBoolean(get(key));
    }

    public final native JSOModel getObject(String key) /*-{
        return this[key];
    }-*/;

    public final native JsArray<JSOModel> getArray(String key) /*-{
        return this[key] ? this[key] : new Array();
    }-*/;
}

This class alone allows you to easily parse JSON returned in a callback. For example, here's an example of parsing Twitter's User Timeline in my OAuth with GWT application.

private class TwitterApiCallback implements RequestCallback {
    public void onResponseReceived(Request request, Response response) {
        if (response.getStatusCode() == 200) {
            JsArray<JSOModel> data = JSOModel.arrayFromJson(response.getText());
            List<JSOModel> statuses = new ArrayList<JSOModel>();
            for (int i = 0; i < data.length(); i++) {
                statuses.add(data.get(i));
            }

            // populate textarea with returned statuses
            for (JSOModel status : statuses) {
                payload.setValue(payload.getValue() + status.get("text") + "\n\n");
            }
            
            Label success = new Label("API call successful!");
            success.setStyleName("success");
            form.add(success);
        } else {
            onError(request, new RequestException(response.getText()));
        }
    }

    public void onError(Request request, Throwable throwable) {
        Window.alert("Calling API failed. " + OAuthPage.STANDARD_ERROR + "\n\n" + throwable.getMessage());
    }
}

To simply things even more, we created a BaseModel class that can be extended.

import java.util.Map;
import java.util.HashMap;

import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.DOM;

public abstract class BaseModel {

    protected JSOModel data;

    public BaseModel(JSOModel data) {
        this.data = data;
    }

    public String get(String field) {
        String val = this.data.get(field);
        if (val != null && "null".equals(val) || "undefined".equals(val)) {
            return null;
        } else {
            return escapeHtml(val);
        }
    }

    public Map<String, String> getFields() {
        Map<String, String> fieldMap = new HashMap<String, String>();

        if (data != null) {
            JsArrayString array = data.keys();

            for (int i = 0; i < array.length(); i++) {
                fieldMap.put(array.get(i), data.get(array.get(i)));
            }
        }
        return fieldMap;
    }

    private static String escapeHtml(String maybeHtml) {
        final Element div = DOM.createDiv();
        DOM.setInnerText(div, maybeHtml);
        return DOM.getInnerHTML(div);
    }
}

You can extend this class and create model objects that represent a more Java-like view of your data. For example, I could create a Status class with the following code:

public class Status extends BaseModel {
    
    public Status(JSOModel data) {
        super(data);
    }

    public String getText() {
        return get("text");
    }
}

Then I could change my JSON parsing in TwitterApiCallback to be:

    private class TwitterApiCallback implements RequestCallback {
    public void onResponseReceived(Request request, Response response) {
        if (response.getStatusCode() == 200) {
            JsArray<JSOModel> data = JSOModel.arrayFromJson(response.getText());
            List<Status> statuses = new ArrayList<Status>();
            for (int i = 0; i < data.length(); i++) {
                Status s = new Status(data.get(i));
                statuses.add(s);
            }

            // populate textarea with returned statuses
            for (Status status : statuses) {
                payload.setValue(payload.getValue() + status.getText() + "\n\n");
            }

            Label success = new Label("API call successful!");
            success.setStyleName("success");
            form.add(success);
        } else {
            onError(request, new RequestException(response.getText()));
        }
    }

    public void onError(Request request, Throwable throwable) {
        Window.alert("Calling API failed. " + OAuthPage.STANDARD_ERROR + "\n\n" + throwable.getMessage());
    }
}

That's how we're doing lightweight JSON parsing with GWT. I've updated my GWT with OAuth demo with this code. You can also download the source. Please let me know if you have any questions.

Update October 20, 2009: I recently had to enhance the JSOModel and BaseModel classes in my project to handle nested objects and arrays. In my project, I have a Conversation object that has a Channel and a List of Task objects. These objects are available in the JSOModel of my BaseModel, I just needed to grab them a bit differently.

public Channel getChannel() {
    return new Channel(data.getObject("channel"));
}

public List<Task> getTasks() {
    JsArray<JSOModel> array = data.getArray("tasks");
    List<Task> tasks = new ArrayList<Task>(array.length());

    for (int i = 0; i < array.length(); i++) {
        Task task = new Task(array.get(i));
        tasks.add(task);
    }
    
    return tasks;
}

To set a Channel, it's as simple as:

data.set("channel", channel.toJson().toString());

To allow setting Lists, I had to enhance JSOModel by adding the following two methods:

public final void set(String key, List<JSOModel> values) {
    JsArray<JSOModel> array = JavaScriptObject.createArray().cast();
    for (int i=0; i < values.size(); i++) {
        array.set(i, values.get(i));
    }
    setArray(key, array);
}

protected final native void setArray(String key, JsArray<JSOModel> values) /*-{
    this[key] = values;
}-*/;

After making this change, I was able to convert my List to List and set it on the underlying JSOModel.

public void setTasks(List<Task> tasks) {
    List<JSOModel> values = new ArrayList<JSOModel>();
    for (Task task : tasks) {
        values.add(task.getModel());
    }

    data.set("tasks", values);
}

To allow the task.getModel() method to work, I added a getter to BaseModel to allow retrieving the underlying JSOModel. Currently, I'm using a homegrown JSON.java class to produce JSON from my BaseModel objects. It all seems to work great and I'm pumped I can receive and send all my JSON using overlay types.

Posted in Java at Jun 24 2009, 09:52:49 AM MDT 10 Comments

Enhancing Evite.com with GWT and Grails

Evite.com On my LinkedIn Profile, it says my current gig is a SOFEA consultant at a stealth-mode startup.

SOFEA Consultant, Stealth Mode Startup, Los Angeles, CA. December 2008 -- Present.

OK, I lied. It's not a startup, it's a well-known company that helps you plan parties. For the last 5+ months, my UI team from LinkedIn has been working with Evite.com to enhance portions of their site with a SOFEA architecture.

In January, we started evaluating Ajax Frameworks and came to the conclusion that GWT was right for us. After we chose the UI framework, other team members chose Grails and memcached to develop scalable RESTful services. The architecture we implemented involves using GWT's RequestBuilder to talk to Grails' services, which cache almost all their JSON output in memcached.

To see an example of a feature we developed with GWT, see Evite's Design Gallery. I personally worked on this feature and very much enjoyed becoming a GWT aficionado in the process. GWT's zero-turnaround feature made doing pure client-side work a lot of fun. It's definitely something I'd like to continuing doing at my next gig.

Everyone from Evite is very happy with what we've been able to do with GWT and Grails. We have a stateless architecture and are quickly able to develop both client-side and server-side features. We've learned to scale the client by using out-of-the-box GWT components. We've scaled Grails by caching as much as possible. We serve up Ads and Analytics using the same JavaScript mechanisms that traditional server-side frameworks use.

At the end of this month, my gig with Evite comes to an end. I'll be spending a few weeks at my family's cabin in Montana and then it's on to the next big thing. What's the next big thing? I'm not sure yet, hence the reason for writing this. If you're looking to develop a GWT application, introduce a SOFEA architecture at your company, or simply adopt some open source frameworks, I'd love to help out. Drop me a line and let's start a conversation.

Posted in Java at Jun 15 2009, 07:41:37 AM MDT 9 Comments

Ajax Framework Analysis Results

Way back in January, I wrote about how my colleagues and I were evaluating Ajax frameworks to build a SOFEA-style architecture. To make our choice, we used the following process:

  1. Choose a short list of frameworks to prototype with.
  2. Create an application prototype with each framework.
  3. Document findings and create a matrix with important criteria.
  4. Create presentation to summarize document.
  5. Deliver document, presentation and recommendation.

When I wrote that entry, we had just finished step 2 and were starting step 3. I first wrote this blog post a week later, when we delivered step 5. Here is the comparison and conclusion sections of the analysis document we composed.

Framework Comparison
In order to evaluate the different frameworks against important criteria, we created a matrix with weights and ranks for each framework. This matrix shows how our weighting and rankings lead us to the winner for our project. You can view this matrix online or see below for a summary.

Note: Criteria whose values were identical across all candidates were weighted at zero. Charting capability was weighted at zero b/c we decided to use Flash for this.

This matrix indicates that GWT is the best candidate for our team to develop SOFEA-style applications with. In addition to the matrix, below are graphs that illustrate interesting (and possibly meaningless) statistics about each project.

Number of Committers

Books on Amazon

Conclusion
After working with the various frameworks, we believe that all the frameworks were very good and could be used to write applications with. If all weights are equal, these frameworks were almost even when compared against our evaluation criteria. The graph below illustrates this.

Ranking with equal criteria weights

Even after applying the weighted criteria, the evenness doesn't change a whole lot.

Ranking with weighted criteria

Without considering the even or weighted criteria, we believe the decision all comes down to what the developers on the project feel they will be most comfortable with. If you're developing with Dojo or YUI, chances are you're dressing up existing HTML and possibly using progressive enhancement to add more rich functionality. On the other hand, Ext JS and GWT are similar to Swing programming where you build the UI with code (JavaScript for Ext JS, Java for GWT).

The tools available for JavaScript development have gotten increasingly better in recent years. IntelliJ IDEA has a JavaScript Editor that provides many of the same features as its Java editor. Aptana Studio also has excellent support for authoring and debugging JavaScript. However, we believe the Java debugging and authoring support in IDEs is much better. Furthermore, we are more familiar with organizing code in Java projects and feel more comfortable in this development environment.

Based on this evaluation, we believe that GWT is the best framework for our team to develop SOFEA-style applications with.

Flash Forward to Today...
The core GWT library from Google doesn't have a whole lot of widgets, nor do they look good out-of-the-box. So early on, we experimented with two alternative implementations that continue to leverage GWT concepts and tools:

  • GXT: a GWT version of Ext JS
  • SmartGWT: a GWT version of SmartClient

Unfortunately, over the past few months, we've found that both of these implementations are too heavy for our requirements, mostly because of the file size of the generated JavaScript code. For example, a feature I wrote generated a 275K *.cache.html file using GXT. After determining that was too slow to give users the initial "pop", I re-wrote it without GXT. After a day, we had an application with *.cache.html files of 133K. Yes, that's over a 50% reduction in size!*

Because of these findings, we are proceeding with the core GWT library from Google and adding in new components as needed. It is cool to know you can make a UI "pop" with GWT, as long as you stick to the core - close-to-the-metal - components. For those applications that can afford an initial "loading..." state, I'd definitely recommend looking at GXT and SmartGWT.

* To make refactoring easier, I copied GXT MVC into our source tree and modified all imports.

Posted in Java at Apr 23 2009, 08:34:44 PM MDT 53 Comments

Nexus is a kick-ass Repository Manager

I started my current gig at the end of last year. I've been enjoying the work and especially the project infrastructure we've been using. We're using the usual suspects: JIRA, Confluence, Hudson and Subversion. We're also using a couple new ones, namely sventon and Nexus. For building, we're using Maven and Ivy (as a Grails plugin).

Nexus I'm writing this post to talk about Nexus and how much I've enjoyed using it. I like Nexus for two reasons: it's aesthetically pleasing and it's well-documented. Another reason I really dig it is because I haven't had to touch it since I first configured it. Software that just keeps on humming is always fun to work with.

Initially, I remember having some issues setting up repositories. I also remember solving them after learning how groups work.

In addition to on-the-job, I've started to use Nexus more and more in my open source life. With the help of Jason van Zyl, I recently moved AppFuse's repository to Sonatype's oss.sonatype.org. I also noticed there's a Nexus instance for Apache projects. If that's not enough, you can get Nexus Pro free if you're an open source project.

Personally, the open source version of Nexus seems good enough for me. While the Staging Suite looks nice, I think it's possible to do a lot of similar things with good communication. After all, it's not going to free you from having to wrestle with the maven-release-plugin.

Next week, I'm helping to polish and document our entire release process (from dev → qa → production). If you have any advice on how to best perform releases with Maven, Grails and/or Nexus, I'd love to hear about it. My goal is extreme efficiency so releases can be done very quickly and with minimal effort.

Posted in Java at Mar 05 2009, 11:59:02 PM MST 13 Comments

Comparing Web Frameworks Book

A publisher recently sent me an e-mail asking some advice. They received a proposal for a book that compares CakePHP, Symfony, Zend, TurboGears, Django, Struts, RoR. Here's a quote from the proposal:

We would like to compare a couple of frameworks and present their advantages and disadvantages in various applications.

Obviously, that kind of manual would be very useful for readers who are starting their 'adventures' with web applications, as it would facilitate their choosing the best framework for their particular application. The manuscript would offer a comparison of the most popular solutions (CakePHP, Symfony, Zend Framework, TurboGears, Django, Struts, Ruby on Rails) and demonstrate the main differences between each.

Therefore, the target audience would mainly be project managers, responsible for deciding on the technologies to be used for in-house projects, as well as less experienced, web application beginners.

Another purpose of the book would be to present 'good practices' in various frameworks, such as code re-factoring, design patterns and application security. From this point of view, it could become a valuable asset for experienced and learner programmers alike.

Since I got a lot of feedback from my tweet on this subject, I figured I'd ask it here.

What do you think of such a book?

Here's my response:

How do PHP books do these days? Of the list of frameworks (CakePHP, Symfony, Zend Framework, TurboGears, Django, Struts, Ruby on Rails), I think there's interest in Django and Rails, but not so much the others. And Struts sucks, so having that as a comparison is obviously going to make it look bad. I wouldn't buy it, but I'm a Java guy that's mostly interested in web frameworks that make developing SOFEA-based applications easier. In my mind, these are Flex and GWT.

The book I'd like to see would cover developing RESTful backends and SOFEA front-ends. RoR, Grails or Django could be used to develop the backend and Flex, GWT and X could be for the front-end. In reality, this is probably a tough book to write b/c things move so fast. If you decide to do it, I'd keep it short and sweet so you can get it to market and update it quickly.

Posted in Java at Feb 23 2009, 09:49:15 AM MST 17 Comments

What's the Best Retirement Plan for Independent Consultants?

Before writing How To Setup Your Own Software Development Company, I sent my Financial Planner the following e-mail.

I'm writing up a blog post on how to setup a Software Development Company for consultants and wanted to see what retirement plan I have. I'd like to recommend it (or others, if there's better deals). Do you have the name and a 2-3 sentence description?

Below is his response:

You have a SEP IRA but depending on how much they make and their savings objective they may also want an Individual 401K and/or Defined Benefit Plan.

A SEP IRA allows you to set aside up to 20% of your income after business expenses, up to $49,000 for those with income of $245,000 or more in 2009. An Individual 401K allows you to save a higher percentage of your income depending on your age and income. If you are under age 50 you are able to save $16,500 so long as your income is at least $16,500 (plus FICA, etc) and $22,000 for those over age 55. You are also able to set aside profit sharing and matching contributions in a 401K Plan. Those under age 50 have a maximum of $49,000 while those over age 50 have an increased limit of $54,000. Finally, for those who wish to save more, you could establish a Defined Benefit Plan and make contributions based on your age and income that total potentially more than $200,000 per year. If you establish a Defined Benefit Plan you are still able to have an Individual 401K Plan but the limits are the employee contribution amount ($16,500 or $22,000) plus 6% of your income up to $245,000 (another $14,700) for a combined total that could be well over $200,000 depending on your age and income.

There is always the Roth and Traditional IRA but those are very basic planning tools - they should still be used and considered but everyone should be familiar with them. 2009 allows $5,000 deposit for under age 50 and $6,000 for over age 50. Roth contributions are limited starting at $105,000 if filing single and $166,000 if married filing joint.

Of course, a perk of working for a company with benefits is they sometimes do 401K matching. However, I'd expect many company to be cutting back on that in this economy. If you're an independent consultant, do you have a retirement plan? Do you think you're doing as well as you could if you were a full-time employee?

Posted in Java at Feb 13 2009, 01:44:52 PM MST 8 Comments

What's the best Java Hosting Solution?

A friend recently asked me who I'd recommend for a Java hosting provider. Since I get asked this question every-so-often, it seemed appropriate to post my answer here.

  1. KGB Internet - I use KGB for this site. I have my own JVM and have full control over what I want to install. I can control Tomcat versions and upgrade as needed. I don't know if I'd recommend him for a business site as he can take up to 12 hours to respond to requests.
  2. Kattare - These guys will give you your own Tomcat instance and seem to have reasonable prices. They do seem to take quite some time to respond to requests (24-48 hours). I have a free instance that I use for a non-profit, so that could be the reason.
  3. Contegix - These guys are far-and-away the best company for Java-based hosting. They're not cheap though. However, they have the best customer service in the business - often responding to e-mails in less than a minute.

Do you agree with these recommendations? If not, who do you recommend for Java hosting and why?

Posted in Java at Feb 07 2009, 10:21:28 AM MST 38 Comments

2008 - A Year in Review

In 2005 and 2006, I did "A Year in Review" entries. 2007 was the year I got divorced, which probably motivated me to write a bit less. This year I'm back and ready to spend the next few hours writing, copying/pasting and linking like a madman. Hope you enjoy!

Workin' on the Feedlot 2008 was the year I traveled the world and developed a true passion for skiing. In January, my good friend Jason Miller moved back to Denver after quitting his job at Bear Stearns in NYC. We spent the first weekend in Nebraska working on Cletus's feedlot. The next week, my car stereo got stolen and I wondered if my bad knee would make it through the ski season (the good news is not only did I ski the rest of the season, but my knee healed itself over the summer).

Abbie and Jack on Green Mountain At the end of January, the kids and I hiked to the top of Green Mountain and Don Brown made Maven not suck. Then I wondered if there was room for both Rails and Grails at a company and quickly learned both.

February started fantastically with a 14" Powder Day at Steamboat. I wondered if there is no "best" web framework and reviewed Grails and Rails books. After spending an awesome weekend in Tahoe, I took the kids on The Ski Train and learned more about Selenium at Google.

Breathtaking Miller and Vial Lake Tahoe - Last Run

This brings us to one of my favorite posts of all time. On February 28th, Jack got a bead stuck in his nose. After taking him to the ER and paying $800, we found out magic recipe for bead removal is to "hold one nostril and give him a CPR-type breath/blow into his mouth". The reason I love the post so much is it's solved the problem for other frantic parents when they Google for "bead stuck in nose". Whenever I get a new comment, it always makes me smile.

March started out with a Powder Day at Whistler. I thoroughly enjoyed the rest of the weekend with good friends Jarvis and Korn Dog. After returning to Denver, I was allowed to blog about building a UI Frameworks Team at LinkedIn and posted my thoughts on Grails vs. Rails.

View from Our Condo In mid-March, I achieved an all-Mac family and traveled to Lake Chelan for my sister's birthday. Shortly after, The AppFuse Primer was released. At the end of the month, I attended TSSJS in Vegas and moderated a Web Framework Smackdown.

In April, the LinkedIn Denver office opened and we all celebrated by attending the Rockie's Home Opener. The ski season came to an end and I wrote a howto for configuring Apache with mod_proxy and SSL on OS X. Then I discovered the JavaOne parties and wrote about running Spring MVC Web Applications in OSGi.

April ended with 82°F and May started with snow. I attended JavaOne (or at least the parties), released AppFuse 2.0.2 and figured out how to do extensionless URLs with the UrlRewriteFilter. The kids and I spent an afternoon in Rocky Mountain National Park and I did some coding in my backyard.

Jack's Special Rock Nice Trail Beautiful Smile Here's Hoping for another run in October

On Memorial Day, I enjoyed a liver-wrenching, Rockies-filled weekend with my sister her girlfriend Mya and Mr. Miller. I also contemplated making AppFuse Struts 2-specific.

June started with some mountain bike riding, planning some excellent vacations and getting a dream machine. I rode the annual trip to Big Head Todd at Red Rocks with Matt and Bruce. I took the kids on their first camping trip for Father's Day and had a blast. It took us several hours to find the campsite and my car kept starting all night long. It's sure to be a family tradition from now on.

Catchin' Bugs

The next weekend, I attended the American Craft Beer Fest in Boston. To end the month, I embarked upon Raible Road Trip #12 with Abbie, Jack and my Dad.

Grand Tetons In July, the bus project began and I posted pictures of the trip to Montana. This year, I hope to spend the whole month of July at the cabin. I bought an iPhone (one of my best technology-related purchases to date). OSCON was fun but the week after wasn't.

Nice 'n Snug August revealed my favorite birthday present. I didn't blog much the rest of the month, revealing why later.

Jack on his 4th Birthday Jack's Birthday Weekend was an outstandingly fun mixture of old friends and good Colorado beer. In September, I went to see the bus at MotorWorks, Abbie lost her first tooth and co-workers and I performance tested Memcached.

What followed was wonderful. Miller and I headed to Oktoberfest for the Best. Vacation. Ever. We still talk about how much fun we had on that vacation. October finished with the Colorado Software Summit and a hunting trip to the cabin.

November was a crazy month. I got laid off and celebrated Abbie's birthday on the same day. Jack got a mohawk and I traveled coast-to-coast in the same week. To close the month, I announced what's next and headed to Costa Rica.

Costa Rica, courtesy of Rob Misek

I had a fantastic time in Costa Rica and was impressed to see Abbie is a blue skier shortly after. I did a Dojo/Comet Research Project for a week and enjoyed the location of my newest client last week. A small adventure turned into a scary adventure and I enjoyed telling my stories to fellow Java Enthusiasts in Portland.

Phew! It's been quite a year. For 2009, I'm still hoping for what I tweeted shortly after Costa Rica. I'd like to visit 3 foreign countries, take 3 months of vacation and spend 1 month in Montana. I have technology goals too, but those aren't nearly as much fun to dream about. ;-)

Happy New Year!

Posted in Roller at Dec 31 2008, 04:56:32 PM MST 2 Comments