Skip to content

All posts by moore - 60. page

Upgrading to GWT 2

I recently had the pleasure of upgrading from GWT 1.5.3 to GWT 2.0.  The client has a variety of GWT applications–some standalone widgets that integrate into an existing site, an application written with GWT look and feel, and an application written with the GWT-EXT library.

The upgrade to GWT 2.0 was much less painful than I thought it would be.

Even code that was written for GWT 1.0 (the mortgage calculator, written back in 2006) compiled cleanly (well, plenty of warnings, but no loss of functionality).  Classes that have been deprecated (some for good reason; hello HTTPRequest, I’m looking at you) have not disappeared.  I’m not saying that the code I wrote for GWT 1.0 shouldn’t be rewritten, just that GWT hasn’t forced me to do so.  Also, other than changing some switches to the command line compiler, the ant script used to compile the GWT modules didn’t have to change at all.

Hosted mode was a different story.  I never really spent a ton of time in hosted (err, dev) mode, but had it working in that past.  Now, I wanted to get it working fully because of the tremendous productivity gains possible–no minute long compile cycle to pull my attention away from my code.  And the fact that you can run and debug in eclipse in more than just one browser is really attractive.  Since I’d never really had it working fully, there wasn’t a lot of upgrade work; it was more like starting from the beginning.  However, I was unable to use the internal jetty server.  Again, my use case is atypical, with a lot of JSON and JSONP requests for data.

Big pluses for GWT 2.0, right off the bat:

I haven’t yet looked into Speed Tracer or some of the updated widgets (I’d really love to toss the gwt-widgets lightbox we use in favor of the GWT standard PopupPanel).  There’s also the tremendous benefit of being on the modern version of any platform–it is easier to get support in forums and in other venues.

GWT widgets and code splitting, a match made in heaven

If you are writing a typical GWT application, which is monolithic and controls the entire viewport of the browser, you probably don’t want to read this post.  Go on, read something else interesting–you probably have emails or tweets or something better to do with your time.

