In this episode, Mazen Chami sits down with Mustafa Ali (Director of Engineering and Head of Mobile at Shopify) and Thiago Magalhães (Staff Software Developer at Shopify) to dive deep into Shopify’s transition to the new React Native architecture.
Show Notes
Connect With Us!
This episode is brought to you by Infinite Red!
Infinite Red is an expert React Native consultancy located in the USA. With nearly a decade of React Native experience and deep roots in the React Native community (hosts of Chain React and the React Native Newsletter, core React Native contributors, creators of Ignite and Reactotron, and much, much more), Infinite Red is the best choice for helping you build and deploy your next React Native app.
Todd Werth:
Welcome back to React Native Radio Podcast, brought to you by the new architecture, not to be confused with the old new architecture, which is now old, but the new architecture, which we refer to as architecture is new. Try it today. It's double Plus. Good. Episode 3 46. Shopify's transition to the New Architecture.
Mazen Chami:
Welcome back, react Native Radio fans. I'm here alone today, but I have two very cool guests with me here. We're going to talk about some cool stuff that Shopify is doing right now in React native. I'm Zen. This is React Native Radio. Ali, welcome to the show. I think for our guests, r and r 3 1 9 Shopify goes full throttle on React native. Your voice might sound familiar to some of our guests. From that, can you introduce yourself?
Mustafa Ali:
Sure. My name is Mustafa Ali. I'm a director of engineering and co-head of Mobile at Shopify. I lead engineering for our main app, Shopify Mobile and also responsible for mobile foundations, tooling and AppSec for all mobile apps at Shopify.
Mazen Chami:
And also on this episode with us we have Tiago Les. I don't think I got that last name right, but I tried. Sorry. Welcome to the show, Tiago.
Thiago Magalhaes:
Thank you. Thank you. So my name is Thiago Magalhaes. I come from Brazil as you can maybe tell for my name. I'm based in Montreal. I work for Shopify for the past three years. I'm a staff developer at the Shopify mobile app. Same app as Mustafa mentioned.
Mazen Chami:
Awesome. Yeah, welcome. Thanks for coming onto the show. Before we get into our topic, let's hear from our sponsor. Infinite Red is a premier React native consultancy located fully remote in the us. We're a team of 30 senior plus level React native developers and support staff and have been doing this for nearly a decade. If you're looking for React native expertise for your next project, hit us up at Infinite Red slash Radio. Don't forget to mention that you heard about us through the React Native Radio podcast. Okay, let's get into our topic. Topic is Shopify's transition to the architecture with Tiago. Notice how I dropped a word from that title. I think everyone's like, oh, what architecture? The new architecture. It's no longer the new architecture. I'm trying to get that to stick. It's no longer new architecture. It's the architecture or the legacy architecture. So I guess let's kind of start off big picture. Let's set the stage to kick things off for us. What motivated Shopify to invest in the new architecture or what we're calling the architecture? What problems were you seeing in the old setup that prompted this migration?
Mustafa Ali:
Sure. So as you may have heard, Shopify decided to go all in on React native back in 2020. And since then we've migrated all of our apps to React native. And one of the main principles for us from the start was that we not want to just consume React native as a technology. We also wanted to contribute back and also help push it forward. The new architecture is a major step in the evolution of React native. So the question for us was not whether or not we should adopt the architecture, but when we should do it. So we were tracking the development closely and we tested it several times after it came out and we decided to hold off until earlier this year when we thought it was close to being ready for our apps. And then we decided to start migrating and we finished it recently as we shared not too long ago.
Mazen Chami:
And you're talking about the article that I believe Tiago was the author of, which we will link in the show notes. And this conversation is kind of loosely based off of that article that I had read prior to this show. So were you actually seeing any, I don't want to say problems or issues with the old architecture or was this just more of adopting the new and continuing to push forward with the React native ecosystem?
Mustafa Ali:
It was mostly the latter. So when we migrate all our apps to React native, we solved a whole bunch of challenges along the way and then we got to a stage we were very happy with our apps. This was mostly an initiative to stay current with what's happening in the React native ecosystem and also help land the new architecture at our scale because a bunch of issues that we encountered that we can get into in some time, we noticed that after releasing the new architecture and when our users started using the app, so we also wanted to highlight, surface those problems that other app devs may not have run into and then help fix them so that everybody benefits from it.
Mazen Chami:
Yeah, and like you said, we will get to those issues that you experienced a little bit later as you were scoping out this initiative that you mentioned. Did you have some non-negotiable goals that you set in place to help direct your vision to landing this new architecture?
Mustafa Ali:
Yeah, there were a few. So the main one for us that we did not want to drop everything else and then do this migration, we had a full roadmap of features to ship and we not want to delay any of that. We wanted to migrate this alongside building and shipping new features for our users. So that was a key principle for us from the start. The other one was that we wanted to make this change mostly transparent to our users. This is a big change under the hood actually quite a lot of work. But for actual end users, we wanted it to be a know up of source, like the app would just continue working as it was before, ideally better than what it was before. That was our goal. So the whole approach to this migration was around these two principles. How do we keep shipping new features while we migrate? And also how do we make sure that performance, stability and developer experience remains the same or gets better but doesn't regress.
Mazen Chami:
Awesome. And to our listeners, spoiler, Mustaf was here talking to us about it at this stage. It was successful and sure all those were accomplished along the ways and that's also a testament to how far the React native team, not just the team at Meta, but the whole ecosystem, including yourselves at Shopify, have come in making sure that this is ready for the big stage and at your scale it kind of proves that any scale, whether it's enterprise or even just small mom and pop shop can kind of do this. Awesome. So you've made the decision and you talked about what your non-negotiables were. Now let's talk about how you actually did pull this off and something that you went through. So I assume you were supporting both old and new architecture side by side and that sounds very complex. How were you able to make the two coexist within each other? Two completely different engines underneath the hood?
Thiago Magalhaes:
So yeah, I can take this one. So as you know, there's flash lists, right? It's a library that was developed by Shopify and it powers pretty much throw a number. 90% of our app is flash list pretty much. So it is a pretty simple goal if you bring flash lists to the new architecture, then you have the majority of your app working with the new architecture. So that was one of the pillars that we needed to tackle first. As for conditional code between the app, what works on the new architecture, what works on the old architecture in the reality there is not that much. I think there is a lot of, there's a lot of mystery about what the new architecture is going to break or not break in your app. It turns out it's not that complicated. Meta did a pretty good job of creating interop layers between for old native modules as I like to call them today, instead of terrible modules.
So there is a pretty good backwards compatibility, but flashlights was the main focus of that because the majority of the changes of the new architecture, at least from my perspective, is the layout fabric itself, like the layout mechanism. So that would have pretty big consequences to the way flash list was developed before, which was totally on the old architecture. So it's mainly working on flash lists, bringing it up to speed with the new architecture, patching parts of our code so that pieces of it that would not work with the new architecture were either we just put a conditional code to block it from executing while we're developing so that we can have an app that functions on both architecture is, although not optimally on the new one, and we go from there doing incremental bug fixes and shipping things to Maine without disrupting the day-to-day development.
And one of the other, we're probably going to talk about this in the article, but Top Hat was a huge part of this. So for those who don't know, top Hat is our, call it our, it's not a testing tool, but it's pretty much like the blood that runs into how we do things in mobile or Shopify. So as a developer in Shopify, when you're developing new features, you create a pull request and then you have this bot that will comment out on your pull request with link to the iOS app and the Android app based on the PR that you just submitted. And people can just one click install that on their simulators or devices or whatever and test it right away with having to check out your branch and build and all of those things to slow us down. So we leveraged Top hat for that. And the way we did this is basically may top hat emit instead of one build for Android and one build for Android iOS, it emits two builds, one of the new architecture, one of the old architecture for both platforms. So mostly people who are working on the new architecture could just go into any random pull request that we wanted to test it and just grab that version and see how is that working on the architecture. That's how we maintain it. It's a broad overview of how we maintain it
Mazen Chami:
Natural. That's very complex, right? Because two ecosystems, and I want to let our mention to our listeners top hat, if you're in the expo ecosystem, it's probably Expo orbit is the equivalent. Now Expo Orbit, you can't necessarily do custom builds, right? And I think you all can tell me where the differences lie between the two. I'm sure there's some differences. Is Top Hat available open source for anyone to use?
Mustafa Ali:
Yeah, it's open source. And actually fun fact Orbit was inspired by Top Hat. Oh there you go.
Mazen Chami:
In this article you mentioned how you kept up to date with React Native Core updates because maybe you realized some issues may have been fixed upstream or whatnot. As consultants, this is something that we usually have these conversations with our client all the time and we tend to see teams missing the point of why to stay up to date, right? It's almost like why am I going to update to the latest version? There's going to be some breaking change and going to have to do regression testing and then it kind of snowballs from there essentially. Is there anything you all want to stress about that point to any of our listeners that are looking at it from that perspective? Why always update
Mustafa Ali:
Many of the big bug fixes go into the next version of React Native usually and sometimes they get back ported to older versions. So if you are encountering an issue, unless that bug fix has been back ported, you don't have too many options apart from migrating to the new version of React native. Now understand that there's a certain level of investment that's involved in it, but think of it this way, when you have third party dependencies in your app, when a new version comes out, it has some bug fixes and performance improvements and new features, it's usually not a big deal to upgrade to that new version, but it's the main framework itself. People are sometimes hesitant and that's understandable, but there's a trade off here. Do you want to spend time trying to find workarounds for bugs that have already been fixed in a new version or do you just want to move to a new version and not deal with those issues anymore? So I think it's not a yes or no answer, it's a set of trade-offs that you have to make. One thing that helps is talking to other teams who are also using React native and they usually we get to hear from other folks who have encountered similar issues before and they can confirm that like yes, this has been resolved for them. So we have higher confidence that the investment we have to make to move to the next version is worthwhile.
Thiago Magalhaes:
Yes. And adding to this very good point during development, during the migration to the new architecture, there were many, many problems that we encountered that we frankly spent weeks trying to figure out what was happening from clicking on certain buttons, not resulting in any actions and why is that not happening? And you start debugging the internals of React Native to try to find out what happened. It turns out this was already fixed on the version that was up for a couple of months and we were just behind, right? So that's one of the things that if I could go back in time and redo this project, I would probably ensure that wasn't the latest React native version before I even started analyzing what was breaking and what was not. And in some cases we found fixes and before we migrated to the new version to upgrade it to a new version of React native and then we had to undo those because it turns out they were fixed upstream in a much better way. So I think especially when you're dealing with React native, which is probably the biggest dependency on the React native project, obviously I think you should try to stay current with it as much as
Mazen Chami:
Possible. Okay, so you're saying adopt the latest version of React native over 20 patch packages makes sense. I could get behind that. Absolutely. Alright, so let's kind of dig in a little bit into some of the issues that you may have run into during the migration itself and how you may have solved them, lessons you may have learned from there. I want to kind of highlight one specifically and you all can kind of share other examples from the article You mentioned one of the trickiest issues was around batch states updates, breaking time sensitive logic. We talk about how many set states can I put on my click event, which one fires first? How does that happen and how does that affect my app? Can you share that, how you solve that specific example and potentially any other examples you want to get into that would be helpful to our listeners?
Thiago Magalhaes:
Sure. So as you may imagine, Shopify mobile is a pretty big app and there is many dependencies in this. And so we didn't see this issue spread out throughout the app. There were very particular situations where this was happening. I can recall one which we still have a couple of native components that we have. We build in the app for specific user interactions that we want and those were being managed by view managers on the old architecture. So there's kind of a disconnect between the React native fabric tree, if I may call it this way, and the native view tree. And this component was essentially a sheet that would pop from below and you would click on a button and it would navigate to another component. And we realized at some point that this action wasn't quite working. In some cases it never navigated. In some cases it just navigated to the same previous component we showed and then navigated to the other one.
It's like a very weird interpolation of states. So one thing we looked at was we started to debug this and we started to notice that that component had an intermediate state that it was designed around an intermediate state which would trigger a side effect, which would be this navigation. And we realized that this intermediate state wasn't showing up on the logs pretty much. So we quickly realized that this is probably an optimization that React native is doing and rightfully so because that intermediate state was maybe not the best way to codify how you want this component to behave. So the fix was mostly let's rethink the state management of this screen, right? Let's create a bit more deterministic states. Let's wait for certain operations to happen before we move to the next state. So when we're a bit more intentional about the state management on that component, react native is able to optimize it without breaking it, if that makes sense.
So this is one of the examples I found. I don't think, like I said, I don't think this is a widespread issue where state bashing is going to break your components per se, but assumptions have changed on the new architecture as to how the state management will behave and I guess it's more of a recommendation if you start seeing weird behavior like that. Looking at the state management is probably a good idea to try to understand if you're being affected by the state batching because maybe you didn't do state, I put it in quotes like the correct way or in a way that only worked on the old architecture, we're been all guilty of this as part of development.
Mazen Chami:
Yeah, I mean I think when new architecture was initially announced and it was like, oh we're going to adopt, I believe, I can't remember what specific version of react it was. The benefit of this is you can do two to three set states right next to each other and only one re-render will trigger, right? It was true in some cases and that was the objective at the end of the day and I think now we're probably closer to that, but back then I remember seeing variable results from it and seeing on Discord that wasn't necessarily the case there, so Awesome. Now one thing that I think a lot of our listeners might benefit from, I think I would be interested in also hearing about is how did you all benchmark tricky things like time to interaction because that I think is a very important aspect of an app, that user experience, you don't want to user to know you're building your app and JavaScript at the end of the day, they want that native feel. So did you benchmark your TTI and make sure you weren't regressing? Did you use any specific tools?
Mustafa Ali:
Yeah, we've invested quite a lot in this area over the years. In fact, that was thing one of the main things we focused on when we switched from Lin and Swift to React native. So we have performance markers for all the screens in the app and we emit them to an observability tool where we track how our app is performing in production. When it comes to this migration, there are a bunch of things that we did before release and after release. So before we ship this, we have an automated end-to-end test suite that runs the app and collects TTI numbers and then we can compare that to the baseline. So what we did was we had baselines for the legacy architecture, we run the suite, we compare that with the numbers on the new architecture and see where the deltas were. In some cases it was faster, some cases it was slower.
So then for those cases we investigated what was going on and implemented optimizations now that we do for every release essentially. So we ship on a weekly basis. So regardless of old or new architecture, we just do that. So that helped quite a lot After release, like I mentioned, we collect a ton of performance data and then we notice we look at trends essentially and then try to figure out what is actually happening in production and then we have alerts associated with these. So if we have internal targets for what the TTI should be and then if it exceeds that TT I across our user base, then alert gets fired, people are on call, investigate, release a fix and we go from there.
Mazen Chami:
Yeah, that's awesome. And I kind of want to mention, bring out the stat that you all have in your article app launch times improved by about 10% on Android and 3% on iOS. 3% might seem very small, but in the grand scheme of things, that's pretty big. And again, as a developer that's worked on these type of migrations, that 3% does not directly correlate to the amount of work that went into that 3%, right? It's a lot that 3% of time that was improved but probably 120% of your actual time to get there and energy. So yeah, I get that. Congrats on that. I think that's pretty cool that your numbers are all much better from where there was before. One thing I want to touch on earlier that you all mentioned was Flash List V two. Shout out to NVI for that work. I know it's something that we've used in our Ignite boilerplate app and we've seen a lot of performance improvements from that and today there's a lot of different packages out there to use, so a lot to choose from. Cool. So kind of done a little bit of a technical deep dive. Let's talk about the future impact that you all have. So now that you're fully on the new architecture, does this unblock you to build features that you weren't able to in the past?
Thiago Magalhaes:
Oh, it doesn't necessarily unblock us for building it. I think React native was is very capable on both architectures for building pretty much anything, but it does allow us to explore more interesting developer experience or even user experience in terms of performance gains that we might have. I think the biggest thing in my opinion is the synchronous layout. And so before you have the situation where you have to wait for something to be laid out so you can get layout numbers and then you can resize something. So the layout cycle becomes this jello almost where your UI is adapting to what's happening little by little and well the new architecture, that's what we could see with flash list too is that you can get all of these values in one shot, like for instance flash list eliminated estimated sizes just by leveraging the synchronous layout capabilities of fabric. So that will certainly allow us to build more interesting user experiences. Pretty excited to see what kind of animation and work we can do with that. And from a developer perspective, turbo modules, they eliminate a lot of asynchronous code that you would otherwise have in your app. So that makes components much easier to deal with in my opinion. You don't have to create hooks to abstract AY operations, you can just straight up just call the native module and get the value if you want. So personally and selfishly I'm pretty excited by that part. But
Mazen Chami:
No, I mean that's a big one that eliminates the wait time to go back. You never necessarily know what's going to happen with the bridge, the UI thread, the JS one thread is probably locked up, right? Let's be honest
Thiago Magalhaes:
Here.
Mazen Chami:
But with the ability now with fabric and ability to just kind of go in, get your value, come back, absolutely. Great developer experience there. I totally agree with you. So I think most offa, you mentioned that you had a tool where you were looking at and comparing the deltas between old architecture and new architecture and making sure you have that. So now that you're fully on the new architecture, I assume you're still tracking those stats and making sure those deltas stay steady or continue to improve. Right. And do you have any other systems in place to catch regressions, whether it's visual also?
Mustafa Ali:
Yeah, so we track performance numbers on an ongoing performance work is never done because you can improve, you can have a performance issue, your app you can improve, you can fix it, but then at the same time you're also shipping a bunch of new features and changes have this annoying habit of also very randomly when you least expect it bring down performance of your app. So it has to be something you have to do on an ongoing basis. Apart from that, we do a bunch of other things. Screenshot testing is a big one. So we have a very comprehensive screenshot test suite that we run for our app. The Shopify mobile app is pretty massive, like hundreds of screens and you can manually go and check if anything is broken in each of those screens. It's just not ly possible at this point. So we have an internal library that we build that basically generate screenshots on the fly and then compares them with the baseline and if something has changed in a way that we don't want to, it flags us so that we can fix it quickly. So that saves us a ton of time.
Mazen Chami:
Nice, nice. Cool. So here's a question I think I'd like each of you to help answer for us. If another company, so Mustafa, if another developer Tiago is looking at doing this migration, what should they watch out for?
Thiago Magalhaes:
Yeah, I have a few recommendations myself and bit of a fun story I cited, I mentioned that the blank screen of Dom in the article, which first time I ran the app into the new architecture, you switch the flags and you build it, then we get a blank screen absolutely no logs, no anything
Mazen Chami:
Isn't that fun
Thiago Magalhaes:
Except that this will probably happen. So it's fine. What I would say is that 90% of our cases, this was due to a native module that was doing something that the new architecture wasn't happy about. So I think it is like try to find the culprits on your code for these issues. I would say native modules, that's something you need to scrutinize. I think you need to add logging, very thorough logging before you start the migration for the new architecture. So exactly what's happening in your app during development so that you can quickly find what's blocking the rest of the app from rendering. That's the first thing I would say. The other thing which I mentioned on another talking point was the state batching aspect of it. If you know that there is a component that you have a tech debt that you never paid, you should probably pay the tech debt now or put that into consideration as you migrate.
There's a very high chance that it will bite you later because if you're hacking state in a way that worked on the previous architecture and if the piece of code that you think is questionable and it's questionable, but you left it there because working anyway, it is probably going to stop working. So it's another point of investigation that you want to do. I think again, performance is paramount. You should be profiling your performance and keeping track of regressions even if you're not going to do anything about it. Just capture those numbers, keep those numbers handy, have a history of what's my app, faster or slower in this period of time. It's extremely important, especially with a large change like the new architecture. I think those would be my top three recommendations.
Mustafa Ali:
Sfa? Yeah, the main thing I would recommend is don't wait too long to start. Meta has already announced that they're going to drop support for legacy architecture in the next major release. So I think time to migrate to the new architecture is now the longer you delete it, the more painful it'll get. The other thing I would say is test as much as possible internally, but also be prepared to encounter unexpected issues when you start rolling out. We did a lot of testing internally, but then some crashes we only found when we actually started shipping to production. So we've covered this in the article as well, but we were very deliberate about how we rolled out this change to our user base. So we started very slow, monitored things very closely. As we found unexpected issues, we started fixing them and then rolled it out more broadly to our user base. So we prepared for that and as long as you have good monitoring in place, you can catch those things, ship fixes and then move forward with the rollout.
Mazen Chami:
Yeah, thanks for highlighting that. I think, I hope no one is starting their migration journey. There's a lot that goes into that journey. First is just even having that conversation. I hope no one is at that stage at this point because like you said, meta has announced it a lot and at the time of this recording, RC five for version 82 was released, I believe it was released this morning. And I love the note that it has and I'm going to read it out loud, crash the app if they force the legacy architecture. So there you go. I mean if Meta is not sending you a big enough sign at this point, and like we mentioned earlier, try and stay on the latest version because that latest version probably has a solution that you're looking for for your bug. So new architecture is the solution, and I think I've mentioned this on the podcast before, if you find the package that you're running into issues that's not new architecture compatible, which I believe is very rare these days. I haven't heard of any at this point, but if you do find an outlier, please reach out and we'll raise it up with meta Shopify, whoever the maintainer is in expo has been doing a lot too in that field and helping there. So. Awesome. I kind of want to ask two more here. If you could start this migration journey again, knowing what you know would do anything differently
Thiago Magalhaes:
Without going back in time and cheating, knowing exactly what line of code I need to fix. I would say the logging part, adding logs everywhere. Another thing that I would probably do is increase our end-to-end testing coverage. So one of the guardrails we have in our app is we have a pretty thorough end-to-end test coverage, which will test features from the app almost as a whole, but there's small edge cases that are not really capturing this task. They're expensive tasks, they're hard to maintain. That's not, you don't necessarily need to cover everything in this task, but we could have covered that situation where that component, where I mentioned where you click on it and the action is not happening, we could have built a unit, sorry, an end-to-end test for that ahead of time and we would have a pretty big list of bugs before we even started to find those, right. So I think that would be good. It would not eliminate the problems you solve when you release, because especially at scale, there will be a few crashes here and there that you need to tweak.
Mazen Chami:
One thing I always tell my clients here is if a ticket is coming in as a bug, make sure we as the developers on the app, the app is in production, it's in the store being used by users right now. If a bug ticket comes in, we're going to make sure that either a unit test, depending on what type of bug a unit test or an end-to-end test is being put in place so that this bug doesn't rear its head again, that we save ourselves down the line. If for some reason we find an issue with React native screen, so with new architecture down the line, we're able to capture it early so we can mitigate it as soon as we go that way. Alright, so I think I want to ask a final question here before we sign off. What excites you the most about the future of React Native now that you're on this new architecture?
Mustafa Ali:
It feels like a new chapter in the story of React native. We've been talking about the new architecture for a long time, so we're very happy to just move to the other side, get the migration done successfully. We're pretty happy with how it went, and we can now start leveraging all the new features in React Native. That meta is shipping also, I'm very excited personally about everything that's happening in the React native community. Literally every single day there are new libraries that unlock new capabilities in React native. I'm constantly blown away by the experiences that people are building with libraries like React native Skia. It's really good to see. I think a few of them also got nominated for the app store design award in the Google Play Award. That was really, I was very happy to see that. So the future is right. We are very happy with where things are going and we want to continue contributing back and helping others build great apps as well.
Mazen Chami:
Yeah, that's amazing. Yeah, great call out there. And again, thank you Mustafa, Tiago and everyone really at Shopify for what you all are doing for the React native community. And thank you for coming on the episode with me. I really appreciate it. And yeah, it have a great day everyone. Bye.
Jed Bartausky:
As always, thanks to our editor, Todd Werth, our assistant editors, Jed Bartausky and Tyler Williams, our marketing and episode release coordinator, Justin Huskey and our guest coordinator, Mazen Chami. Our producers and hosts are Jamon Holmgren, Robin Heinze and Mazen Chami. Thanks to our sponsor, Infinite Red. Check us out at infinite.red/radio. A special thanks to all of you listening today. Make sure to subscribe to React Native Radio on all the major podcasting platforms.
There’s no perfect time to get started. Whether you have a formal proposal or a few napkin sketches, we’re always happy to chat about your project at any stage of the process.
Schedule a call