• React Native: A retrospective from the Mobile-engineering team at Udacity
  • Nate Ebel
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: pkuwwt
  • Proofreader: DateBro

React Native: A look back at Udacity’s mobile engineering team

Udacity’s mobile team recently removed the last feature of our app written in React Native.

We received a lot of questions about React Native and its use, and people asked us why we stopped using React Native.

In this article, I hope to answer most of these questions, focusing on:

  • What is the size and composition of our relevant team?
  • Why did we try React Native in the first place?
  • Why was React Native removed?
  • What works? What doesn’t work?
  • . And others 🙂

I certainly can’t claim to be an expert on React Native. There are people on our team who have more experience than I do, but they’re not necessarily experts.

I just want to talk a little bit about our own experience, what works and what doesn’t work in our particular usage situation. Whether React Native works for your team/project is entirely up to you. The purpose of this article is to provide you with some additional useful references when making decisions.

“It’s entirely up to you to use React Native on your team/project”

It should also be noted that the experience and insights here are from Udacity’s mobile engineering team, not the rest of the company. Our thoughts do not represent those of other teams that use React/React Native, or build content for it.


team

First thing, what is our team like? The size, experience, and organization of your team will have a significant impact on how React Native works in your project.

Our mobile engineering team covers both iOS and Android platforms.

Team size

React Native

  • 1 iOS developer
  • Two Android developers
  • 1 PM
  • 1 designer

now

  • Four iOS developers
  • Three Android developers
  • 1 PM
  • 1 designer

In the 18 months or so we’ve been using React Native, both our iOS and Android teams have expanded. The team also has a new PM. We also went through multiple designs and multiple paradigms.

Developer background

How comfortable was each team with the JavaScript and React programming paradigm when React Native was introduced?

iOS

The only original developer on the iOS team was comfortable jumping into the React Native camp because he already had a lot of JavaScript and Web development experience.

Currently, 3 out of 4 iOS developers are comfortable with JavaScript and React Native development.

Android

When React Native was introduced, one of the two Android developers was comfortable with JavaScript. The other (myself) has little background in JavaScript, React or Web development.

Another Android developer who joined later also had no JavaScript or Web development experience.


The application

What is our application for?

The goal of our mobile application is to bring Udacity’s learning experience to mobile devices. They need to support authentication, content discovery, project registration (and, in some cases, payment), and finally the use of learning materials for different projects and content types.

These apps are also hotbeds for testing new experimental features that improve the user’s overall learning progress.

The size of the code base

  • IOS: 97400 lines of code (.swift,.h,.m)
  • Android: 93000 lines of code (XML, Java, Kotlin, Gradle)

Functional consistency

When React Native was introduced, the functionality of these applications was basically the same.

The core experience remained largely the same as the project progressed, but each team had some “experimental” features that were unique to a particular platform.

In addition, requirements such as localization and smaller APK package sizes are increasingly priorities for Android teams due to greater internationalization requirements. The Android team also works closely with teams in other regions to develop features for specific markets that the iOS team doesn’t have to focus on.


Why/How React Native was adopted?

Why did we introduce React Native?

At the time, we wanted to develop a completely new feature that only worked on mobile devices. We want to experiment and validate quickly on both platforms, so cross-platform is very attractive.

Because this is a new closed feature, we see it as an interesting experiment with a cross-platform approach.

We chose React Native for the following reasons:

  • Increasingly viable cross-platform solutions
  • Most of the team (two-thirds of the developers) are comfortable with JavaScript and Web development
  • Faster development
  • Success stories of other teams outside the company

How did we introduce it?

Our initial React Native feature was based on a separate GitHub repository, which was then incorporated back into both iOS and Android repositories as a Git subtree.

This approach allows for very rapid prototyping and, if necessary, allows the feature to be released as a standalone product.

As we gained more prototyping experience, we gradually added a larger second feature to the React Native repository.

A time line

  • Aug 2016: Create the React Native repository for feature 1
  • Nov 2016: Feature 1 released on Android
  • Nov 2016: Development of Feature 2 begins
  • Dec 2016: Feature 3 prototype development begins
  • Jan 2017: Feature 1 development completed
  • Feb 2017: Function 2 released
  • Mar 2017: Feature 3 prototyping finished
  • Nov 2017: Last update for Feature 2 on Android
  • Dec 2017: Feature 4 was prototyped as a standalone app. Finally, it was re-implemented in native code for performance reasons.
  • Feb 2018: Last update for Feature 2 on iOS
  • Apr 2018: Feature 1 removed from Android
  • Jun 2018: Feature 2 removed from both apps at the same time

