Video details

Chain React 2018: Strategies For Using React Native In A Brownfield App by Harry Tormey

React Native

Hot reloading--the ability to push over the air updates to published apps and the promise of having your app “just work” out of the box on Android as well as iOS--make React Native a tempting proposition for frontend developers. But what do you do when you have to integrate React Native into a large existing native code base?
This talk is from the perspective of an experienced native iOS developer who has worked with React Native to ship several cross-platform Greenfield and brownfield apps.
Things I will talk about:
- Overview of the challenges involved in integrating React Native into an existing app. - A real life case study integrating React Native into a native app with millions of users. - Strategies for passing data and events in a brownfield app. - Working with build systems like CocoaPods - How to do CodePush in a brownfield app - How to handle navigation in a brownfield app - Best practices for working with Native engineers - Example brownfield application


My name is Harry Tormy, and today I'm going to be giving a talk entitled to strategies for users in React Native in a Brown Field application. The agenda for my talk is like this. I'm going to start out giving you some background information. I'm going to explain terminology that I'll be using, such as what a green field React Native application is and how it's different from a Brown field React Native application. Then I'm going to move on to section two, which is entitled Should I Do this now? In this section, I talk about why Brownfield React Native development is particularly challenging, and I give you some heuristics that you can use to decide whether Brownfield React Native development is a good fit for you or your organization. I then go on to propose a strategy that I think you should use if you want to try experimenting with Brown field React Native development. Section three is entitled How Do I Do this? So if you do decide that React Native Brownfield React Native is a good fit for you, how do you go about implementing it? In this section, I show you an example brownfield React Native application that I've open sourced that was based on some work that I did for a client. I talked you through the architecture and the process that I used to develop this application so you can take this process and architecture and apply it to your own. Brownfield React Native integrations. So what is a green field React Native app? A green field React Native app is an app created from scratch using React Native. What is a Brown field React Native app? Brown Field React Native app is when you use React Native to power one or more views or user flows within an existing Native application. Should I do this? Should you attempt to integrate React Native into an existing iOS application or Android application? Before I try to answer this question, let's take a step back and ask ourselves, what is the point of React Native? Now imagine that you were trying to explain this not to a software engineer, but to a layperson. There are many ways that you could do this, but I think a fair way would be to say that React Native allows you to do more with less. If you were to sit down with this person and you were to write out from first principles the high level prose of React Native, you might say the following NCAE react Native allows you to have one engineer work on both your web and your mobile product. React Native allows you to make cross platform apps from one TypeScript JavaScript or Flow code base. You can have an iOS and Android app that works roughly the same. React Native also allows you to have a faster development cycle. Unlike Native, you don't have to wait for your application to compile to see the changes that you've made. In theory, React Native allows your front end engineers to be roughly two to three times as productive. So why is Brownfield development harder than Greenfield development? Well, let's think about the things that you would need to know if you were trying to do a Greenfield React native app on your own. You'd want to know JavaScript, how React works, and how to use React native. Now let's think about if you were trying to do a Brown Field integration on your own without any help from anyone else, what would you need to know? Well, you'd need to know JavaScript. You'd need to know how React works. You'd need to know how to use React native. But you'd also need to know a few other things. You'd need to probably know at least one native language. So if you were doing this in an iOS app, that would be probably Swift or Objective C. If you're doing this for Android, that would be Java or Coffin. But it's not just enough to know the language that the application is written in. You also have to know how that native platform APIs work. So, for example, if you were doing this for an iOS application, you'd probably want to have some idea how a view controller works and what it's used for on Android. That would be Activities or Fragments. But you'd also need to know about that platform's ecosystem and tool chain. So, for example, if you want to install a third party library with a React native app, you use Yarn or NPM. For native iOS, you have Cocoa Pods, Carthage, and a few other options that you can use to install third party libraries. When you install a third party library, it has consequences for your native app, both in terms of the binary size and the way it gets compiled. You need to know about all of that. You also need to know how the existing native code base is architected, but it doesn't stop there now. I've been doing software engineering for about ten years. I started out doing desktop apps, and then I moved to native iOS, then to native Android, then back to native iOS. And today I do React native. And as a rule of thumb, I would say it takes me about one to three months to learn a new platform. Well, if you're doing a Brown Field integration, you potentially have two new platforms that you need to learn. When you switch to a new job, it takes you a while to get your bearings in a code base, right? You potentially have two new, completely different code bases, one written in Swift, one written in Copy or Objective C. In Java, those have different patterns and different things that you need to learn. So initially, a Brown Field integration is probably going to be at least two to three times as hard as a Greenfield app. In other words, a Brown Field integration potentially nullifies many of the advantages of React native. So why would you do a Brown field integration? Well, there are many ways to look at technology, but from the point of view of a business, I think one way that you can look at tools like React native is the return on investment. So we're all software engineers. Our investment is the time that it takes us to learn the tool that we're planning on using. The return is what that tool enables us to do that you couldn't do before. A positive ROI should, in the long run, either save time or increase the pace of development for you or the organization that you're part of. For an individual who doesn't know React native already, and I stress that part. Using React native in an existing native app is probably a bad investment. So who would a Brownfield integration be a good investment for organizations? So as the number of engineers working on any app grows, an investment in infrastructure is usually required to maintain the pace of development. Examples of infrastructure investments that organizations might make are as follows optimizing build times, applying continuous integration, applying Linters, changing your data store, or using GraphQL, something like Apollo, which Peggy was talking about would be pretty awesome in a larger organization. React native is just another piece of infrastructure that you can view through the lens of return and investment. So which organization should try a Brownfield integration? Well, I would say using React native in a Brownfield app is probably best suited for larger organizations for the reasons that I outlined in the slides before. React native is an expensive piece of infrastructure to integrate into an existing native code base. Ideally, organizations that have multiple teams working on the same app for multiple platforms. Ideally an organization that already has a web team that uses and is familiar with React react native in theory and I stress in theory can help those organizations that just described be more efficient. The cost of learning can be paralyzed by having multiple people work on a project at once. So if you imagine how you would go about doing a React native integration, you'd have your native iOS and Android engineers do the initial build out in such a way that subsequent engineers coming from for example, the web team don't need to know the specifics of how the iOS platform works or the Android platform works. They can just focus on doing business logic and display and React native and being very productive. However, adopting any new piece of infrastructure can result in failure if you choose the wrong project. This isn't just a Brownfield React native integration thing. So let's think about a scenario for a second. Let's say you're a native iOS developer and you're on a tight deadline for a product feature, and a week before you have to ship your app, you say, hey, I've been reading Hacker News. This round thing is a really cool new database. I'm going to get rid of core data and switch over to Round. That's a very risky, invasive thing to do, and it might make you slip your schedule. And if that happens, people will be annoyed within your organization, at Realm and at you. But that's not to say that Realm isn't a good database solution. You just picked the wrong project and you timed it wrong. So it's very important to choose the right project at the right time for your organization. This begs the question, how do you pick the right project for a Brown field integration? Now, I have been doing consulting and contracting for a number of years, and I've been working with companies doing Brownfield React Native integrations, and a lot has been written about Brownfield React Native recently. But one article in particular that resonated with my experiences as a consultant that helps companies do Brownfield React Native is one written by the cofounder of Expo Mr. Charlie Chiever entitled should we use React Native or should you use yeah, should we use React Native? Sorry. So here's what Charlie has to say, and I think this is really solid advice for people getting started and who are just experimenting with Brownfield React native. He says the following. If you're thinking of using React Native for a few things, like a setting screen, an FAQ, or something like an about page, the kind of thing where you just stick in a web view, you're likely to have good luck. Now Charlie doesn't just stop there, though. He goes on to issue a warning. Now before I show the warning that he issued, I just want to say something. So I spoke at Chain React last year and I've been asked a number of React native events, both as a speaker and as an attendee. And when you talk to people at these events, most of the people are web engineers who are coming to mobile and React Native is their first foray into mobile. So a lot of those people may not be aware of the history of JavaScript and mobile. So a lot of people who are iOS and Android engineers have negative experiences with JavaScript in the past. They might have an outdated view of it and think of JavaScript as being synonymous with Jquery and like hybrid web apps, that didn't feel very nice. So Charlie says the following. There are people who identify themselves strongly as native iOS or Android programmers and have a really hard time being happy with React native. Ios programmers in particular are very unhappy with it and generally regard JS as an infestation of the company's code base. It's true. For example, I would have been one of those engineers a few years ago because I've been doing like mobile development since 2008. And if you go back in time like Yahoo, all of these companies were all doing hybrid mobile apps, and at the time I hated working with them because JavaScript back in 2008 was like Jquery and it was web views and mobile browsers were very slow and stuff like that. So if you're going into an organization and you're trying to pitch React native, you have to be mindful that the engineers who've been working on mobile for a long time might not have the current view that you have, which is that, hey, in the last few years, Babel and transpilers are a thing, TypeScript is a thing. There's all sorts of cool stuff going on with reason. There's all of this tool chain that makes it totally different. They don't know how React works, and so they might have a negative perception of you. But luckily for you. I gave a talk because I consider myself an iOS engineer first and a reactivated engineer second at an iOS developer conference called UI. Comp. And the title of the talk is an iOS Developers Take on React Native. In this talk, I explain how React native works, how it's different from hybrid web apps, and how a lot of things have changed, both in terms of the frameworks like React and transpilers and other stuff that makes JavaScript are awesome. So this talk is geared towards native developers, and you might want to check it out if you're trying to explain to people why React native is not an absolutely terrible idea. So Charlie also goes on to say the following thing, which I agree with. Even if you're using React native for things that it's good at and having success, it can still be hard for largescale native and react native development to exist in the same organization for nontechnical reasons. So again, as I just made the case, this is a technology that's probably best suited for larger organizations. In larger organizations, you have to deal with the relationship with different teams. So if you want infrastructure to be widely adopted in an organization, it's important to build trust in both you and the infrastructure that you're trying to get the organization to adopt. This isn't just a React native thing. This also applies to databases and other types of technology that you might want other people to use. So I endorse the Charlie Achiever approach, start small, and build momentum on your success. Ideally, your first Brown Field project should be something simple and quantifiable. A lot of native engineers will see the word JavaScript and think, oh, this is going to be really slow and buggy. If you start out with a small screen, a promotional dialogue, and about things, a setting screen, or whatever, you can put those fears to rest, or at least mitigate some of them and build momentum. Okay, so I've given you some food to thought for thought, but now you've decided you actually want to try this out. So how do I do this? Well, I'm going to show you an example app, and this example app that I've written is actually based on some work that I did for a San Francisco based startup called Keep Safe. Keep safe. Basically, they sell a suite of Privacy tools, and they have a freemium business model, and they get you to upgrade to a subscription for more features. So what KeepSafe wants to do is they wanted to basically power the dialogue that converts you from a free to a premium subscriber with React Native so that they could iterate under A. B tests faster. So they wanted to be able to use code push to shift new experiments without submitting a new app to the app store. So let's look at this example. You can find the source code for this example up on my GitHub here. And what we're going to do is the white screen that you see is the native part of the app. The blue and purple screens, which match the Chain React color scheme, are powered by React Native. This is going to simulate this flow. So let's play this demo. So what does this example need to do, irregardless of if we were using React Native or not? Well, we need to display a particular upsell experiment when a user does something in the native app, that something might be tapping a button or an icon, or it could be when the user's account is in a certain state and they use the application at a certain time. We also need to get a list of the available experiment screens at Runtime. So when the application starts up, we need a way to say, hey, what screens have you got into so that the A B testing system can know which ones we can show you in this particular version of the app. So what parts of this demo or React Native powered? So as I said before, the white screen is all native, and the colored screens are React Native. And this is kind of a rough diagram showing the flow between the two components. So what does our React Native integration need to be able to do? Well, fundamentally, we need a way to send and receive events between React Native and the native applications you're integrating into. We also need a way to pass data in and out of React Native. So how do we do this? Well, luckily for me, some very smart engineers from Pinterest were doing some brownfield integration work, and they came up with a solution called React Native EventBridge, which makes it easier to bridge React Native in the context of a Brown field application. You can find it up here under Get up. It's a really good package. They're actually here today at Chain. React Torbin might be a little bit easier to find than Michael. Michael doesn't, in fact, look like a disembodied Starbucks Cup, but they're both awesome people. You should talk to them about Brownfield React Native at Pinterest. Okay, so let's talk through this from the point of view of you clicking that purchase button, what's actually going on? So when I click Purchase, React Native is going to emit an event in JavaScript with an SKU. An SKU, for those of you who haven't worked in commerce, is just a unique identifier that maps back to an item. In this case, it would probably be put into Apple Pay, but it could be something that would be a Shopify ID or something else. Events are just strings that are defined both in JavaScript and in native. Native code has event handlers that hook into the existing payment system. So there's basically a handler, a callback function that's waiting for a string to come across the bridge with an optional payload, and it's going to do something when that occurs. So let's go look at this example again and enumerate the events that are going to be coming back from React native. So we kick off the React native screen. We tap the close item. That's a dismiss event. We click the purchase button, and that dialogue that's coming up there that's meant to represent an Apple Pay event. So that's also going to be event that's going across the bridge. So what happens? So when the application starts up, when we're displaying that white screen, before any React native is on the screen, we get a list from React native of all the screens, and we build basically them into our AB testing framework so it knows what you can display when you dismiss a screen. We need to tell the native navigation system to dismiss the screen that's in front of the user. When we make purchase, we need to hook into Apple Pay or whatever we're using in the native side, and we need to handle that purchase event. So on iOS, every screen roughly maps to at least one view controller. A view controller, loosely speaking, is kind of analogous to a React component. So there is a native view controller that's hosting the screen that's displaying the React native UI, which is the purple and blue stuff up there. This native view controller is responsible for processing the events that are coming back from JavaScript, and React native is responsible for basically the business logic display logic, and it also, in a more built out example, would have code push integrated, and when code push receives a new set of screens, it would send basically that event over the bridge, and the native code would update the manifesto screens in the application. So what does this look like in code? Well, we would define a bunch of strings to represent events roughly like this. Your component would look like a normal React native component, but let's just Zoom into the purchase function. What is actually going on there? So this is using React native EventBridge to emit an event that's going to be caught on the native side of the bridge. And this event that we're emitting is just a string like I showed you before, and we're passing with that a dictionary that contains the SKU. So what does this look like on the other side? Of the bridge in the native side. Well, we have some constants that correspond to the events like dismiss screen, purchase item, list, Greens. We also have a view controller. Again, remember a view controller is roughly analogous to a React component. But this is the thing that when you actually click that purchase item button gets instantiated. And in this it has a bunch of code that basically set up callback handlers to handle the events as they're coming across the bridge. So let's Zoom in on one of those. So in this particular example in Swift, what we're doing is we're saying hey, when we get a purchase item event, call this function. And in this particular example, I'm obviously not hooking it up to a real purchasing system. I'm just displaying a UI alert dialogue. Right. Okay, let's Zoom out and see in totality all the JavaScript code that went into powering this application. So what does the entry point for this look like in JavaScript? Well, just like a normal React native app that you would create, it has a place where you register your module and it has a render function. Component did Mount component will unmount. In the render function though, I call a function called Get screen. And with this Get screen function I'm passing in the props that came true initially with React native. So this gets green function basically is just a big series of if statements that checks to see if the screen key in the props that you passed in corresponds to a component that this bundle is aware of and it returns that and that will be what gets rendered with the props that you passed in. Below, there is a screenless function. This is the thing that actually gets sent back to native when the application starts up. So the native application will start up and just say hey, React native what like screens are in there? And I return basically a list of all of these screens with configuration files associated with them. Those configuration files which I'm going to show you in just a moment will be turned into props and passed through when you instantiate the React native thing that's being displayed. Again, this is just the constraints that we're using in our React native application. The Upsell screen. I showed you this before. It looks exactly kind of like a normal React native component. It just uses the React native EventBridge to emit events. So what about this configuration screen? Why do I do this? So this is the default properties that I want to use to drive my screen that I'm displaying to you. One thing that we do include here is the skew and the price. The reason why we do this is you might want to actually localize the price to different countries and you would do this probably using the existing Apple Pay infrastructure. Or at least that was what my client did. So what would happen is by default it would pass down the skew and config, but it might change the price depending on the locale it is and you do that in native code. So what happens when React native displays a screen? So again, as I was saying, every screen in iOS has at least one view controller in it and React native viewcontroller Swift is the thing that hosts React native. And so when that gets instantiated, it basically passes down some props which are based in the config JS file that I just showed you. Index. Js gets called when the screen is shown and it basically figures out based on these props, which screen to actually display. In the props there's going to be a screen key that you will set so you can use the same React native viewcontroller Swift to power multiple React native screens if it doesn't find the screen. I also include a screen not found dialogue, but that should of course never ever happen. Native code has event handlers in it. Those event handlers live in this example in React native View controller. And whenever an event like dismissing a screen or talking to Apple Pay occurs from yet native, basically a callback gets called in those code. So let's have a look at what this looks like in native code. So if you're not familiar with iOS development, an app delegate is basically the entry point into your iOS application. It is the first thing that gets called and the lifecycle functions that are in there correspond to different events that pertain to all of the different view controllers in your app. So basically what we're doing here is we're basically talking to the React native view controller and saying hey, the application did launch. So basically fetch all of the screens out of React native and warm up the bridge for me. React Native Viewcontroller Swift I showed you that earlier. Basically what this does is it handles processing all of the events that get sent back from JavaScript. React Native Event this is some objective C Code that I wrote to handle an event and it's basically just a string and a callback function which is the handler. In this example, React Native Host Controller is the parent class of React native Viewcontroller. Swift. It just basically defines the interface that you're going to use for basically adding, removing events, or telling the React native that the application did launch. It also is a way for you to insert data into a React native view after you've displayed it, right? React Native Constants this is just basically the strings that I'm using in the native side of the code base and this little thing. React native Screen Manager this is the Singleton where all of the screens get put into and it's meant to simulate an A B testing framework. So basically when I click that button I'm going to call into this and say hey, give me a random screen and a set of props to display at runtime. Okay, so that's the architecture. But how would you actually apply this if you are going to do a brownfield react native integration? Well, let's talk through a scenario. Imagine that I'm working with Michael and Torbin at Pinterest on a new product and imagine that I don't have all of the native iOS knowledge or Android knowledge, and I am just a humble react native engineer. But Torben is an expert Android engineer and Michael is an expert iOS engineer. How are we going to ship a new product feature? Well, the first thing that we do is we probably get together and we'd look over the Max that had been designed by our designer and we would just ask ourselves, hey, do we need to do any native work to support this new feature? And if the answer is yes, then Torbin and Michael spring into action and I stubborn some events and continue on implementing my JavaScript or TypeScript or flow react native UI. We then basically converge with our PM and we basically look over the mocks and we test it out. If something is broken on Android and the native side, Torbano will fix it. If something's broken on iOS, Michael will fix it. If my UI looks a bit whack, I'll go make that awesome. But when the designer PM and our testing process is happy, we then move on to the next stage. We basically can't do over the air updates for native code. So if we had to implement any new native features, we basically just package up our bundle, put it into the app, and we wait for the next release cycle for that to go into the App Store. If we want to do an over the air update and we haven't done any native changes and the PM or designer is happy. We'Re good to go. We'll just push it out immediately and turn on the test for those users. So I'm not the only person who's done speaking or has written about brownfield react native. There's a bunch of awesome people who've done really great work, and I think one of the most famous of them is Artsy. Artsy have a brownfield react native application and if you're thinking about doing brownfield react native, their blog is an absolute must read. You definitely should check it out. They've also open source their application and they've open source a component library. That's really good and it's worth checking out. One of the main contributors as Artsy, who does a lot of work on Cocoa pods, Danger and brownfield react native is Arthur Ortho is an absolutely awesome guy. He makes a great cup of tea. You should follow him on Twitter. Totally great guy. I believe they are hiring as well. So shout out to Artsy and Pinterest are experimenting with brownfield react native. So Vivian Q wrote a really great blog post about this. I believe that Vivian is here today at Chain React Torben who I mentioned earlier gave a more Android specific presentation on Brownfield React native at Roycon Berlin a really awesome Android developer conference entitled Leverage your Android knowledge to boost your team's velocity with React native you can follow both Tourben and Michael on Twitter. They're two awesome guys they're here today so have a chat with them. I would also just like to add that I do React native consulting, contracting and training and I actually have been doing Brownfield training specifically. So if you're interested in hiring me or you need any help with your projects, shoot me an email at Harry n [email protected] you can follow me on Twitter at hturni and I will be publishing these slides to my medium blog which you can [email protected] I just want to finish off by saying thank you so much to Michael and Torbin and Rob for helping me out with my presentation and for keep safe for letting me help them out with their application and I also want to say thank you to infinite Red. This conference is absolutely awesome and you all are absolutely awesome for listening to me, RandallAn thank you so much all.