TL;DR: A couple of months back, I wrote about a TODO app built using React for web and React Native for iOS.
Last week, the team at Facebook released React Native for Android. So, I circled back to add Android support and revisit how code sharing looks now.
Getting up to speed
With this new release of React Native, I was able to add support for Android to my little TODO app.
The first task was to shuffle directories & files around and add the base Android support. In general, the project layout is now cleaner. Assets for each platform now live in separate sub-directories.
Next, to start iterating & experimenting, I copied the code from the iOS app into Android-specific directories. I only needed to make some small tweaks to account for differences in native component sets. That got my base app functionality working.
Then, I squashed the iOS & Android models together when I realized that code was identical between the React Native platforms. That could change in the future, but there's no need for a difference right now.
After sleeping on it, I refactored some common mixins to take advantage of additional sharing opportunities I found between iOS & Android views. That helped to further shrink the lines of duplicated code.
This added what amounts to a new category of code sharing in my project. So, I separated that code into its own module to make the distinction easier to see & measure. Now, I have code shared between web and native in general, and code shared between the iOS and Android native platforms.
Finally, in an attempt to start automating my code metrics, I added
Visualizing the code metrics
So, I tried drawing some Venn diagrams in my notebook. But, I'm terrible at drawing. That's when I remembered that SVG is a thing where I can draw by writing code. So, I spent an afternoon teaching myself some SVG and reworked my metrics shell script.
I'm not going to bother trying to make the areas actually proportional to the lines of code. But, here's a rough picture of code sharing:
If you can't see those images, then you'll need to find a browser that understands SVG until I can be bothered to convert to PNG. (Pull requests welcome!)
As before, most of the models code is shared between web and both native platforms. What's unique is mostly boilerplate wrapping the localStorage / asyncStorage split between web and native.
On the view side, however, things are a bit more spread out. In a nutshell, React patterns in general allow a decent chunk of code to be shared between web and native. And even more code can be shared between the iOS and Android platforms.
But, unique concerns in each platform - web, iOS, and Android - call for unique code for each case. This is not actually a failing, though: Varying the UX between web & iOS & Android is a flexibility you'll probably appreciate.
In other words, use components & conventions unique to each platform without your app suffering from the lowest-common-denominator UX problem historically found in a lot of multi-platform apps. In the case of this TODO app, that just boils down to trivialities like checkboxes & switches & segmented controls. In a larger app, I'd expect this concern to grow.
I'm being lazy and not coding up the math in percentages. This approach shared about half the code from the web app, and even more than that for each of the native apps. I think that's a significant advantage over writing separate apps.
Of course, all my caveats from the first go around still apply: This is a very simple app. The code devoted to doing interesting things versus React boilerplate is probably not at a good ratio. Also, as more view components arise, further overlap might be found. And, hopefully, common logic would remain the primary area of growth on the model site.
I think this approach toward building apps remains interesting & promising.