Basecamp 3 for iOS: Hybrid Architecture
m.signalvnoise.com
m.signalvnoise.com
I'm a native iOS developer who is horrified by 95% of the "hybrid" or cross-platform approaches to mobile development out there today. They all seem to primarily be driven by a desire to use Javascript, or some manager naively thinking they can cut their mobile dev budget in half, rather than any concern for what's best for the user. I thought React Native might finally be a sensible approach, but there's a long list of things I really dislike about it.
However, Basecamp's mix of native and webview here is thoughtful and appropriate. Rendering those web-based views with 100% native views would be a huge pain for very little gain, and this approach allows them to retain much of the advantages of an overall native architecture.
Now I have to learn Dart, trust that Google doesn't kill Flutter, trust that they'll give it their full support even though they're also supposed to be safeguarding and advancing native Android dev, etc.
Plus, I still have to deal with all the issues that any hybrid or psuedo-native solution adds. Things like feature lag, crappy and non-native UI / UX, more pain during debugging / optimizing, extra layer of bugs to deal with, lower community and support, etc, etc.
Just learn Swift! It's not that hard! :)
They take a qt like approach, I.e they attempt to simulate these native components.
They don't look as bad as a rendered webview, but they look distinctively different from the native implementation.
For example on Android, the ripple implementation is very different on Flutter.
It might even be that Flutter more closely adheres to the design spec, but since what I am used to is the actual Android implementation, the Flutter one feels wrong.
On top of some missing features like accessibility.
Perfs are also not entirely where they are promised, but that's a separate issue.
My impression is that it's "native" only in the loosest sense of the word. On iOS, it creates a single view controller and then draws everything in there, I guess technically with UIView objects? But there is no use of native controls, so you're at the mercy of whatever crappy controls someone has created. Quality is seriously lacking for most of those. Essentially zero adherence to the greater platform standards or settings. Feels exactly like Java applets or Flash sites from the 90s. Blank canvas, roll your own everything. I guess the drawing of whatever you want is fast, but that doesn't make it "native".
A glance at the dumpster fire that is the "navigation controller" situation is enough to turn me away. There's still not even a standard way to handle multiple views and the transitions between them??
Also, I really dislike Javascript. Why would you prefer to write code in JS instead of Swift? The entire npm / dependency / build situation also felt incredibly brittle. Felt like if I came back to this app in 6 months and touched anything, there was basically 0% chance it'd still work without a ton of fiddling with dependencies, etc.
It just seems terrible.
I basically agree with most of what's written here: https://arielelkin.github.io/articles/why-im-not-a-react-nat...
(this also ignores all the baggage that any non-native platform faces, no matter how good. things like: feature lag, crappy and non-native UI / UX, more pain during debugging / optimizing, extra layer of bugs to deal with, lower community and support, etc, etc.)
Basically React Native makes a lot of sense if you have a React web team.
In this scenario it works well if you want to spin up an app from scratch or for growth related stuff within a brownfield application.
It makes no sense for a native only shop.
“But there is no use of native controls, so you're at the mercy of whatever crappy controls someone has created. Quality is seriously lacking for most of those. Essentially zero adherence to the greater platform standards or settings. Feels exactly like Java applets or Flash sites from the 90s. Blank canvas, roll your own everything. I guess the drawing of whatever you want is fast, but that doesn't make it "native".”
This isn’t entirely true. You can wrap any uiview and embed it in the React Native view hierarchy. So you have a lot more flexibility than say Cordova (I.e where your ui is a big web view)
Even if you do full native, you run into the same problems. I,e you are going to either use something from cocoapods or roll your own. I’ve seen plenty of half baked third party native libraries.
“Also, I really dislike Javascript. Why would you prefer to write code in JS instead of Swift? The entire npm / dependency / build situation also felt incredibly brittle. Felt like if I came back to this app in 6 months and touched anything, there was basically 0% chance it'd still work without a ton of fiddling with dependencies, etc”
To avoid having to deal with writing an Android app from scratch ;)
I’m a native iOS developer, I mainly got into React Native last year because of all the issues around swift leading up to 2016 wwdc. This years it’s much better and I’ll probanly spend some more time learning it now that it seems stable. However I think it’s unfair to pretend that the last few years of swift have been a smooth ride.
Modern JavaScript is a lot better than it was 4 years ago. However I totally understand why you would not be into it.
This is true, but: a) you have a base set of excellent native controls provided by Apple, and b) you have a much more mature community providing third party controls.
It is true that not everything is wrapped, but if you run across something you need, it's not that bad to create the wrapping yourself; here's more details: https://facebook.github.io/react-native/docs/native-componen...
Edit: what a beautiful example of what I'm talking about: https://github.com/facebook/react-native/issues/371
For example: if you have a list of 1,000 things, you might put them in a scroll view first; but that will lead to very bad loading and scrolling performance (it will with straight native code as well). Instead, you should use FlatList (https://facebook.github.io/react-native/docs/flatlist.html) which is built to be performant on long lists (by reusing components, etc).
There are also a few additional considerations that you don't have when writing pure native code. One example is that if you send a lot of data (like a huge image) over the JavaScript bridge, then that can really slow down app performance. There are ways to get around that however, but it can be easy to accidentally do things like that which hurt performance (and those types of slowdowns might be confusing and difficult to track down).
So yeah, it's not perfect - but it's the best cross platform development tool I've used, and most potential issues have workarounds (once you learn what's causing the issue).
Generally won't be 100% accurate to the native versions, but at least it's better than when people were writing cross platform applications in Java with the menubar at the top of the window instead of in the menubar.
Most apps have only few users. Most apps don't have a million dollar budget. Most users don't care or notice whether an app is native or not. They use it to get a job done and don't care if that button is slightly less responsive than another.
Million dollar budget is a strawman. I've built dozens of complex apps for five figure budgets. Very few ran into six figures, and they'd have been a train wreck on hybrid.
Most things don't need to be an app at all. Those that do need an app should at least consider making a reasonable investment.
Besides, it's not like hybrid is some magical unicorn technology that enables creating a great app at a tiny fraction of the budget of a native one. You save like 30-50% in the best case, and get what you pay for.
It actually is.. You cite saving "50%" likes it's no big deal. Clearly you're in charge of coding and not in charge of the business.
> Most things don't need to be an app at all
Well then you'll be writing this logic in JS for a web-app anyways.
I'm curious, what part of your native app couldn't be done in a hybrid model?
But, and this is a big BUT and the reason why hybrid is a good solution: Users demand apps. Your average user rather downloads an app for the local bus service or a museum than going to a mobile website, because experience taught them that mobile websites are shitty and some apps work offline, at least. Yes, both of us rather use a good mobile website, but average Joe doesn't.
The app experience might not be better, it might even be worse, but users are looking in the Stores for apps like that. The reality of the App Store is that there are a handful of "good" apps everybody uses, and then there are the 95% that are garbage anyways, but are still preferred over mobile websites.
I'm not saying that you can build the perfect app with hybrid, but solutions that are good enough for most people, because they want to catch the next bus and give zero fucks about a native experience. And then, saving 30-50% or maintaining an app for Android AND iOS as a solo developer suddenly becomes quite a strong point in favor of hybrid.
I think you have it backwards. I think you're still hung up on the developer experience, not the user experience. My observation is that users clearly prefer native apps to hybrid apps. And yes, you can throw together a hybrid app a bit faster, but you're just going to lose out to someone who did a better job (probably with native). So you might have saved a few bucks, but it's all going to be wasted.
Just my observation, YMMV, etc, etc.
The problem is that you now have two separate apps. Not only does at least some of the code have to written twice, but every other activity from hiring developers, designing the app to releasing new versions have to be done twice. In co-ordination. Over and over again.
Like a lot of technologies, hybrid is really solving people problems. If your core business relies on one product or service that you sell direct to consumers, then it's probably worth accepting the extra complexity and doing two native apps. There are plenty of scenarios where it probably isn't worth it.
Hybrid actually comes with hidden costs, and can actually be harder for debugging, as well as toolchain maintenance and build engineering. The pay-off, though is having a single process. Frequently, cost savings are one benefit from that, but not the only one.
The summary here would be: we have a native app that provides the most used screens, while the smaller text-heavy pages are rendered as a webview.
The webview hide elements that would normally display on desktop, that don't make sense for mobile, via javascript.
Turbolinks is used to route links.
Overall, I think Basecamp makes very smart hires, with people who care about technology and have a good head on their shoulders - making these types of apps and write-ups possible.
Your average mobile dev(sweat)-shop would never be able to pull this off because this involves good decision making and a stable team that communicates well and is up to date on the latest tech.
I definitely think that for a cross platform app, going all out with something like Cordova or React Native isn't particularly smart.
Sooner or later, you are going to reach a point where you need to use a feature of the underlying OS which your abstraction layer doesn't support well (or at all) and will end up having to make a horrible compromise.
Also, apps build with these frameworks usually don't look or feel native, I can generally tell that I'm using something built with Javascript (not always, sometimes the developers nail it, but a lot of the time).
However I feel that developing completely separate native versions of the same app with zero overlap in code isn't smart either.
It's definitely good to find a middle ground.
I personally like Xamarin. Xamarin.Android and Xamarin.iOS get you as close to native as you can get, while still allowing you to share a fair amount of code between the platforms.
I'm using this approach on a project at the moment and it's working well.
I would love to try Basecamps approach here on a project, it seems very smart.
Sooner or later, you are going to reach a point where you need to use a feature of the underlying OS which your abstraction layer doesn't support well (or at all) and will end up having to make a horrible compromise”
I can’t really speak for Cordova but one of the strengths of React Native is that you can drop to native code relatively easily. I’ve done this in the past for projects and it’s not been a problem.
Can you give a specific example of such a compromise?
“I personally like Xamarin. Xamarin.Android and Xamarin.iOS get you as close to native as you can get, while still allowing you to share a fair amount of code between the platforms”
I’d say the biggest problem with xamarin, aside from debugging, is that all your developers need to learn c# right?
At least with the other approaches (article, Cordova, react native) mentioned they can use languages used by the target platforms (web, mobile).
I spent 5 months rewriting my game Falcross from Obj-C to React Native, and it functions exactly the same (even better in some places because of RN's wonderful Animated API). Try the game and tell me if you "feel the JS": https://www.falcross.com/
As a solo developer, RN allows me to share 95% of code between platforms and still customize that ever so important 5% with native modules. And I'm iterating 2-3x faster than I was with Obj-C.
Definitely want to try it on a project at some point.
I don't see why. They're different platforms; you're going to want people who are experts on the platform working on it, not someone who is only doing the other platform because the boss said they need it.
I would take native teams for both platforms over one team doing a hybrid thing any day.
That being said, actually shipping the same code on both platforms has its own costs and considerations.
Is there any real movement on iPhone or Android moving to replace native apps with offline web apps? Any competitor on the horizon?
Apple and Google are being very Microsoftesque in dragging their feet towards the inevitable.
iPhone was initially supposed to be web-apps, then reality set in.
You're under the assumption that 'big bad men are keeping us down', whereas in reality, if you don't want your phone to run out of battery, handling website animations and transitions, the best you can hope for is hybrid, as Basecamp has done.
It's decade later. I'm using Safari for hours at a time in web apps with video and JavaScript. Performance is excellent. Battery life is sufficient.
Now let me run these same web apps offline with embedded web servers or cached data!
I find it us developers tend to readily dismiss low-end, even "middle of the road" hardware when we ourselves use high-end hardware.
This article on who they developed the Basecamp app is excellent. I'm toying with a similar approach in a little interactive adventure app I'm writing in Pythonista. Except of course that Pythonista isn't really native at all, but still I'm using a webview to display location descriptions and various choices as links, but native controls for things like inventory management and displaying various stats.
One could argue that besides its original flaws, the web platform has been hobbled and maybe downright sabotaged by the platform owners (Microsoft, Apple, to an extent even Google). Javascript could have been cleaned up 10 years ago, same for many other web concepts still in use.
Even in a shopping app (where Native isn't so disadvantaged), a Browser View lets you do a quick google search on the product or company. Once browsers become faster, I'm hoping native will get relegated to games. If OS vendors are listening, a way to install web apps beyond (a) "Click the three dots and Add to Homescreen" or (b) the PWA thing.
Maybe just let web apps into the app store. It's not like the Appstore has a high bar on quality these days, anyway.
Whoa, no. One of the points of having native is to /have/ standard functionality. Native copy/paste, native sharing, etc. All those things have to be implemented and hooked up to by the browser or JS library, otherwise.
Not to mention native controls, the native UI behaviour, etc which is otherwise mimicked.
I can't speak for Android, but under iOS you get all of that for free if you're using UITextViews that have selection enabled (as opposed to UILabels). It'll also give you Wikipedia/Dictionary/Thesaurus lookup popover, data detectors (auto-linking dates, etc) and more.
There is functionality somewhat unique to browsers, sure, but it's a smaller set than you may think and in many cases, dropping in a resource intensive WebView for a couple of little perks is what's overkill.
Personally, my feelings are that if your app is mostly a webview, just stick with a web page. There's little benefit adding a wrapper, and it strips control away from me as a user (no blockers, etc).
I agree, but it is clear that those who grew up with phones do not. Apps dominate the marketplace and use space for millenials.
For more complex applications that also need to open from push notifications or respond to events and have several ways to end up in some sort of screen (like going to a chat view controller discussing a certain document from a push notification) it's just not doable to do all these tight couplings between screens.
I create a router that has an enum per screen which can accept another parameter if there can be a certain mode or certain data is required. The router figures everything out and the enums force you to provide the right associated data. Just call something like this from any place in the code you want to segue and it's done:
Router.segue(to: .profile(of: .followedUser(selectedUser)))> Why did we move away from RubyMotion? Quite honestly: we needed to buckle down and learn the platform as a team.
Doesn't sound like there was any real abandonment as much as "We should use the tools the platform supplies".
Then I discovered React Native, not only it is cross-platform (Android, Windows) but it is also a joy to work with (the last time i felt this was with Rails). My apps are now completely on 1 single code base, very maintainable, as native as I want, and hardly crash. Besides, the binaries are so small (4MB iOS & 8MB Android).
(PS: My android app https://play.google.com/store/apps/details?id=plus.land)