OK, now we just have the people left who are using GWT to build widgets; that is small encapsulated pieces of functionality that integrate into an existing web based application (case #2 outlined here).  If you’re doing this, and you use the “span to enable” gwt mini pattern, you want to upgrade to GWT 2.0 simply to get the new code splitting functionality.  If you don’t want to read that previous link, the synopsis is that code splitting lets you define a number of pieces of distinct code, using GWT.runAsync.  Then, that code won’t be downloaded until it is reached.

Previous to this feature, if you had a number of widgets, you ended up with a large chunk of code to download on every page (this is an issue with GWT that the monolithic applications simply don’t have to deal with).  Some of that code will be run.  Some will not, but you’re still paying for download and parsing of that code.  You had some unsavory options to deal with this–let all the code be downloaded, or manually split up code into separate modules that you managed (either by hand or with deferred binding).  The second solution led to smaller downloads, but meant a lot more management–if you wanted to add a widget to a page, you not only had to add the enabling span, you had to recompile the entire GWT module–and much longer compilation when you deployed your entire web application.  However, if your widgets were static, this path might have been an option.

My client used the former solution (entire code download on every page), and was very excited about the code splitting, since that essentially automates the second choice above.  In the space of about one half hour, I was able to reduce the initial download size of the GWT javascript by 10%, and there’s scope for much more, since the code is pretty naturally split up into separate chunks for each widget.

It’s not perfect, however. The two concerns I’ve had so far:

  1. The XS linker is not supported.  This means that if any of your widgets need to be cross domain, you need to create an additional module specifically for that.  For example, if I have one module, A, which is used to start up all the widgets on the site, and inherits from both module B, which has some GWT code split calls, and module C, which needs to be cross domain, the compiler will error out when compiling module A.  I need to create a second module XSModuleC which inherits from module C and is compiled by the XS linker, and then use that module for all cross domain purposes.
  2. If you call GWT.runAsync from an event handler, like onClick, you will not have a valid event on the first call (when the module is loaded) but will on all subsequent calls.  This is easy to fix, but was a bit mystifying to me.  Basically, if you have code like this:

onClick(ClickEvent event) {
if (event.getSource() instanceof Image) {
// do something with image
}
}

you need to replace it with:

onClick(ClickEvent event) {
if (event.getSource() instanceof Image) {
// save event.getSource into an instance variable
GWT.runAsync(new RunAsyncCallback() {
// do something with image in instance variable
}
}
}

I'm sure there are other complications I'll find once I do more code splitting.  (Here's an interesting post about code splitting in large applications, and simplifying the API of code that is split (plus, you get to see the word cromulent in context).)  But, for now, code splitting and GWT widget development seem like a match made in heaven.
[tags]gwt,code splitting[/tags]

Finding supported GWT user.agent values

The GWT compile process has been taking longer and longer, as I’ve moved from 1.0 to 2.0, because they keep adding optimizations and functionality.  You could deal with this in a number of ways.  You could write less GWT.  You could buy a faster computer.

More realistically, you could live in your IDE, and run in development (nee hosted) mode.  However, sometimes you just have to test with javascript.  The external browser development environment can be tough to set up correctly, especially if your application depends on external resources, and you can run into weird bugs.  I’m currently dealing with an issue where I depend on an external library and it is consistently throwing an assertion exception in development but runs fine in production mode.

If I am compiling to javascript repeatedly, I often compile for just one user-agent, which saves about 80% of the compile time.  When I have code more put together, I can compile for all other browsers.  This process is not flawless, as I am currently debugging a cross browser issue (something that works fine on FF doesn’t work on Safari) but I probably wouldn’t have tested on Safari until after I was through the lion’s share of development anyway.

The way to target just one browser is to put this string in your module (.gwt.xml) file:

< set-property name="user.agent" value="safari,ie6,gecko1_8" / > (remove the spaces next to the angle brackets)

How do you find valid values?  Via this thread, I found that you look in UserAgent.gwt.xml, part of the gwt-user.jar file.  This has the javascript code that looks at navigator.userAgent.  It is not as fine grained as the ubiquitous browser detect script, but shows you what different browsers are known to GWT.

For other tips on speeding up the compile process, check out this series of posts.

[tags]gwt,user.agent,gwt compiler, slow as molasses[/tags]

Andrew Hyde: tips for your startup job hunt

Andrew Hyde, Boulder startup hub, gives some tips on the startup job process.  Having been a part of a few startups, I thought I’d review the high points of the list, but it’s worth a read regardless.

Lots of his tips are useful to people hunting for jobs at established companies as well–I’ve long been a believer in personal blogging (#12) as a ‘living resume’ (among its other benefits), and the research required to write a blog post about the company (#10) will be useful to you as well.  Here’s another post with good tips.

I especially enjoyed his riff on generalists: “In the history of startups, not a single ‘generalist’ has ever been hired.  They are called founders.” I’m not sure I entirely agree, but I do think that if you want to be hired for money at a startup, you should have a strong focus (whether that be development, marketing, sales, operations, etc, etc).  However, even if you are hired as, say, a developer, you’ll need to do other things (testing, customer service, perhaps even marketing)–that’s part of the fun.

He does give some contradictory advice: have a resume in PDF (#2) but at the same time “ditch a resume” (#8).  I think he means that while a resume is nice, startups are more interested in specific projects and achievements than a typical big company with an HR department.  Some argue one should approach all job interviews in the same manner.
The most important piece of advice that Andrew gives is #7, which is worth quoting in full:

Be clear.  You are looking for a job.  Cut the buzzswords, what is the best fit?  Steady?  Fast paced?  Live in Boulder?  Just say it.  Cut the shit.

In my job hunts, knowing what I actually wanted was the hardest task, but the most important.  Why is it hard?  When I’ve been looking for a job, I am anxious and concerned about the future, often thinking about my slowly draining savings.  Declaring what I actually want (beyond “a job, any job, please God, give me a job” which is sometimes how I feel 🙂 ) necessarily excludes opportunities.  However, that is the exact reason that it is the most important task.  By excluding opportunities that wouldn’t be a good fit, or would make me bitter, or wouldn’t serve the employer well, I freed myself up to focus on situations where I could help the employer succeed and be happy.

[tags]startup jobs[/tags]

Real life inspiration from laid off ad agency workers

“Lemonade” is a great 35 minute movie about people making lemonade from getting laid off.  The “lemonade” ranges from coffee roasting to yoga; artist to blogger (on ads, or on employment).

The content is entirely interviews with people were laid off from advertising agencies.  But the advice is good for anyone.  As always, good advice is easy to give or hear and hard to follow.

Here’s four ways to support the movie makers if you should be so inspired.

Via Seth Godin.

Online Tools for Enriching an Offline Community, CSA edition

I had a meeting yesterday with a Anne Cure, a farmer, and her web specialist.  She grows food that I buy via my CSA (community supported agriculture) share–I have a list of Colorado CSAs if you’re looking.  Anne, and the rest of the farmers she works with, has created a great offline community as part of the CSA.  There are multiple events at the farm, including an end-of-year pig roast.  As a CSA member, you get great veggies, you are part of a community and you support a local farm.  It’s win-win-win.

I asked Anne to meet with me because I felt that, while there was some member to member interaction, it wasn’t as prevalent as it could be.  Often, at CSA pickup, I wouldn’t talk to anyone except for Anne, or one of the other farm workers.  And I rarely observed any of the other members having any interactions either.

Being a web guy, I thought that bringing the community online might help.  Of course, there are always challenges around that–it takes work to maintain an online community too!

Here’s a list of all the ideas I thought of to leverage the offline community Cure Organic Farm has built, as well as some we discussed during the meeting.

Some of these ideas take little effort, some take a lot.  Some bring in revenue, some don’t.  Some put all the effort onto existing staff, others leverage excited community members.  Some had been done already, some they had never heard of.

Hopefully anyone else who has created an offline community can pick and choose useful tools and ideas, from below, to enhance that community online.  If you have additional suggestions, please feel free post them in the comments.

  • Use posterous to create a dead simple blog.  Leverage its auto posting capabilities to push content into other social networks (twitter, Facebook, etc, etc).  Use twitter/FB to drive traffic to their farmstand.  Cure Organic Farm does already have a Facebook page.
  • Use email list management software, like MailChimp, and look at the reports to see if email is a useful (aka ‘read’) means of communication.
  • Promote carpooling to pick up CSAs–save gas and promote interaction between members.  Consider using a tool like Divide the Ride.
  • Add a page of ‘Cookbooks Anne Uses’ (they already have a links page of various recipe sites).  Have that link to Amazon and you could possibly make latte money from it.
  • Cure Organic Farm puts out a great weekly newsletter during the CSA season, full of quotes and recipes.  However, searching it is an issue (I suggested Google Custom Search).
  • Also, making those recipes available in some kind of ingredient specific manner would be useful.  Even if the recipes aren’t broken out, just knowing that I can find a recipe for garlic scape pesto in newsletter #5 from 2008 is useful.  This could be done with a simple database or even plain HTML.
  • Forums, of course, are great community building tools.  They also are great for spam.  I imagined forums being used for sharing food knowledge (recipes, ‘how do I use 3 lbs of beets?’), though you could also share community events and even barter goods.  The issue with forums, as ever, is moderation–how to make sure that people are not abusing the forum (or each other).  This qualifies as a high input/high possible return tool.
  • An online calendar.  Both for specific events, such as the aforementioned pig roast, and informal knowledge, like when tomatoes are expected to be ripe, would be great to have on a calendar.
  • Online registration for CSA membership and other event payment.  They do online registration already (if the shares haven’t already sold out).  They currently use paypal, and the fees can really eat into the farm’s profits, so they don’t see a bigger effort into this area being useful.
  • Classifieds.  Kinda like the forums but for money or free.  Same model as craigslist, but aimed at a self selected group of people.  Again, moderation and ensuring appropriate use are challenges.
  • Using a ready-setup community building site like ning could help accelerate online community building.  I also pointed them to the great Transition Colorado Ning site, so they could see what a related organization was doing.
  • Use wufoo (or email) to let users submit newsletter content.  Just sharing what other businesses and professions other CSA members are in can help knit the community tighter.
  • Advertising on the site.  They weren’t too keen on this, but I think that the correct type of advertising would be useful.  Again, possibly too high effort to be possible.
  • List of links to local resources.  They are already doing this, but should make it easier for people to request addition.
  • Write a blog.  This is a higher input version of the posterous suggestion, but I think it would be fascinating.

Cure Organic Farm is a niche producer of vegetables, with a fiercely loyal CSA membership (shares almost always sell out within days of being open to the public) and proximity to Boulder, so their toolset will necessarily differ from another organization (imagine a farm just starting off, further out, with less reputation).  Hopefully some of these ideas and tools will be helpful to others thinking about strengthening offline community using online resources.

[tags]community supported agriculture, online tools, offline community, pig roast[/tags]

Why Are You Following Me on Twitter?

Don’t you know that I’m a web developer posting geeky stuff and you’re a bar posting specials?

I joined the Twitter movement a while ago (not a first mover by any means) but have been actively using it more in recent months.  I find it useful as well as diverting.  However, I don’t want to discuss how I use it right now; what I want to focus on is a behavior that interests me.

It seems if I follow someone, mention anyone by name, or tweet on a topic of interest once, there’s a reflex for people to follow me.  This doesn’t happen all the time, but happens often enough that it bears examining.  Why would someone do this?

  • if I posted once on a topic of interest, I might post again
  • it’s easier to follow and then unfollow than it is to read my twitterstream and see if I’m actually worth following
  • I might follow someone who follows me, and followers are good
  • Someone might know me (online or offline) and a tweet might have alerted them to my presence on twitter
  • Someone might have seen my tweet, clicked through to my profile, and thence to my website, read a couple (or all :)) of my posts, considered whether or not I might have more of interest to say, and followed me.

Those are the main reasons I can think of.  Did I miss any? Oh, and the last couple are improbable, based on my web stats.

I think it’s early in the Twitter game, especially for the pragmatists (Twitter having crossed the chasm), and it feels like the early days of my RSS reader (when I first discovered the wonderful world of blogs).  Any time I stumbled upon a blog that had an interesting post, I added the blog’s feed to my RSS reader.  Eventually, I was following hundreds of blogs.  For a while, I kept up, reading the new posts diligently, but because of real life and work, I fell behind.  Now, I rarely open Bloglines–I know which blogs I want to check out and just visit them directly.

I think the same thing can happen to your twitter home page–if you add people indiscriminately (or even slightly discriminately) you risk polluting it and decreasing its value.  Note that I don’t use any of the tools built around Twitter.  They may help manage this issue–and I hope they do.

Because it is so easy to follow people on Twitter (easier, in fact, than determining whether it would be worthwhile to follow them), it’s also easy to clutter up your experience.  In the end, I believe this clutter will either drive you away from Twitter, or force you to spend time unfollowing (or, as Dion put it, “gardening”).

[tags]twitter, crossing the chasm, social media[/tags]

The future of the web browser…

… from the perspective of people building platforms for add-ons (or plugins or extensions or what-have-you): this collection of videos from the keynote of the Add-on-Con covers a variety of interesting topics regarding browser development, the security model and how extensions fit, ad blockers and what they mean, and more.

Of the major browsers, Chrome, Opera and Firefox are represented–the Microsoft/IE representative was sick, and Apple/Safari was MIA.  It’s about 30 minutes of video, unfortunately split into 5 separate segments.  Well worth a view.
[tags]video killed the radio star[/tags]

Hibernate Boolean/Integer ClassCastException

I ran into an issue the other day with Hibernate configuration.

I have a bean that maps to a table in the database.  It has a column, featured, that only has values of 0 or 1.  For legacy reasons, we map that to an integer (turning it into a boolean is on the List Of Things To Do).

I ran into an issue, and was getting this error in the logs:

Caused by: java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.Integer
at org.hibernate.type.IntegerType.set(IntegerType.java:41)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:136)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:116)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1698)
at org.hibernate.loader.Loader.bindParameterValues(Loader.java:1669)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1554)
at org.hibernate.loader.Loader.doQuery(Loader.java:661)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
at org.hibernate.loader.Loader.doList(Loader.java:2211)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2095)
at org.hibernate.loader.Loader.list(Loader.java:2090)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:94)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1569)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)

Here's the relevant section of the mapping file:

<property name="featured" type="integer" columnn="featured" />

I tried explicitly laying out the type of the SQL column:

<property name="featured" type="integer">
<column sql-type="INTEGER" name="featured" />
</property>

But neither of these worked; I received the same error.

I took a step back and looked at the bean.

Integer featured;

public Integer getFeatured() {
return featured;
}
public void setFeatured(Integer featured) {
this.featured = featured;
}

...

and realized that I had added a convenience method that was confusing the Hibernate code:

public boolean isFeatured() {
return ...
}

When I changed the signature of the convenience method to:

public boolean isFeaturedListing() {
return ...
}

the exception went away.  Thought I'd share for anyone searching for this stacktrace.

[tags]javabeans[/tags]