We took some time to reflect back on some of the best lessons we've learned after completing over a half dozen React Native apps. Here are our top four takeaways and lessons learned from our experiences building large React Native applications.
Develop iOS and Android at the Same Time
Not every React Native app we build targets both Android and iOS (yes, we like React Native so much we use it even if we don't need its cross platform capabilities.) When we are expecting to target both platforms, it is extremely important that we develop styling and platform specific functionality for both at the same time. Going back and adjusting styles per platform later is asking for frustration as a fix for one breaks the other. In our experience, it is more cost effective to style for both platforms at the same time, rather than one and then the other.
What version is the app? (Build ≠ Release ≠ Semantic Version)
Remember, what you list as the version in the various app stores has nothing to do with what version your app thinks it is. When building an app to replace an existing one, clear version management is exponentially more important, but will also quickly become important if your app takes off and becomes popular. It is also extremely important because hopefully you are continuing to iterate on your app.
Let's clearly define 3 terms:
- Release - A compiled app binary that you are going to send to App Store Connect or Google Play.
- Build - The build number (or Version Code in Android) must always be increasing, so increment this every time you push to the store (a release), no matter what you are trying to accomplish (test release or public release).
- Semantic Version - The public facing version number, which can be set in a few different places, in the store its just a vanity, more importantly, in your app's code, it should know its own semantic version number.
The lesson here it to make sure the internal semantic version number understood by the app is correct, and you'll get some big wins.
First is that your crash reporting will correctly identify the version that had an issue, beyond just knowing the build number. As I mentioned, the stores will require that your build number and release number are increasing, but we find that a semantic version number is much easier to discuss and understand what features have been enabled in that release. Second, the latest release report from Firebase (more on Firebase later) is super useful to measure adoption, and it relies heavily on the semantic version number your app has coded in it. Finally, you want the app to understand it's version number, and show the user somewhere in the app so that they can refer to it during support calls.
Managing the semantic version number and build version number were not as simple as we expected. Fastlane (more on this later) helps, but it can't increment the semantic version numbers for all platforms, or do so necessarily in the way you want it to. Here is the approach we took:
- Increment the build number every time we push to a store, including alphas and betas.
- Before every public release to the stores, increment the semantic version number.
- If it is just bug fixes, increment the patch version number.
- If you add enough major features or changes that you want to increment the major or minor version numbers, then move those forward.
This way your build number will march on, making updates easy to track, and you'll have a new semantic version in the stores so you can measure crashes and rollout easily.
Descriptive and Organized Code
For our most recent React Native project we used a very strict code review policy; we ensured that a developer unfamiliar with the code read and reviewed it. Most of the time, that developer was me. I've got a great team, and they are doing amazing things with React Native (as I've outlined in this post already) and I'll be the first to admit, I'm not as fluent in React Native as they are. The code the team wrote, especially with smart use of Redux and Sagas, was extremely readable. No matter where in the app they were working, I was able to understand what was being built, and how it was expected to work, even with minimal context.
This has been even more apparent as we've had a few bugs to squash or additional features to add; thanks to our well organized, and super clear code, it has been easy for me to jump in and help out. This really helps solidify my belief that this is a great direction for mobile development, because ultimately finding good developer talent, and making sure they can dive in quickly is a big deal. React Native has helped empower our team to excel in mobile development and bring in new talent who are able to become productive quickly.
Invaluable Tools and Processes
There are a number of tools we used that really helped with our processes:
- Sagas We've used this in various projects before, every time we are better organized and they have even more value in describing the flow of data and logic within the app.
- Fastlane We used this to automate builds, and it worked really well.
- React Native Debugger This desktop app is crucial in the development of the mobile app if you’re using redux and sagas.
- Firebase This is a great set of tools, and was very easy to integrate for analytics, crash reporting, rollout monitoring, remote configuration, and push notifications.
Do you have a mobile app idea? Get in touch and we can help turn it into a scalable, maintainable, and successful reality.
Header photo by Janko Ferlič on Unsplash