Remove React Native’s motivation?

The answer is fairly straightforward.

We removed the last bit of Code related to React Native from the app because the only remaining React Native feature was about to go offline and we weren’t going to support it anymore.

“Why stop developing new features with React Native?”

The more interesting question might be: Why did you stop developing new features with React Native?

The reasons are as follows:

  1. The number of features that need to be developed on both platforms drops
  2. Android platform unique product requests increased
  3. The nightmare of long-term maintenance costs
  4. The Android team was reluctant to continue using React Native

So what will replace it?

Features developed with React Native were removed and are no longer supported, and we have no need to replace them.


What works well with React Native?

What do we do well with React Native?

  • React Native is fairly easy to get up and running, and build on both platforms
  • Code bases and tools can be drawn from the React and JavaScript larger ecosystems
  • We can prototype functionality on both platforms at the same time
  • In a cross-functional team, the same developer can build most of the code for Feature 2 for both platforms simultaneously
  • The team’s common understanding of React Native has deepened

What problems have you encountered?

In the process of using React Native, we encountered a series of problems. Some of it comes from our use process, some from our use cases, and some from React Native itself.

Design and user experience challenges

Platform consistent UI/UX

Because we were integrating several new screens into the larger user experience area of the existing React Native, we wanted the new React Native code to adhere to the development model and style of the Native platform. This means we don’t have to have the same UI design on both platforms.

It’s easy to adapt React Native’s style to the Native platform, but you need to understand the design paradigm in each code base. At a minimum, you should check each platform and even develop new custom controls for each operating system.

For us, it’s often necessary to reach out to developers and designers on each platform to understand what needs to be done, otherwise using one style on both sides will result in a completely different user experience on Android than on the rest of the app.

In more complex cases, we need to write additional platform-specific code to customize the user experience for each application.

One example is ensuring that a back/ Up icon behaves correctly. Since the new React Native code is integrated into existing apps (where/how), ensuring the correct behavior of the back/ Up icon and back button clicks requires Native code on the Android platform, You also need to make Android specific code changes in the React Native code base.

Changes in the Native design will result in changes to the React Native code when integrating functionality

In at least one case, when the navigation structure of an Android app changed, we needed to update the React Native code accordingly, for no other reason than to handle the integration issues.

We haven’t been able to make them exist independently. The React Native implementation’s functionality is actually in a fragment, which is placed first in the screen of a BottomNavigationView and then moved to a coordinate state between itself and other local fragments.

Such platform changes require going back to a separate code base, making changes and updating the integration to ensure that new changes do not negatively impact the iOS application.

Equipment related problems

Whether you call it “fragmentation” or “fragmentation,” the reality is that there are more unique configurations to consider on Android devices.

In many cases, we found that the layout didn’t fit well with the different sizes of Android phones. We found that animations run smoothly on the latest iphones and Pixel devices, but not on low-end devices that are more widely used in international markets.

This isn’t unique to React Native, of course, but is a common issue in Android app development. However, this is a platform-related issue that we need to consider. When these issues become more common, we have to reflect: How much time does React Native’s cross-platform platform save us?

Global growth

During our time with React Native, the Android team became increasingly focused on internationalization. We have several international offices that require localized and lightweight APK packages.

React Native can do string localization, but requires additional Settings. In our case, it requires code changes to different repositories. This adds to the complexity of the localization task, especially if you need other teams to help with the localization, which is not great. This makes features implemented by React Native less localized.

We were able to reduce the APK file size as required, but it was difficult to handle the sizable portion of the React Native footprint. When we removed the last feature implemented with React Native, our APK was reduced by about 10MB, including the Command Resource and React Native itself.

Integration Challenges

Integration with local components and navigation structures

In our experience, when integrating React Native into an existing application, the integration is fairly straightforward if it’s a standalone feature; But how you need to integrate and communicate tightly with existing components is where you run into trouble.

We found that a lot of bridging code was often required to communicate between the React Native component and the React Native component. This part of the code also needs to be updated when we need to modify the React Native component to fit the navigation structure.

Toolchain/build issues

Integrating React Native requires updating the build process for each application. We used CircleCI to build our project, which needed to be reconfigured to support additional React Native build steps.

