Talks

Use Turbo Native to make hybrid apps that don't suck

Use Turbo Native to make hybrid apps that don't suck

by Ayush Newatia

In the video titled "Use Turbo Native to make hybrid apps that don't suck," Ayush Newatia discusses the evolution and potential of hybrid applications, challenging prevalent misconceptions in the tech industry. He starts by defining hybrid apps as those that merge web technologies (HTML, CSS, JavaScript) with native APIs across iOS and Android, emphasizing that these apps have been historically criticized for being slow or inferior, largely due to earlier experiences with platforms like Cordova and React Native.

Newatia recounts the history of these biases, illustrating how a statement by Mark Zuckerberg in 2012 contributed to the negative perception of hybrid apps. He highlights that many disapprovals stem from outdated technology and ineffective strategies used in hybrid app development. Observable advancements in mobile device performance illustrate that hybrid apps can now deliver satisfactory user experiences.

Key points discussed during the presentation include:
- The Concept of Hybrid Apps: Defined as applications combining web and native technologies.
- Historical Biases: Critiques of hybrid apps were often based on past failures and have become ingrained beliefs without reassessment.
- Performance Improvements: Modern mobile devices show significant performance enhancements compared to older models, indicating that hybrid apps could thrive now with appropriate frameworks.

- When to Use Hybrid Approaches: Newatia suggests a hybrid approach makes sense for server-rendered web apps rather than heavily native-integrated apps like Uber.
- Advantages of Hybrid Apps: Notable benefits include reusability of web app views and the ability to push updates remotely without going through app review processes.
- Separating Code Bases: Effective hybrid app design should implement separate code bases rather than a shared one to respect platform-specific standards.
- Introduction to Turbo Native: A part of the Hotwire Suite, Turbo Native offers a way to use native libraries for iOS and Android while maintaining a hybrid model, thus allowing for seamless integration between web content and native functionality, emphasizing performance and user experience.

Newatia concludes by addressing the critical question regarding user experience in hybrid apps compared to their fully native counterparts. While not identical, they can be sufficiently effective for many applications. He points out that consumer satisfaction ultimately pertains to the app's functionality, irrespective of its development framework. Examples illustrate this point, with successful hybrid apps like Basecamp and BBC Sport achieving high user ratings despite their hybrid nature.

Overall, Newatia's talk at Friendly.rb 2023 encourages a reevaluation of hybrid applications, suggesting that new tools and improved performance may lead to successful implementations that meet user expectations.

