Hybrid Mobile App Development : Learning from experience

Building mobile apps is not a side dish anymore, it has become a part of the main course for businesses. Hybrid mobile apps (Javascript + Native) tick more proverbial checkboxes than pure native apps as far as a sales pitch is concerned for non graphics/game apps. The hybrid supporters will tell you to go read how linkedin rocked with a hybrid strategy.

On paper hybrid mobile apps let you

1. Write once deploy on multiple platforms (heard that somewhere before in the 90s).

2. Leverage the existing talent of JavaScript developers (there are more web developers than native developers)

3. Share the JavaScript code with the web based version of the app.

I thought so too when I embarked on my first hybrid app (first mobile app for that matter) for which I was getting paid. After finishing the project, my answer has changed to ‘it depends’.  Here’s why.

When we started the project, our aim was to build it as much as possible in JavaScript. We chose Ember.js as the client side MVC framework and apache Cordova (previously phonegap) as the bridge between the Web view and the Native runtime (which was ios). To write better JavaScript code we added a healthy dash of state of the art JS libraries (require.jsq.js, underscore.js, mocha for testing). To top it, we used  Node.js on the server side and added some serious Html 5 love in the form of WebSql as our database. All the above frameworks and libraries are awesome in their own ways, but it had an unforeseen consequence. For most developers in the team, it was a fairly steep learning curve.  JavaScript is a very powerful language, but it also not statically typed like a Java/Objective C is. Minute spelling mistakes mean rework, however small and they all add up to the throughput. Since our database was also handled from JavaScript, it meant more async programming. Q.js is a great library which helps you write readable and maintainable async code. For people used to imperative programming, it takes some time get adjusted to it’s idioms. Ember.js is also a very powerful MVC framework, but again it has a steeper learning curve compared to a lot of MVC frameworks. All these factors meant that we couldn’t churn stories out as fast as we had estimated initially.  If we hadn’t used all the above libraries and frameworks, our code would have looked like how most JS codebases look; Spaghetti.  The sales pitch for the hybrid app didn’t consider the team’s skill sets/experience with languages, frameworks and how it can be a bigger factor in estimation than Native vs Hybrid is.

After a while we did get productive, but then there was another snake waiting to bite us. The snake of memory leaks. We noticed that app crashed when we used iframes. After some trial and error, we found that it was because, the iframe’s src was not set and Cordova didn’t like it. Setting it to something fixed the crash. One problem fixed. A month later however, we figured that app leaked memory (5-10 MB) for one user interaction. Again after a couple of days found out from Xcode’s memory profiler that the sqlite library was leaking memory. This was apparently because the websql api has a method to open a connection, but none to close it. So every db call was leaking memory. The fix here was to have the db connection object as a singleton. The leak came down from 10 MB to 5 MB. There still was a huge leak and not fixing it meant getting rejected by the app store. Xcode’s memory profiler didn’t show the leak. It turns out the UIWebView/WebKit is unmanaged code and hence doesn’t show up on the profiler. Unlike the inspector on chrome, the one on Safari didn’t let us profile the javascript memory, so it was just guess work. After spending a really long time trying, we figured that upgrading to iOs 6.1 fixed the leak and guess what the iframe src hack wasn’t needed as well. We had won the performance battle, but the casualty was around two months of trial and error dev effort give or take. Since it came at such an advanced stage of the app development, sunk costs fallacy prevented us from a rewrite.

The business did not want an android app as of then, but we gave it a try nevertheless to validate our assumptions. It took us a couple of days to get the basic stuff running. There were  however a lot of niggling bugs around the DOM and JavaScript. A hybrid is most certainly not a write once, run anywhere. It takes a lot of fine tuning for specific platforms. It is certainly nowhere near Java’s platform independence. Sharing code for domain logic is certainly possible across platforms, but then designing the JavaScript code with the right abstractions is a must. If you couple the domain objects/logic with the UI, then porting to other platforms becomes harder. Fortunately, we had this one covered, so we ended up with fewer issues.

The other lesser challenge we faced was getting the app to look like a native app. This meant time spent designing and iterating on not only the style sheets, but also the user interactions and app transitions like a native app. For a pure native app, there is no such effort because the styles and transitions come out of the box. The bigger catch being that customising the app for another platform means more work. So much for platform independence.

At various points in time, we felt that going native was the easier option, but  then we had put our minds to JavaScript and more native meant more rework during porting. So we stuck to our hybrid guns. Now in hindsight, it feels that we spent more time debugging and fixing very very hard issues. All that time and money could have been saved if we went native even for parts of the application which had the hard problems like the memory leaks. We had around 90 percent JS code and 10 percent native code. Maybe a 70:30 ratio could have saved some time and money (again it is an educated guess).

The Moral of the story:

1. Hybrid apps are not exactly platform independent. It takes some time to port them, depending on the UI complexity.

2. Traditional JavaScript developers can never get productive right away and churn out a native style JS app.

3. Code Sharing can be done amongst platforms, only if you design your abstractions right.

4. The tools for profiling and debugging hybrid apps are non existent or not good enough (at least for now on iOS)

If you read the previous link on how cool hybrids were at Linkedin last year, then also read why Linkedin dumped Html5 and went native this year. Looks like the guys at Linkedin had similar issues.

Having said all that, it is a great strategy to start your app as a hybrid (only if you are really targeting multiple platforms). If you have great JavaScript and css guys and if you design your code well, then the chances are that you may tick all the proverbial as well as real checkboxes. The more harder and subtler calls which you will have to take are, ‘when is a problem hard/complex enough (because we are spending too much time on it), so that we can explore native options’. Ultimately it is not about about the JS code to native code ratio, but about getting the app out as fast as possible, because the mobile app ecosystem moves much faster than the traditional server side ecosystem. You better put it out fast, or else somebody else will.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s