When we launched the iPhone version of Basecamp in February of last year, it was after many rounds of experimentation on the architectural direction. The default route suggested by most when we got started back in early/mid-2012 was simple enough: Everything Be Native!
This was a sensible recommendation, given the experiences people had in years prior with anything else. Facebook famously folded their HTML5 implementation in favor of going all native to get the speed they craved with the launch of their new app in August of 2012.
Thus their decision was likely driven by what the state of the art in HTML and on mobile looked like circa 2010-2011. In early 2010, people were rocking either the iPhone 3GS or 3G. By modern 2014 standards, these phones are desperately slow. Hence, any architectural decisions based in the speed of those phones are horribly outdated.
Decisions based on computing speeds quickly decay
With that in mind — that performance data driving previous tech choices was outdated — we set about to do a series of bake-offs. We implemented the main progress screen in the iPhone app in first a fully native version, then again in an HTML-backed version.
After a fiddling a bit, the conclusion was clear: There was no discernible difference! Well, except for the fact that it was far quicker to develop the HTML version than the native version.
Naturally, this isn’t true for all domains. If you’re programming a 3D game, you want every ounce of raw-metal speed to improve the experience. But if you’re building an information system like Basecamp, you’re looking at least as much at programmer speed as you are computing speed. And frequently, it’s well worth trading the latter for the former. So we did.
1st Gen: Native shell around server-generated webviews
Basecamp for iPhone is a thin wrapper of native navigation around essentially a webview core. This webview is powered by the regular Basecamp Rails application, with only a few stylistic differences from our normal mobile web view. But the difference is still profound.
Having a native shell makes the feel of the mobile web site very different indeed. It let’s people find the app via the App Store, and their login persists forever (rather than the frequent cookie losses you seem to get on mobile Safari). Users have loved it. The app has a 4/5-star rating.
And we loved building it! The iPhone app was mainly built by a single programmer and a single designer. Since we already had a wonderful mobile web site that could be repurposed, the effort was easily manageable.
Something that could not have been said if we were trying to build all of the Basecamp functionality natively, from scratch. A team of 10 probably wouldn’t have been enough, even if they had worked for 18 months. We were simply orders of magnitude more productive by using the web and HTML as our main runtime for the native app.
2nd Gen: Native shell + native navigation
That was the first generation mobile app for Basecamp. The release of Basecamp for Android just a few months ago was our second generation. And the level-up is significant.
What we learned from the first-generation iPhone app was the power of native navigation, but it wasn’t until the Android app that we went all in on that. In the Android app, we’re using native contextual menus — automatically constructed from data in the HTML views — to make it feel even better. It’s to the point where it’s hard to tell where native ends and HTML begins.
Again, the development of the Android app happened with a tiny team. 1-2 developers and about half of a designer. We were again able to reuse all those mobile webviews that already powered the regular mobile web and iPhone experience. A huge productivity jump. And again, users love it. The app has a 4.5/5-rating from more than 1,000 users.
While many companies are grumbling over just how slow the development of native iPhone apps can be, even more seem to do so with Android. Maybe because they’re just used to the iOS workflow, maybe because of all the different Android variations, but for us it didn’t even matter either way. We were able to put out a fantastic version of Basecamp for Android by reusing 95% of the work we had already done, and we didn’t need to balloon our team or company to get there.
Spending the productivity spoils on native where it matters
We’re now working on our third-generation mobile app for an as-of-yet undisclosed platform (although I’m sure it won’t take much extrapolation for you to guess!), and we’re going a step even further. From 1G to 2G, we doubled down on native navigation, while reaffirming our webview-core architecture. In the jump to our 3G app, we’re taking our productivity spoils and spending them where they can make a difference.
The start of that is by picking a part of Basecamp that really can benefit from high-fidelity native UI and making it so. Where we before had 100% of the meat of the app in HTML, we’re now going with 90% HTML, 10% native, and really getting the best bang for our buck by picking the most worthy 10% to go native with. The integration feels really nice and seamless, and you may well not even notice at first which parts are HTML and which part is native. Which is exactly the point.
The technology underpinnings of our hybrid approach
The technology behind this is all fairly straight forward. The main hurdle on the native side is dealing with the webview integration and controlling the loading phase, as well as the cross-links between native and HTML. We’ll try to share more about these techniques soon, but it’s a lot simpler than you’d think.
On the HTML side, we’re running a proud and polished monolith of a Rails application. The same controllers and models that are delivering the desktop web experience are responsible for the mobile views, which in turn are integrated into the iPhone and Android clients. This is made trivially easy by the Rails 4.1 feature of variants.
This also makes the rollout of new features endlessly easier. Imagine if we had to change a Rails desktop app, a Rails API app, a client-side MVC app, a mobile web wrapper app, an Android app, and an iPhone app whenever we wanted to improve or introduce new functionality! That’s simply not a workload that’s realistic for a team of 10 programmers and 7 designers.
Besides the much-reduced workload, it also means we’re able to fix problems much faster. When the majority of the functionality lives in the HTML served from the server, we don’t have to wait for Apple’s multi-day approval cycle to fix things. Maintaining the native apps become more like maintaining the web through continuous deployment.
Hybrid disruption of the all-native paradigm
So in classic disruption theory, the hybrid model is eating its way up through the complexity chain. I’d argue that the majority of information-based apps today can be successfully implemented through this approach with varying levels of the native/HTML split.
It also makes it easier for small teams to break out of the iOS-only bubble when it comes to mobile. When you don’t actually have to recreate the entire app, and you’re not just doubling the maintenance burden, it becomes a lot easier to go multi-platform from the beginning. Or at least much faster to add new platforms as you go along.
I know there’ll be plenty of skeptics of the hybrid approach. Either because the context they work in requires lots of native fiddling (or they at least think it does!). Or perhaps because they spent so much time perfecting their UITableView chops that it seems a shame not to flex those muscles at every chance. Or perhaps because it served the big-company moot well to have mobile development be so much harder and more time-consuming than web-development.
But whatever the reason, I think every software shop today should take another look at the hybrid approach. You might well find the time is right for a switch. If so, congratulations, and enjoy!