00:00:10.000 Give it a warm welcome for.
00:00:17.680 Hey, well thank you very much! Um, yeah, I'm just going to talk to you about hybrid apps and a better way to go about them. So let's just dive in.
00:00:22.920 What are we going to talk about today? We're going to start with what's a hybrid app, just to start right at the basics so we're on the same page.
00:00:25.920 They seem to get quite a bad rap in the tech industry; people don't seem to like them. We'll talk about why this has happened and why it may not be quite accurate.
00:00:29.840 What is Turbo Native? So I've been talking about it, like I mentioned in the title slide, as a better way to go about hybrid apps. So what's it, why does it help, and what's the correct approach to get them right? It's quite easy to get this wrong. Before we start, allow me to be a bit of a narcissist. A bit about me—that's my avatar on all my socials that you'll see. I'm not quite that rock and roll in real life, but I'm allowed to exaggerate because it's the internet.
00:00:53.000 I'm from London and I'm a freelancer; I kind of specialize in web development mainly with Ruby on Rails. That's my business website. I co-host a podcast because, well, who doesn't have a podcast these days? It's called JCE Spec, and it's about web specifications and standards that kind of drive the modern internet, which I promise is a lot more interesting than it sounds. Yeah, you'll find that on all good podcast platforms, probably some of the bad ones as well.
00:01:16.280 I'm on the core team of Bridgetown. If you're unfamiliar with it, it started life as a fork of Jekyll, and it's kind of grown into a lot more than that. We don't even call it a static site generator; we call it a progressive site generator because it can do so much more than just generate a static site. So if you've ever been frustrated with Jekyll and how it's kind of frozen in time, I highly recommend that.
00:01:39.640 I also run an app called Scaton; it's kind of on pause these days because I've got a lot of other things going on. But yeah, that is one of the many things that I kind of have going on. I've also written a book, which I'm going to shamelessly plug on an entire slide. Basically, all the code samples and most of the content of today's talk has been extracted from this book. If you're looking to level up with Rails and Hotwire, it's my completely 100% unbiased opinion that this is the best resource out there. Of course, I would say that.
00:02:02.640 But anyway, enough about me. Let's dive in. So, what's a hybrid app? A hybrid app is one that combines web technologies like HTML, CSS, and JavaScript with native APIs on iOS and Android. The degree to which these two worlds collide depends on what tools you use. These are a couple of popular mainstream tools: Cordova, which used to be called PhoneGap, and React Native. These are the tools most people would kind of reach for when you say hybrid apps.
00:02:39.680 We'll come back to these a bit later on, but for now, let's take a rather sizable detour into the Chinese hills where there was once a monastery where a distinguished teacher lived with his disciples. Every evening, the monks would gather in the Great Hall to listen to their teacher's teachings and to meditate. But there was a problem: there was a stray cat that had adopted the monastery as its home, and every evening, it would follow the monks into the Great Hall, where it would meow, scratch, and generally be annoying throughout their silent meditation.
00:03:03.479 After a while, the teacher got pretty fed up with this and ordered the monks to put a collar on the cat and tether it to the far side of the monastery. Every evening now worked well for a while. The teacher, the monks, and the cat all went about their nightly routine, and everything was fine, until one day, the learned teacher died. But the monks continued to tie up the cat every evening.
00:03:39.160 More years passed; eventually, the cat died. So what the monks did was they went down to the nearest village, bought a replacement cat, and tied that up every evening instead. Two centuries later, religious scholars write learned essays on the importance of tying up a cat prior to evening meditation. This is an ancient Buddhist tale known as the tale of the tethered cat, and it serves to explain principles that have outlived the conditions that created them.
00:04:04.360 Now, tech loves a tethered cat. This might sound familiar to a lot of you. I think the notion that hybrid apps are bad is another tethered cat; it's just something that got established, and people have stopped questioning why this may be the case.
00:04:37.240 Over the years, I've heard so many falsehoods about hybrid apps—things like hybrid apps are slow, hybrid apps don't look native, and even hybrid apps are insecure. I don't know how that one came about, but it's stuff I've heard, and I just got thinking: how did these falsehoods get so ingrained in our industry? I started thinking back, and one of the starting points was Mark Zuckerberg in 2012.
00:05:05.760 He said the biggest mistake we've made as a company is betting on HTML5 over native. Now, Facebook rewrote the hybrid app around that time and shouted about it a lot. Well, if Mark Zuckerberg says it, it must be true, right? I think it just got ingrained in the industry; people said, "Okay, if Facebook can't do it, then hybrid apps are just a failed concept that don't work. We're going to go fully native, and that’s the end of that." The other thing was that the two mainstream tools I mentioned earlier, Cordova and React Native, both operate on the philosophy that you have one shared code base between the two platforms.
00:05:43.720 Now, that doesn't work. That has never worked, and it will never work. Does anyone remember Java apps? Yeah, they were rubbish. How many of you have an Electron app that you absolutely love? Yeah, this concept of shared code base just doesn't really work. Same thing with Flash; that’s another great example.
00:06:29.200 On top of that, Cordova also builds out your entire app's UI in HTML, CSS, and JavaScript, so the UI looks quite almost the same on iOS and Android, which is not very good because platform standards differ between the two. If you want to give your users a good native-esque user experience, you want to at least follow some platform standards in your app’s UI.
00:06:46.720 React Native... Well, I don't want this to turn into a rant, but I think Nigeria made a good case against React yesterday, and React Native isn't much better to be honest. I'm going to show you what the former lead developer of React Native used to have on his Twitter bio, which says a lot about that tool.
00:07:31.920 I think between Mark Zuckerberg's 11-year-old take on the tech and the two mainstream tools being quite inefficient, we've established a textbook tethered cat here. But before we look at why these presumptions may not be valid in 2023, let’s take another detour.
00:07:59.679 This time, we're going into the English countryside, which is a little closer. There once was a man who had a long way to walk to work, and every day he would have to go well out of his way because there was a large hedge that blocked the most direct route. So every day, he would walk a mile longer in the morning and then back home in the evening, thinking that if the hedge weren’t there, he could save himself an hour of walking every day.
00:08:40.720 Eventually, he had enough and decided to make a hole in this hedge so he could walk the most direct route. So he did that, and that was the day that the bull that lived on the other side of the hedge killed him. How a Texas longhorn bull found its way in the English countryside is up to your imagination—it’s fiction, let’s just roll with it.
00:09:15.120 This tale, established by a British writer and philosopher called G.K. Chesterton, is known as Chesterton's fence. He used it to explain that we shouldn't remove a rule before fully understanding why it was first put into place and all the effects that its presence has.
00:09:55.560 So let's look at some of the circumstances around this myth that hybrid apps are bad. If you look again at Mark Zuckerberg's quote from 2012, that’s 11 years ago, the world of mobile JavaScript performance is like a different league compared to where it was back then.
00:10:28.679 I found an old iPhone 6 lying in my drawer, ran a speedometer test on it, and got a score of 24.8. Then I ran the same speedometer test on my current phone, which is an iPhone 13 mini, and got a score of 349 in what? Seven years? That's a ridiculous performance jump. I mean, I don't even have words to describe it.
00:10:55.840 Okay, granted, we're looking at a $600 top-of-the-line phone with that score of 349. When I saw the score, I texted a few friends and family who had Android phones and asked them to run this test and tell me what score they got. Again, these are not scientific numbers but anecdotal, and I still got scores between 60 to 100 on all current Android phones.
00:11:35.920 So we're looking at about a 3X improvement on a phone from 2014. I think that proves that the performance level of mobile devices now is completely different from what it was 11 years ago, and maybe it’s time to revisit the idea of hybrid apps. Perhaps the tech is there now that we can build them and deliver a really good user experience.
00:12:12.159 Let's reconsider it and talk about when we should go hybrid because hybrid isn't a silver bullet. It’s not something you would choose every single time. You would go with a hybrid approach when the beating heart of your app is a server-rendered web app that speaks HTML, CSS, and JavaScript.
00:12:39.720 Ideally, you'd use one of these full-stack frameworks or something similar to drive that, but it’s not necessary as long as the primary focus of your web app is HTML and CSS. That’s when hybrid makes the most sense. If you're building something like an Uber, which requires deep native integration because you need maps, location, and that kind of stuff, and you don't really need a web app, then hybrid isn't really the right approach.
00:13:05.599 That’s when you’d want to invest in a fully native app. So what are the advantages of this hybrid approach? Well, I think the biggest one is that we can reuse HTML, CSS, and JavaScript from the web app. You can reuse all your views from the web app in the native app.
00:13:47.560 This is a huge competitive advantage because if you're a small team, building every view three times is just a massive overhead, and probably impossible for solo developers. It's simply not feasible to deliver an app on three platforms if you have to rebuild every single view. Again, that’s a huge competitive advantage if you can just reuse those views in a good way.
00:14:23.760 Because it’s hybrid, you still have one foot firmly in native land. Native APIs like push notifications, contacts, maps, etc., you still have access to all of that. You can still make use of it when you need it, so it gives you the best of both worlds, up to a point.
00:14:45.760 This is a cool advantage: you can push updates remotely by just updating the web app. Obviously, it’s kind of limited in what you can do with this because some stuff just needs native code, but after you reach a level of stability with your native code, you can do quite a lot just by deploying the web app and pushing new features.
00:15:05.920 You don't have to go through this app review process and hope that someone at Apple or Android’s review team isn't having a bad day and rejects your app for no good reason, because that does happen. So, okay, enough preamble. Let's talk about how we can do this well.
00:15:26.480 The first thing is separate code bases. I said earlier that shared code bases don't work. Use Xcode and Android Studio—we build a fully native skeleton of the app, and in that skeleton, we render web content. So this is kind of what it looks like: you would have your navigation bar, your tab bar; the core backbone of the app will be native, so you're not going to get away from writing native code.
00:15:53.640 You’ve got to write at least some, so the actual content of the screen is rendered as web content. It's just HTML, and it's the same thing that your web browser would deliver. In a way, this app becomes a custom web browser, and this is where Turbo Native comes into the equation, and this is where it helps.
00:16:22.599 So what is Turbo Native? Well, it's part of the Hotwire Suite of tools, which is an open-source front-end stack from 37 Signals. It's made up of three parts. The first part is Turbo, which is a successor to Turbo Links; if you’ve worked with Rails for any number of years, you might be familiar with Turbo. Turbo Native is kind of part of that umbrella, and it extends Turbo on the web.
00:16:58.679 The second part is Stimulus, which is a purely front-end library that allows you to attach pieces of JavaScript logic in the form of controllers to your HTML elements. It’s a very lightweight way to add JavaScript logic to your HTML page. The third part is Strada, which released last week and completely impacted the final part of my talk. Wait three years for that library, and they release it one week before I'm giving a talk.
00:17:30.720 I'm kidding—we will talk about it a little bit; I'm not going to cover it because I haven't had a chance to look into it deeply yet. So let's look at Turbo Native: it’s a native library for iOS and Android. It’s written in Swift on iOS and Kotlin on Android. Conceptually they’re almost identical, but from an implementation point of view, they're quite different because it follows platform standards. The way you write code in Swift and the way you write code in Kotlin is different, and the platform APIs and design patterns vary.
00:18:24.960 That kind of goes back to my earlier point where you shouldn’t share a code base; you should respect the platform you’re on. This library does that, because even though it's conceptually the same, the implementation is based on how you would write code for that particular platform. It extends Turbo on the web, specifically Turbo Drive, which is another part of Turbo.
00:19:00.080 If you're not familiar with Turbo, I just want to briefly explain it so we're all on the same page. So Turbo on the web is pretty non-intrusive; it installs itself on your web app, and then when you click a link, instead of just navigating to that link, Turbo intercepts the call and makes a fetch request to the destination.
00:19:48.240 Then it gets the response and swaps out the body element with the response, also using the push state API to update the URL, so your back and forward button in your browser still works. So how does Turbo Native augment this kind of flow? Well, first, when Turbo Native loads a page for the first time in your app, it will install itself as an adapter on its web counterpart.
00:20:23.440 How does it do that? Well, both iOS and Android have native APIs that let you communicate with JavaScript and vice versa. If you have a web view in your app, you can literally use native code to communicate with it both ways. Turbo uses these native APIs to install itself as an adapter, placing itself right in the middle of Turbo's request cycle.
00:20:59.840 So now, when you tap a link in your Turbo Native app, instead of making a fetch request, it calls a native method instead. In this native method, you can either proceed with the default navigation or present a fully native screen instead. I love this approach because it means you're never fully committed to either hybrid or fully native.
00:21:34.640 You can build out certain screens in your app fully natively if you want, leaving the rest to be web views. If you have one screen in your app where the user spends 90% of their time, you might want to build that one out fully natively to ensure the highest level of fidelity possible, giving the user the best experience on that screen.
00:22:05.440 But for all the other screens that are not used that frequently, you can just leave them as web views because you don't need that extra bit for those. I really like this kind of approach because it introduces the concept of progressive enhancement to native apps.
00:22:47.200 Let’s zoom into what default navigation is that Turbo Native gives us. When you tap a link, the first thing it does is create a new native screen. If you're familiar with any native APIs on iOS, that would be a view controller, and on Android, it would be a fragment. Next, it injects the web view into this new native screen and tells Turbo to navigate to the destination, presenting the new screen to the user.
00:23:25.000 This is great because it reuses the same instance of the web view across all screens, so you get all the performance benefits that come with Turbo. From a user's point of view, this is a seamless native transition. Let me show you a video.
00:23:58.800 To me, that looks pretty native. The swipe to go back on iOS and things like that just work because we're using native navigation. All that functionality is provided out of the box for free.
00:25:00.000 Now, some of you may have noticed that this fully native login button is within a hybrid app. Until about a week ago, it was more of a mystery how we did that, but then Strada came out and explained that it basically lets you place fully native elements while being driven by a web app.
00:25:34.639 We’re not going to dig into the intricacies of how Strada actually works; we're going to go one level deeper and talk about the tech on which Strada is built—the web to native bridge. As I mentioned earlier, Turbo uses native APIs to install itself as an adapter on its web counterpart.
00:26:10.640 We can use the same APIs to perform various tasks. On iOS, you can post messages to native code by sending a JSON message that will trigger a Swift method, allowing you to handle any message accordingly.
00:26:46.920 On Android, there’s a similar API, but we need to declare a method as the JavaScript interface and then call that from JavaScript. It accomplishes the same goal: enabling message passing between native code and our web app.
00:27:24.640 This is powerful because now we have two-way communication between native code and our web app. We can have our web app instruct the native app to perform certain actions, such as rendering a fully native button. To accomplish this, we would create an HTML element that acts as a proxy for that native element.
00:28:01.280 This is how I would do it. A simplistic approach would be to attach a stimulus controller to it and then specify some data attributes to dictate the platform's actions. Just like on the previous slide, we specify the kind of component to render.
00:28:43.280 When this controller connects to the DOM, the connect method is called. First, we add an invisible class because we don’t want it seen in the web UI, and then to render it, we create an instance of the bridge element, which isn’t going to be explored in depth now but essentially encapsulates some data attributes.
00:29:18.920 The web bridge then uses the adapter pattern to call the correct API for sending messages to the native app because, as I noted, the code differs between Swift and Kotlin. You simply create a bridge element, post a message to native code, and in that code, you write logic to accommodate that corresponding action.
00:29:53.640 To summarize, the web to native bridge allows to pass messages from JavaScript to native code and vice versa. You can render fully native components that trigger web actions. Essentially, there's no limit to what can be triggered; you can create whatever is needed because it’s just a generic messaging bridge. Strada is a thin layer on top that standardizes the messaging while eliminating many complexity issues.
00:30:44.480 Now, let's wrap up by addressing the burning question: Is the experience as good as a fully native app? No, it simply isn’t. We can get pretty close, but it’s not the same. However, I feel its sufficiency is supported, mainly because after a point, you can get diminishing returns.
00:31:25.440 Your hybrid app can get quite far, but to get that extra bit of fidelity with a native app, you might have to spend an order of magnitude more.
00:32:12.479 Is it worth it? I’m not sure in most cases I’d argue probably not, because most apps are CRUD apps. As much as we may hate to admit it, I think most web apps perform CRUD operations, and the hybrid approach works perfectly in that scenario.
00:32:50.040 I cannot emphasize enough that the consumer doesn't care. The app could be written in Swift, Kotlin, or even assembly for all they care; it doesn’t matter. As long as the consumer can do what they opened the app for easily, without errors or issues, they will be happy.
00:33:25.200 A couple of obvious examples to illustrate this are Basecamp, which are the flag bearers for Turbo Native. You can see they both have 4.6 ratings on the App Store, indicating very happy customers.
00:34:03.600 Another slightly unexpected example is the BBC Sport app. It's a hybrid app, but it doesn’t use Turbo Native as far as I know. It follows the same philosophy: native navigation with web content integrated. If you don’t believe me, go to any BBC Sport URL and append ‘app’ at the end of it.
00:34:44.040 Now look at that 4.7 rating. In contrast, if we compare that with a highly popular fully native app, I think it’s possible to build a fully native app that's substandard. It's also possible to build a delightful hybrid app. Thank you.