They announced they were moving to React Native three years ago. Since then, they’ve set up a mobile enablement team, they’ve set up an internal training programme, and they’ve ported four out of three hundred screens [edit: see discussion below]. They are choosing to do it gradually because their estimate for a rewrite was three years. They are choosing not to go with the “new features in React Native” approach because their estimate for that was four to five years.
They seem really happy with their “We all get shit done, ship fast, and learn” progress, but I’m sure I’m not the only one reading this article and coming away less likely to choose to migrate to React Native, right? This does not sound compelling at all.
Where do you see they only ported four screens? In the dashboard screenshot it clearly shows "RN Screen Count: 139/572", so they've ported 139 screens, right? The "four" figure you're referring to is the root navigation screens of the app which get a lot more traffic, hence why they prioritized those to uncover issues.
> Here’s a spoiler: Today, if you open the Shopify Mobile app, all four root screens are in React Native already!
If you write “where we are now: we’ve ported all four root screens”, that’s what I’m going to hear. I’m not going to look through screenshots for contradictory figures. If they have actually ported 139 screens, maybe they should have said “where we are now: we’ve ported 139 screens”? As far as I can see they don’t say anything like that at all, are you inferring from screenshots alone?
Regardless, my point still stands – if you need to set up a training programme and a facilitation team and it’s going to be a multi-year effort, and after all that you proudly tell people that they can’t tell the difference between the old version and the new version… this still does not sound compelling at all, even if you have got almost a quarter of the way through the project in three years.
They explained earlier in the article that root screens were larger, high-impact screens at the top level of the app. They even bolded "root screens" the first time it was used to highlight it as a key word.
I’m pretty sure they mean the root of navigation stacks. They have high impact as it’s the first thing a user will see and should contain all the most important features
That depends on what parts got ported. I worked on a large app where just a couple payment screens too as long as most of the rest of the app because there were so many business rules to take care of.
If they prioritize the most important and complex parts of the system, they may be a lot closer to finished than the numbers would seem to indicate.
Also when you write an app for iOS you have most of the code to target watchOS, iPadOS, macOS, tvOS, realityOS etc.
For an app like Shopify where users often want to see revenue, sales etc in different environments using React Native seems a bit short-sighted to me.
I would've just use Djinni [1], kept most of the core code in C++ and then build native apps. Approach that Dropbox, Snapchat etc. took and seems to work.
That's what really puzzled me about 1Password's switch from native Mac to Electron.
The reason was, "we want code sharing with Windows". Okay, you've got that now… it's terrible… but you're also maintaining a SwiftUI app for iOS and iPadOS. Why not code share that with Mac?
But code-sharing between MacOS and iOS is also investment in cross platform technology. They're _already_ managing two code bases, why does Mac have to be on the shitty one?
This probably works if a lot of your core code is not UI or presentation (dropbox sync, snapchat video filters). My guess is the shopify app is almost all presentation and their backend handles most of the heavy lifting and writing presentation in C++ is... not ideal
This probably works if a lot of your core code is not UI or presentation (dropbox sync, snapchat video filters). My guess is the shopify app is almost all presentation and their backend handles most of the heavy lifting and writing that in C++ is... not ideal
I got so frustrated with a cross platform technology i just wrote a native app to get away from it which the company later adopted. It implemented all latest native features, was tiny in size, and code base was easy to understand.
As it grows and our teams grow it does get harder, but also, if you’re using bleeding edge features, cross platform solutions can only cater to the lowest common denominator
I have had similar experiences on several decent sized mobile projects.
The idea of a single code-base to rule them all is very seductive.
The reality, when you get to UI and hardware issues, is when you begin to get frustrated.
If your app doesn't need perfect hardware coverage, great hardware sub-system coverage (cameras in particular), and you have some cohesive UI design that won't irk people on seperate platforms ... then go ahead, React Native, or ionic, or flutter, or plenty of frameworks will work for you.
Otherwise, I think it is better to just bite the bullet and run two separate code-bases with pretty tight project managment to keep them synced.
Well I give them props for at least having a facade of a "what went wrong" section, which most RN articles leave out, although it doesn't feel like an honest analysis of the negatives of their switch.
I'd like to see some actual data about what percentage of their code is written in native vs RN. In my experience you need to maintain massive amounts of native framework code on both sides to support the RN code, and to implement stuff that RN can't do or does horribly. Adding RN into the mix just basically adds one more platform to be supported, making things more complicated, rather than combining code into fewer platforms. RN teams never bother to mention how much native code is needed to support them, and seemingly never include native work that was done when giving metrics about how long it took to "write" a feature in RN, usually because a separate "native" team does that work, not them, so it's conveniently not mentioned.
Also curious about other metrics such as how many developers they lost that weren't interested in becoming JS developers. Or have they stuck around because there's still so much native work that they need native developers for, to support RN.
Anecdotally we've got a RN app, and we've only got one or two native source files for each platform, which are mostly there to bridge in third-party libraries for things like analytics. Our UI and business logic are almost 100% JS and it works out really nicely for us
Of course this is a mostly standard (but not small) CRUD app. We've got some custom animations/widgets here and there, but mostly it's vanilla forms, controls, views, etc. which translate easily to both platforms
We also started out on RN from the beginning; it's possible that migrating to it from native code is a much bigger challenge
Same for us. Certain dev environments bugs were been a big pain in the ass for us in the past. For the logic side of thing React Native has been a nice experience for us as well!
> [...] and seemingly never include native work that was done when giving metrics about how long it took to "write" a feature in RN, usually because a separate "native" team does that work, not them, so it's conveniently not mentioned.
In this case it seems like they transitioned a mostly native mobile workforce into React Native, so I don't know that the last bit makes much sense here. I agree with you that there is a general absence of information about how they still deal with the native side of everything with React Native becoming more and more important in their apps. Even just the "yet-to-be-transitioned-but-we-need-to-use-it" kind of stuff would've been more interesting to learn about and certainly "What native stuff remained in sections that were ported?" seems reasonable as well.
I’m one of few left in our company of our original mobile team after we switched to qt, and i pretty much soft quit by writing an entirely new native app
My personal opinion, it is the worst, we spent more time working on getting it to build than coding, it’s a platform only a die hard cpp developer could love and only because they’ve never tried anything different.
Even the mobile app we do have in qt has substantial coding in native. It doesn’t have things like faceid for login, light/dark themes, is extremely restrictive in supported devices and orientations.
There’s next to no community, anyone who does mobile just doesn’t use it, and imho, for very good reason, mobile dev moved on and supporters of qt just seem to like making it harder for themselves to support it.
I’d say it works ok on desktop, but i generally find qt apps on my mac look dated and have odd unmac like qualities.
I would love to see their test using a regular Android device, not a high end iPhone.
Android has like 90%? worldwide market share and most phones are way underpowered vs even old iPhones. Picking a solution that only works well for SV users is a terrible decision.
RN uses native controls (not a webview) and JS is plenty fast for most UI logic (it's almost never the bottleneck on slow web apps), so I would not expect performance to be a problem here
React Native is much slower on Android than on iOS, sometimes by orders of magnitude. You can get things usable on a lower-end Apple device, but on a lower-end Android an optimized RN app is still unusable. Part of this is due to the JS interpreter available on Android (which FB has tried to replace). But I think it's also due to architectural issues in Android itself and the natural overhead that RN has being too much in a constrained environment.
The real reason is the shitty CPU on typical low-end to mid-end Androids. They suck at running JS. And I mean REALLY suck, as in 5-10 times slower than an iPhone.
I recently came across a ridiculous example of a high-end Chinese phone (700$) where one our web app's interactions that normally is near-instant, took 6s instead. Turns out that besides the generic issue of poor JS performance on Android (due to CPU), this particular manufacturer decided to deliver on their ridiculous battery life claims by...running all JS on a low energy CPU core.
Right. As much as people want to complain about Apple forcing WebKit/View on everyone, what it has enabled them to do is build specific hardware level optimizations in for JS and page rendering, which means you can get really good desktop-level performance even with an otherwise limited CPU/battery. Given Chrome's horrendous issues on MacOS, they are going to drain the battery as fast as possible and then blame it on Apple. Chrome users will then blame Apple for bad battery life.
If you can get away with it, it's not a bad option. But it's still early days. If you run into compatibility problems or bugs with libraries being used, you could be in trouble.
I like your confidence but obviously you haven’t released an app in an Asian market. Performance is an issue here since most are using outdated Android phones from average of 5 years ago.
You're right. Just checked it and in some markets like India it's about 90% but globally it's more like 70%.
But yeah my point is that US devs (specially SV devs) tend to be myopic about this as they are using iPhones like most people in their bubble. If you're making an app for the US market then this is probably less of an issue, but for worldwide audience this is a huge issue. Not only with RN but with web apps too.
The scrolling/transitions animations are jittery in the left in the video, it’s a readily identifiable artifact of RN apps in fact, whereas the native one is incredibly smooth in all refresh transitions and scrolls. I wonder how difficult it is for RN to fix this. Just this one singular improvement in UX would be worth its weight in gold.
This is where things get interesting in React Native. The answer is: yes you can have smooth animations. However, the animations have to be driven at the native level and not in JS.
The reason for this is: React Native is on a run loop. And on each loop, new state is shared over a bus from the JS side to the native side. So if you manage the frames of an animation over this bus, it's going to be very slow. If the native side manages the animation, you don't have this overhead.
The same goes for touches. If you touch something, the native side gets the event and then this goes over the bus and RN picks it up. But if RN then responds to that touch by highlighting a view, that means another message has to go back to native - lots of overhead. For that to happen without a perceptible delay you have to have these events handled on the native side.
Another thing that can happen is too many things in the view change at once: you then have a traffic jam on the bus and the UI slows down or becomes unresponsive. This can happen if state changes too quickly.
You can get decent performance out of React Native (especially on tables, which is otherwise a dark art in iOS), but you have to know where the bottlenecks pop up.
The only stutter visible is during page navigation. Initially I even thought the right one would be RN. This is a solved problem in RN itself, with the default animation libraries already doing most of their work off the main JS thread. But it is extremely easy to overload React when all the extra rendering and business logic is put in, and it starts eating away the performance.
The new Fabric architecture is supposed to reduce the native-to-js bridge cost significantly and might make performance on par with native - yet to be seen.
So after three years, they've ported "all four root screens" in React Native?
I can't fathom how broken each of their platform's codebases must have been to require everyone to learn a whole new paradigm to start over from scratch. Further more, they are presumably causing the same code quality issues because "React Native was a completely new tech stack for [their engineers]." So the codebases were so broken that they had to rewrite them and they chose a system that most of them are learning as they go.
As someone who worked on the Shopify iOS and Android codebases, I would argue they weren’t all necessarily so broken. The flagship mobile app (the one primarily discussed in the article) was in good shape on iOS (and arguably better shape on Android). There was some fragmentation in architecture among teams, but overall things were reasonable and I didn’t personally find it difficult to jump into unfamiliar sections of the codebase..
Shopify’s other apps that migrated first were either much older, and therefore had much more tech debt, making the rewrite more enticing, or were much smaller in scope, making the rewrite much faster to get to feature parity. Once all the other apps had migrated or decided to migrate, it made a lot more sense to explore it in the flagship app discussed here.
Some disclaimers, I’m no longer at Shopify, and while I worked in the very early iterations of the port of the flagship app, I wasn’t necessarily a vocal proponent of migrating it to RN. I enjoy RN, but I enjoyed working on the native Shopify apps.
The choice to port to RN wasn't technical at all. Tobi (the CEO) prefers RN philosophically. No technical argument opposed to RN--which is super easy to come up with, along several axes--would have stopped the port. It was inevitable.
This is my opinion, as I watched it unfold. I'm no longer at Shopify.
It seems like the choice to use RN is usually made by the business side rather than engineers. I'm biased because I work as a mobile engineer but I've never heard an engineer emphatically love working with RN. In fact, I've usually heard horror stories about how it works, still having to write platform code, finding the talent that knows how to properly write RN, the fact that it's technically single threaded, etc. But hey, at least the higher ups get to hear "there's one codebase and therefore it's cheaper."
If he's willing to have the business fund it long term then fair enough honestly. But it seems like a weak strategy that isn't playing out well judging by the progress made over the 3 years so far.
Will another 10 years go by and there still won't be a dark mode for the app?
As someone who uses the mobile app basically every day, it is absolutely one of the things that bothers me, every single time I use it. That's not a good thing.
Former Shopify iOS dev here. I pushed SO HARD to get dark mode to be a thing we would do. It's table stakes, IMO, in 2020 and beyond, to support it. We'd get roasted on Twitter, LinkedIn, just about everywhere. HN Comments, even. :)
Got shut down at the highest level. Like, definitively. As in, please don't ask again.
I don't think you'll ever see it as long as Tobi is CEO.
Ugh, i got a bit of pushback on supporting dark mode in my native app, luckily i was starting from scratch and once you show you can pretty much do it by setting up assets correctly and that you can switch modes from the quick menu to test, noone even thinks about it anymore.
They were all coming from a non native mindset though
Ehh ridiculously easy seems like a stretch. You need to adapt all of your designs for dark mode and if you haven’t thought about it in the past or you don’t have a design system that is easily adaptable in the app you are going to be updating a lot of components and screens.
OK, yeah, you need to think about it first, but it should just be a case that all the colours in your design have alternates. It's mostly a case of differentiating between background and foreground colours.
Then you put all your colours in the Assets, only ever used named colours, maybe hardcode some shortcuts, then you never think about it again.
There are a couple of rare cases here and there, eg custom drawing using Core Graphics, where using cgColor won't pick up the change, you have to grab the underlying colour again and force a redraw
The migration tracker is nice. Highly recommended approach for any migration project, incl. data migrations. It not only helps track the progress over time, but also provides great material for status updates. It's a perfect place to redirect stakeholders who have questions on the status or to help reduce their anxiety around progress.
> As we port screens to RN, we also look out for opportunities to improve the UX of the app.
I would be curious to hear more about how this went - in my experience trying to do two things at the same time can lead to trouble, tempting as it may be (was it the migration or the upgrade we did along the way that caused this new bug?).
Having done this, it goes poorly. You create new problems as you go because somehow, to the surprise of everyone, brand new ideas are less fleshed out than vetted ideas. Shocking.
Making technical and functional changes results in an inability to explain A/B tests that attempt to prove that the migration did not have negative effects.
If you change UX as part of the migration, you're often unable to tell whether the cause was technical or functional. It's just too easy to say that it must be the technical side, but you don't have tangible data unless you actually compare the functional changes built on top of the same technical foundation.
Another aspect are behavioral metrics that may change between two implementations making these difficult to compare.
Agreed, you are almost always better off resisting that urge and taking note of things that should be improved as you go, otherwise scope balloons out of control.
Shopify acquired Tictail, a Swedish e-commerce company that had their flagship app written in React Native. They worked on porting Shopify’s Shop app to React Native, with great success. Subsequently, a 12-16 week experiment took place during which a small team explored rewriting one of the larger apps in both Flutter, then React Native. React Native was settled on primarily due to pre-existing knowledge of React and React Native in the company.
Sure but the pixels painted to the screen and the gestures handled by the application code are all the platform’s native UI framework. Knowledge of the underlying platform UI framework is transferable.
In React Native if something is slow or you want to use a recently-released native platform feature you can write a native component. That’s possible with Flutter too, but if you mix Flutter & native views, there’s a bunch of performance issues due to texture copies and thread synchronization.
In the video demo they show a glitch in the iOS screen. For a fraction of a second the Recent Products carousel has height zero and we see the cells from the carousel below (try recording with slo mo camera to see it). An obvious programming error, and yet they chose that for the demo. It doesn’t exactly inspire trust.
Question for mobile devs - how viable is to share code betweeen native android and IOS apps? IE, all the user interface is done natively, but you share business rules, and maybe even an abstract view layer with names of fields, actions etc.
Would you have to write it all in C, as that's the lowest common denominator for stuff that can be used in both swift and kotlin? Or are there other alternatives?
If you want to do code sharing on mobile between android and iOS, Kotlin Native is probably the most viable technology on the market.
Doing some MVVM-style solution where you share the model and view-model layers is probably the type of architecture you would want to go with, having both view layers merely subscribing to an abstract description of the view state living in the view-model and sending up commands to manipulate the view state.
As for being viable - it's certainly doable, but the technology is still a bit rough around the edges, and it's not at all certain that it's going to be worth the effort.
Cpp libs can mostly be used and it’s the strategy we use, the main worry is trying to avoid massive sizes with dependencies up the yazoo in some of them.
I’ll speak from the swift side, it’s improving a lot, but we’re still in a bit of a transitional phase.
With a swift package, you can include cpp libraries but still need an obj-c bridging layer, but afaik swift is becoming better at interoperability, but we maintain a few versions behind swift bleeding edge.
Android are also able to add their own stuff to the repos to make it work. So we basically have a mobile repo that can work for ios and android, pulling in cpp binaries as submodules
You can use C++/C to do this but depending on what you're doing it probably won't save you much time. You could also use JS to share code since both platforms have JS interpreters you can run arbitrary code in - but the ergonomics of this would likely be sup-optimal. For most apps, the vast majority of the work in mobile is the front-end - so sharing code this way would just end up being a headache.
More or less, yes. Because you have more opportunity to maintain state locally on a mobile app (which isn't done as much in browsers), you will see more business logic. But it's largely very similar to web dev. Again though: depends on what you're building and how much you need a remote backend.
No, though i’ll admit it can be easy to get sucked into, bit that’s true for any platform, there are plenty of strategies to avoid this, mvc with uikit and swiftui further improves.
Just setting up test targets can mitigate this kind of thinking
I think Rust is one of the most promising languages for such a shared layer. Can also be used on the web via WASM. This enables native UI with shared business logic.
Kotlin Native is another option that still allows native UI on the iOS side.
No, I meant more as in haven’t tried it myself. Plenty of folks have done similar things with C and C++, I’m not sure if anyone has done it with Rust yet.
Certainly more difficult than Flutter or RN, but if truly native UI is a goal I think it, along with Kotlin Multiplatform, are the best options
Right but say you wanted separate UIs written in the native language for that platform.
Again - not a mobile dev - but my spidey senses tingle when I see "cross platform UI". Feels like it won't go well, that different platforms have different conventions, that the abstraction layer will leak like a sieve, etc.
I still don't get why React Native is so exaggeratedly popular when re-writing code in huge codebases just because it's similar to the React you use in the desktop.. Or just because it's "A single codebase for both platforms". Do people not research into the topic before starting to migrate? People could work with Flutter, which is still cross-platform and outperforms RN in every way possible. It's like having a single Java or Swift codebase for both apps, because it's a well-thought out framework built for mobile natively (On a language capable of compiling to native), not a hacky workaround to have React represent phone UIs (Built on a mixture of languages).
> I still don't get why React Native is so exaggeratedly popular when re-writing code in huge codebases just because it's similar to the React you use in the desktop.
It isn’t popular. It’s talked about way more than it is actually used. 5.3% of mobile applications use React Native. 4.4% of mobile applications released in 2022 use React Native.
Where I'm working we're porting the native apps gradually to SwiftUI on iOS and on Android using Kotlin Compose - addressing a lot of the development speed issues mentioned in the article, and shifting to a 'reactive' model while retaining truly native performance and components.
Developing in SwiftUI is lightning-fast - there are a few bumps and bugs that have been extensively discussed, but it's really simple to still use UIKit components in the places that need them (which are becoming fewer all the time).
For me the tone of the article is very 'positive' but the amount of time and effort seem horrendous. And now they're stuck with React. Not sure how many times these articles need to be written and then... [0]
As a former iOS UIKit dev I actually prefer react native to SwiftUI. If we have to do this declaratively (and I have to re-learn how to do complex layouts) lets also make it platform independent and reusable with Web.
It feels like SwiftUI is being pushed down my throat and I have a strong aversion towards things like that.
Has sharing between the web and RN worked out for you? It seems like it hasn’t for many, or any high profile apps.
Even mobile web and non-web mobile are quite different platforms, even at the UI layer. There are many different expectations, platform norms, and interaction differences that don’t work well in browsers or across platforms. I’d love to seen an example of it working well but I haven’t yet.
Honestly I havent tried much sharing with web but I can at least vouch for sharing between iOS and Android which seems to work mostly. In a few years time I think it will become much more easy and bulletproof than it is now. Making two different apps in SwiftUI and Jetpack Compose seems overkill already.
I remember component sharing being a topic on day 1 with react native. I also remember it coming up a lot about 5 years ago when MS launched a component library that theoretically did this (didn’t seem to take off). I’m skeptical of the approach given that so much time has passed, with so much incentive, and it still hasn’t happened.
Building both SwiftUI and Jetpack Compose apps is definitely a ton of work, but I think the right choice at scale. Before “scale” is “achieved”, I’d advocate for doing one platform well (there’s often an obviously more important one) and packaging the web PWA for the other platform.
True at scale it makes perfect sense to do that. Its just not a very lean (2 different codebases for 2 platforms) and maintainable solution (apple and google keep changing how they do things and kick out apps that dont follow suit)
They seem really happy with their “We all get shit done, ship fast, and learn” progress, but I’m sure I’m not the only one reading this article and coming away less likely to choose to migrate to React Native, right? This does not sound compelling at all.