Wednesday, December 26, 2012

Web Developer Admits: Objective-C > HTML5

Polyvore released its second iOS app recently. Pure native iOS. Yes, the second. Most people don't remember the first version. We launched a PhoneGap based app earlier in the year but removed it from the app store less than a week later. So why the complete change between v1 and v2?

Before I continue, a disclaimer: I love HTML5. I created the Yahoo! Pipes editor back in early 2007 which surprised many when they realized it wasn't flash but HTML+canvas. I love CSS3 hardware accelerated animation (check out the accordion in the Polyvore mobile HTML web site). Local storage is so useful. HTML5 features just make the user experience faster, better.

So why did we want to create an app when we already had a mobile friendly HTML version for webkit-based browsers (iOS and Android)? Engagement. We really wanted to offer up a more compelling user experience, complete with all the things people expect from apps like push notifications. From a business perspective having an installed presence on the device that could keep bringing users back for new content, and potentially shopping through the app, would be ideal.

An HTML5 based approach

Polyvore's front-end code is all HTML, JS and CSS and, given we are a startup with the usual constraints on engineering, we wanted as much code to be the same as we could across our clients. Using a single client codebase rather than using two should make it both quicker to develop the app as well as add any missing features. Its much faster to iterate and leverages our current developer knowledge base. You can also get your app onto other platforms too (iOS and Android)! Sound familiar? This is one of the lures and promises of HTML5 based apps for web companies. These are all good reasons.

So we opted for wrapping and modifying our JS/CSS with PhoneGap (now Cordova). And off we went. We tried mobile jQuery, Sencha and a few other JS frameworks while we were at it. We spent a lot of time trying to make our PhoneGap app feel native using CSS 3D transitions and various other well known tricks. And indeed, working with Webkit as your operating system gives you a great head start - and from a pure familiarity and comfort perspective, it’s just great. Few cross browser woes either (Android webkit, sigh).

But then you start running into stuff thats really hard to control. For example, Polyvore is a graphics heavy site and putting lots of images into a -webkit-overflow-scrolling: touch; accelerated scrolling experience will cause webkit to crash. Sometimes. Occasionally. Memory related? Probably. De-referencing images as they scroll off helps - but you don't get the scroll events delivered when you really need them when you're running in the smoother scroll. These types of issues just kept cropping up. And we kept building more and more special stuff to make it more and more app like. More plugins for PhoneGap, more Objective-C stubs, more special cases. What you end up doing is attempting to rebuild UIKit on the iPhone and view animations for Android (or using a framework that’s doing the same).

It felt like hammering nails into in a wonky floorboard. We fixed one problem and another would pop up. We probably spent over 80% of our time fixing weird side-effect glitches and making our code work within PhoneGap correctly. But eventually we felt it was much better than our HTML mobile version of our site with transitions and notifications and so we launched it.

Lessons learned and relearned

We shouldn't have. Ultimately our first version didn't feel like an app. It was sluggish in places and unpredictable in others. It didn’t have a set editor. People have high expectations when using an app - it has to be fast, the UI response has to be immediate, it needed to have the most used parts of the desktop experience. If it looks like an app, it needs to behave like one - a differentiated, better experience from the web site. Otherwise, why bother? We took it out of the app store a week later.

Some of these reasons may sound very familiar and the Facebook blog post came out mid-way through our development of the second app. We couldn’t have agreed more when we read it.

Unfortunately we’d needed to re-learn an important lesson. It’s all about great products. Not average “ok” stuff, but truly great. It’s something we focus on here at Polyvore and this time we’d missed the mark. We’d spent so much time and effort re-creating UIKit-like functionality in JS/CSS that worked “just like a native app”, we’d lost sight of our goal. Creating something great.

Going native

The best way of creating that awesome app is not to insulate yourself from the power of the operating system you are running on but to embrace it. So we created the new iOS application that’s in the app store today from scratch. We deliberately chose not to leverage another middleware solution like Appcelerator so that we wouldn't be at the mercy of another code-translation layer between UIKit and our code. We wanted performance and predictability. We wanted control. We wanted to build the best app we could.

An obvious caveat. Building an app this way is clearly going to take you longer, possibly a lot longer. You’re re-writing your entire client side interface in a language and environment you are unfamiliar with, and if, like us, your web-oriented engineering team has no iOS experience to build upon, the learning curve is going to be pretty steep.

Reassuringly there were a lot of abstractions and code we could leverage from our JS. We moved our data model over almost directly into Objective-C and re-used our Ajax APIs for fetching and updating data. And while the entire DOM-based UI and JS eventing system had to be thrown out, KVO and NSNotifications coupled with UIKits built-in widgets translated very well.

Even after a few weeks of learning Objective-C and fighting Xcode we knew it was the right choice to deliver the app we wish we'd created the first time. Things that took forever getting working well in HTML5 just work. View transitions, UI Thread prioritization, background threads, view re-use and memory management are all built in. Not added on, but core to the framework.

Quick, fast, snappy. Objective-C is certainly no panacea - it has its own issues and weirdness. It wasn’t a quick and simple “port” and without being able to leverage any other Objective-C knowledge in our organization we did a lot of things wrong before getting them right.

Do you really need an app?

Is HTML5 an abstraction layer too far above where you really should be working, giving you limited interfaces and control of the things you should care about like memory handling, threads, and (ultimately) performance? For simple apps it's tempting to say don't worry about it, it’s the quick thing to do and mobile CSS/JS frameworks will get it done for you. But if your app is simple why is it an app at all? Why bother with something in the middle when Safari is installed on the phone already and your app will always be a subset of your mobile traffic? 

So before you start coding your app ask yourself if you really need one. An HTML5 version of your site in the web browser can behave however you want it to without confounding users’ expectations. If you want to create the best user experience possible for the iPhone don’t try to fake the iOS look and feel, you’ll spend too much time on the things you get for free from a native iOS app and not enough delivering the meat of your experience. So bite the bullet, learn Objective-C, and produce that awesome app that will bring joy to your users.