Robert Cooper gave a great lightning talk at our recent Atlanta GTUG meetup, where he discussed using a single codebase to target multiple mediums (e.g. Android, Facebook, Wave, etc.). This post was taken from his original post, which is a good read, providing sound pointers as to how you can maximize audience reach with minimal code changes.
Robert's original post
I love crossword puzzles.
In the time before time, I would stop at my local coffee shop and purchase a copy of the New York Times. I would flip to the crossword and with the classic "double fold" begin the crossword puzzle. Mobile devices soon took over the world, and subscribing to the electronic version soon made much more sense than killing all those trees. Last fall, I switched from the orchards of Cupertino to an Android device, alas, there was no good way for me to do the New York Times puzzle on my way to work anymore. Time to start a project.
I developed the original version of Shortyz for Android (named in honor of, and with apologies to, Will Shortyz of the NYT) in about three weekends. It had a number of usability issues and was rough around the edges, but it was "Good Enough for Me." Unfortunately, because of stolen laptop I lost some progress on the source and my market signing key (yeah, I know). So I decided to "do it right." Forgoing the Android classes I implemented my own two-dimensional scrolling, touch handling and rendering code. Now I am quite happy with the results.
The new Shortyz code was much cleaner. I had implemented a Playboard class as the Controller of my MVC application and was completely independent of the UI code. I moved my IO classes out of the same package as my
Model classes, created a .gwt.xml file, and like that, I had the core of a GWT application. Implement a new UI and I am good to go.
Starting with my Android code, I had a playable web application in about five hours. Not bad, but like the first version of the Android code, I had some annoying usability issues and it was a little sluggish. After another day of work, I changed the UI code from using a play->render cycle like the Android app to use a more traditional MVC data binding system (based on Gwittir), and the performance problems were mitigated.
The next step was to take the web app and make it work everywhere! This is where Gin, a Google Guice DI for GWT apps, was key. My initial web app used a client side persistence mechanism to store play data (HTML5 LocalStorage, Gears, DOM Persistence, Flash). This works great for a standalone web app or a gadget, but for a Facebook version or Wave, I need alternative strategies. For my iGoogle version and Wave, I also need to make requests through the gadget.io API. Gin and Guice made this a breeze. Each of my versions simply becomes a new EntryPoint (or Gadget) class, a new Injector, and a new Module definition.
The real challenge came developing the Wave version. While Apache Shindig makes doing local development of Gadgets easy, there isn't an equivalent local harness for Wave gadgets, so you end up having to do a full build and deploy cycle to work on it. There are also some things that aren't clear from the Wave API docs that creep up, such as the maximum size allowed for the State object. After a solid 40 hours of work, though, I had a co-op play Wave gadget with player colors, remote cursors and nice playback support on the Wave.
So what is the take away here? "Extreme Source Compatibility" is a real thing. This is a Java application running on "Everything But The Java Platform" with the bulk of the code easily reused. Each subsequent version of the app took only a few hundred lines of code to get running. There are some important things to keep in mind. First, making sure your business logic and data models without dependencies on lots of external code is important. Since my Model layer was simple POJOs and my Controller layer pretty much just java.lang and java.util, there was a zero-hour ramp up time to make it work. Cleanly separating this code is also important. Since my input handling code and UI code was cleanly separated, this was much easier than it could have been to do the port. Finally, Guice rocks. While a lot of us in the "enterprisey" world understand the testability advantages of using a DI framework, many rarely have to provide lots of alternate implementations of classes. When you need it, though, it is amazingly handy to have a simple way to re-compose your whole application. Best of all, bugs I fixed in the core library while working on the web version rolled right into the original Android version unmodified.
As an interesting aside: GZipped, the GWT version is about the same size as the Android version; both are less than ~100K for the download. Custom code for each version makes up about 10% of the total LoC, with the exception of the Wave version where it is closer to 25%.
Quick colophon: Wave for GWT via CoboGWave: http://code.google.com/p/cobogwave/ Gadget Support: http://code.google.com/p/gwt-google-apis/ Gin, Guice for GWT: http://code.google.com/p/google-gin/ Data binding, local storage and JSON serialization: http://code.google.com/p/gwittir/