When I first started working on MemoryMiner in December 2004, I had completely had it with building web applications. I’d spent the prior 8 years creating a sophisticated and completely web-based Digital Asset Management system using great server-side technology from NeXT/Apple called WebObjects. Being able to deploy our app from day one as a hosted-service was huge, but there was only so much you could do to make a web application come close to what was possible, user-experience wise, on the desktop. I was therefore utterly thrilled to work full-time with Cocoa, especially since I was completely familiar with its precursor from my days working on NeXTSTEP applications.
Still, the web is critically important for a project like MemoryMiner, and it has been this part of the adventure with which I’ve most struggled. From version 1.0 onwards, MemoryMiner for the Mac has been able to publish sets of annotated photos to the web using a self-contained story viewer. The first two versions were done in Flash (by someone else), and while they worked OK what amazed me was how much effort it took to do something that I thought should have been easy, namely to read an XML file with descriptive data about a bunch of photos and display them in a coherent, pleasing fashion.
Here’s an example of the Flash-based Web Wiewer:
Beyond styling, even basic behaviors such as having an image resize proportionally and remain anchored while the browser window is resized was maddening. Was I asking for too much? I could never get it to work consistently across IE/Firefox/WebKit, so I just gave up. On the plus side, the general performance was quite good (loading time, CPU usage). Still, it bugged the crap out of me that doing the most basic things proved so difficult.
Fast-forward another year or so, and I hear about this web application called 280Slides and the Cappuccino framework used to create it. Playing with that app the first time was a revelation. I almost wept the first time that I started looking under the hood: the APIs and code syntax were immediately familiar to me as a Cocoa developer. I knew I could leverage a lot of know-how, and maybe even some code.
As soon as Cappuccino was made available to the general public, I started experimenting. How do you display an image using Cappuccino? You create a CPImageView instance and call setImage: passing it your CPImage instance. Works for me (and probably causes “traditional” web developers to roll their eyes). As a first experiment, I made a test app with the idea of creating a simplified version of the image annotation view I use in MemoryMiner for the desktop. I actually just started copying and pasting Obj-C code into a text editor, changing the class prefixes (i.e. NSImage becomes CPImage) and getting rid of pointers (e.g. NSImage *myImage becomes var myImage). Pretty soon, I had a view that could display a photo as well as draw selection markers (ummmm, drawRect:). Amazingly enough when I resized the browser window, things just worked. I didn’t write a line of CSS, I didn’t have to do one thing in FF/WebKit and something else in IE. This is what I was looking for!
By late Spring of 2009, I was pretty addicted, so I kept going with my prototype, adding the ability to create and edit selection markers, add captions to them and persist my model objects via a RESTful Rails back end. Mapping? Easy. There’s MapKit for that, along with a growing selection of high-quality third party code. Community? Got that as well. Among Cappuccino developers, I’ve found the same willingness to help each other out as we all strive for excellence.
In order to get the initial load time to where I needed it to be, I created a single application that I host on a small slicehost instance, with the web server configured to automatically compress all the .j (Objective-J) files in my application. Between the compression, and the image spiriting techniques that were introduced late last year, I’m pretty happy with the load speed. It could certainly be made faster by eliminating some of the unused code and image sprite data, and I’m confident that this, or other optimizations will be made. All you have to do is take note of the progress made by a tiny team in a rather short period of time.
Best of all, unlike the old system where each web viewer instance had all the code needed to display the content in the same folder as the content itself, the new system works by simply redirecting to the hosted web viewer app’s URL, passing the published RSS feed as a variable in the redirect URL. This means that once a user looks at their first published MemoryMiner viewer, any subsequent loading of any other story viewer will have the viewer code already in the browser’s local cache. Improvements made need only be made once in one place, just like in the “good old days” at my prior company.
Here’s an example of the Cappuccino-based web viewer:
While my first publicly shipping Cappuccino project is a read-only viewer, I’ve been working on a full-blown version of MemoryMiner for the web. It’s currently in early Alpha testing, and the feedback thus far has been extremely positive. The viewer and the app actually share a fair amount of code. Most importantly, both use the same Model View Controller design patterns we all know and love. My MMSSelectionMarker class in Cappuccino is virtually the same as its cousin on the desktop: the main difference is that one is persisted in a local sqlite database, the other in a web-service. Believe it or not, I’ve become pretty comfortable moving code back and forth between desktop and web. I implemented undo using Cappuccino before doing the same in Cocoa.
Still, compared to developing with Xcode & Interface Builder, developing a Cappuccino app still feels a bit primitive Fortunately, as Cappuccino has matured, it has been getting better tools, such as 280Atlas which lets you compose your UI layer graphically using real “freeze dried” objects that connect to each other using the familiar control-click and drag mechanism just like on the desktop It’s essentially IB and Xcode mixed together.
For whatever reason, people can easily get into flame-wars about web apps vs. desktop apps, and this toolkit vs. that toolkit. For my part, I really don’t care. I want MemoryMiner to be a person-centric application. Generally speaking, people want to interact their stuff on whatever device they happen to be using. I’ve found that Obj-C/Obj-J and Cocoa/Cappuccino give me lots of leverage because of the dynamic nature of the language, the richness of the frameworks and the availability of quality third party code. Others will say the same thing about Java/C#/Ruby/Python, etc. etc. To each their own, but if you’re a Cocoa developer and care at all about the web, you’d be crazy not to give Cappuccino a serious look.