As we explained in our previous article, it’s not that intuitive on the Android side.

React Native packaging on Android: How do I run the React Native packaging command line when Build_engineering.udacity.com is released on Android

Once our build process included the required React Native tasks, it increased CircleCI’s release build time by about 20%.

After removing the last React Native feature from our codebase, we made the following improvements:

  • CircleCI builds in about 12 minutes instead of about 15 minutes
  • Apk distribution file size changed from 28.4MB to 18.1MB

The Android team also experienced some issues with Android/Gradle build tools colliding with React Native. Recently, we have been working on issues with Gradle 4.

The iOS team also had a number of issues.

Configuring the build tool was a pain because we used a non-standard file structure with React Native. Since we have multiple project repositories, we put the ReactNative repository in the srcroot/ReactNative directory, whereas many existing build tools assume the default application file structure is /ReactNative/ios/ios.

In addition, we used Cocoapods to manage dependencies, which was originally recommended with React Native but is no longer recommended. This problem is exacerbated by our non-standard file structure, which requires annoying little tricks in podFiles to read files from the correct location.

Since Cocoapods is no longer the standard way to include React Native, updates to podfiles rely on community updates, which are not always synchronized. Several versions of our CSS /Yoga dependencies have been updated, but the Podfile still references the wrong version. At the end of the day, we were still using some nasty post-install trick, which was really just sed/regex to locate the included calling code.

Finally, THE CI of iOS projects is also a pain point. Now we have to add an NPM dependency layer and make sure we update it properly before continuing with the installation. This adds a lot of time to our build time.

We also had a crash because one version of NPM had package.lock and the other didn’t, which caused us to install the wrong dependency version during a React Native upgrade.


React Native’s own challenges

The document

React Native develops rapidly as a whole, but we also find that its documentation is sometimes lacking. Especially when we first adopted it, we found that certain versions of documents/answers may or may not be only relevant.

Currently, there is little documentation to integrate React Native into an existing project. This is also a headache when we update our CI build.

As React Native continues to evolve, documentation and community support have improved. If we started using it today, maybe some of our past questions would be easier to answer.

navigation

We started with NavigationExperimental, which is not an easy navigation library to use. When ReactNavigation appeared, it quickly became the accepted Navigation in the community, so NavigationExperimental was gradually phased out of recommendation before ReactNavigation was fully adopted.

However, there is no way to implement functionality with ReactNavigation (e.g., push flow in a current Modal stream) without forcing something together.

performance

As mentioned earlier, we noticed performance issues several times.

We can do really nice animations on iOS and Android devices with enough space, but they don’t work well on low-end Android devices that are more widely used in the international market.

The React Native part of the app took longer to load than we expected. That makes it less of a seamless transition.

When prototyping standalone feature 4, graphics rendering performance became a major concern because React Native couldn’t match the performance of Native applications.

Lag behind local platforms

Because React Native isn’t built in sync with iOS or Android Native apps, React Native often lags behind Native platforms. It often relies on new native functionality supported by the community.

One example is much-needed safe Area support for the iPhone X. We ended up having to temporarily not support SafeArea because it was coming out soon. SafeAreaView is a platform-specific feature that cross-platform developers need to take into account when developing relevant features.

React Native has also been slow to adopt new platform requirements at other times, such as in August 2018 when Android apps were required to adopt API 26. There are still some unresolved issues to implement this requirement.

No continuous updates

React Native doesn’t support backward compatibility, which is pretty frustrating. An example is React Native’s PropType Deprecation when upgrading its React library.

Unless you maintain your own custom replica repository, many third-party libraries will become unusable without continued maintenance.


Maintenance Challenges

The React Native part of the code base is a constant headache to maintain. As mentioned earlier, Android often requires extra work to integrate with existing code or fix UI problems. This keeps iOS and Android out of sync on different branches of the React Native code base so that development on different platforms doesn’t drag each other down.

Because of this branching problem, the code slowly began to diverge, and it took more and more effort to bring them back together. As a result, updates on one platform do not immediately reflect on the other.

The speed of React Native’s changes also poses a challenge. Because of the potential for non-continuous changes, we often can’t update a dependency quickly enough to add a new feature or fix a BUG.

Also, sometimes this creates more friction, which slows down the frequency of code maintenance. For a small team with limited bandwidth, if you can’t easily/quickly fix React Native code, the chances of fixing problems in your code will only get lower and lower as it may involve additional development effort.

After adding React Native, it is often not clear at which level a BUG exists. Is it on both platforms? Or is it platform specific? If the BUG exists on only one platform, is it Native code or React Native code? These issues add complexity and slow down the QA process.

When fixing a problem in the React Native part of the code base, we currently have to consider both iOS and Android, so it’s possible to consider three technology stacks instead of the ideal one.

Also, because not everyone on the team is comfortable with React Native, there are fewer people who can jump quickly between technology stacks and fix problems.


Can we do better?

I believe that some of the problems we face stem from our specific use cases, but some of them can be mitigated.

Fewer code branches

We can do better by keeping the application consistent with the changes in the React Native repository. I believe that keeping these updates in sync will give us a stronger cross-platform feel when implementing these features.

Increased testing on devices, especially Android, helped us catch more UI/ performance issues early and fix them before release. Fixing problems before new code is written further reduces the number of code branches.

More consistent design

It is possible to improve the native appearance of these features by adopting a more specific design plan from the outset. A specific example is using text/margin values consistent with the rest of the native application, rather than using new values in the new user experience area, and applying them to both platforms.

Understand your team better

Those members of the team who are less comfortable with React Native should work harder to adapt to other technology stacks. This increases the number of people who can quickly fix the problem.


Is there a use case better suited to React Native?

I don’t think anyone on our team thinks React Native is bad. Obviously, I believe there are use cases where React Native is more appropriate.

Do you need to quickly, two-platform, prototype/build a new app from scratch?

Do you need to implement an application/feature that looks/behaves platform-independent?

Do you have free JavaScript developers for mobile app development?

If the answer to all of these questions is yes, React Native might be a viable option for you.

In particular, React Native is very attractive if you have a JavaScript/React background and don’t need much Native code. It allows you to start building a mobile application without having to learn two technology stacks.

React Native would also be a good choice for a completely cross-platform app development juggernaut.


Will we still use React Native?

The iOS team and the Android team have a different story.

iOS

Possible. The iOS team is generally happy with the React Native development and is already considering using it to build new features. Also, in terms of product launches, our PMS have more confidence in the React Native solution on iOS devices than on Android.

Android

Don’t. Ideally, the Android team would not invest in React Native. We found the React Native component’s integration process to be cumbersome, and the user experience doesn’t work equally well on all Android devices.

Furthermore, we prefer to stick with one technology stack rather than add another layer of abstraction to the Android framework, which also means adding potential bugs.

Our impression is that the process of creating new features for Android with React Native is relatively fast, but the transition from an early stage to a final release, as well as the long maintenance process, tends to take longer.


Will we use another cross-platform solution again?

As a team, we’re probably not going to jump into cross-platform development anytime soon. It’s possible that iOS teams will build something new with React Native, and only on iOS devices, as they will generally enjoy the development experience more.

Individually, team members will continue to focus on React Native and Flutter. Because solutions such as React Native and Flutter are constantly evolving, we will continue to evaluate these technologies for our team.

So, that’s where we are today.

We have a better understanding of how React Native fits into our team and roadmap. We can use this judgment to guide our next decision and make the right technology choice for the team.

“Can we determine for sure if React Native is right for you? Can’t.”

We know the advantages and disadvantages of React Native, so can we determine whether React Native is right for you?

Can’t.

However, our experience can be used as a reference to help you evaluate the feasibility of React Native in your project.


Want to learn more about mobile development?

  • Google’s android development nanometer degree | Udacity: Launch your career with Google using our Android development nano course

  • Become an iOS development | Udacity: Learn iOS app development and become an iOS developer using our iOS Developer Nano course

  • React | UdacityReact is a completely disruptive front-end development. Work with Udacity to master this UI library from Facebook

  • Use Flutter to build local mobile application | UdacityLearn from Google experts how to use Flutter to create high-quality native interfaces on iOS and Android devices

Pay attention to our

To learn more about the engineers and scientists building Udacity, follow us on Medium.

Want to join us? Please @udacity, lots of opportunities.

Udacity on mobile devices

[on mobile devices Udacity |, the iPhone and Android: We have made the Udacity course experience onto the tablet and iPhone and Android. Start to learn the skills required to you) (https://www.udacity.com/mobile)

Thanks to Aashish Bansal and Justin Li.

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.