Prologue
“a poor craftsman blames his tools” - Idiom
While I think a poor craftsman blames his tools, it’s not lost on me that a poor craftsman chooses bad tools, I don’t think React Native was a bad choice given the historical context of a small team having to support multiple platforms and given the options available at the time.
The tech stack for an alternate client or Status 2 is certainly open for discussion, as in the heated discussion (React-Native vs native mobile app) , but not the point of this post.
I want to question the ‘React Native is Slow’ meme that is spreading within the organisation. This meme is harmful, as I believe most developers are using this as a heuristic rather than using critical thinking to solve problems. Based on my last call with design, the meme has now also spread to designers, which is now prematurely limiting their design decisions and preventing Status from being even more visually stunning.
Historical Context
tldr: skip to Status’ UI Performance
It’s no secret, but yes, at one stage of my life, I was blessed with the curse of being a Flash Developer. I wrote the first ever Inverse Kinematic Bone Tool system for Adobe Flash MX 2004 before it became a defacto tool, I moved onto Flash Develop where I wrote and contributed to 3D Engines for Flash where we could push for 60-120 FPS. I also used to write in FLASM, AVM and AGAL to push Flash to its very limits. Writing exploits was also kind of fun at the time. Eventually lead me to Haxe which was adopting ECMAScript language features that was way ahead of its time, compared to javascript.
This was all before 2009, back when Internet Explorer 6 was a thing.
Why do I mention this?
Because in 2009 there was a meme that built up around Flash saying it was bad, slow and non-performant. The final nail in the coffin was Steve Jobs infamous post. Now I’m not objecting that this is a truism, but Flash let you do some amazing stuff that couldn’t be done in-browser otherwise, and if you took the time to wield it, it was an amazingly performant tool.
While the tool is partly to blame, the bigger problem was the usage of Flash, the problem with tools that lower the barrier to entry is you get a bunch of low-tier developers flooding into the space.
Everyone was looking to HTML5 as the Flash Killer, which of course is what the developer base migrated to, leading to articles like Electron is flash for the desktop a few years later. Hmmmmm!
The more modern the application development tool, the higher the abstractions and the worse it seems to be, there seems to be a trend of software bloat matching the resources of the time, I guess the argument is we trade-off developer productivity. I personally would like to go the other way which is why the Nim+<GUI> approach is interesting. The language gives you pythonish developer productivity and it’s closer to the metal. Okay yeah Nim’s community & library support is lacking which might make it a bad choice. Anyway I digress.
The point is, this persisting meme is blaming the tools, but really it’s a reflection of ourselves. We have alot of talented people in Status and I think we can do better.
Status’ UI Performance
It’s no secret that Status is slow, it’s getting better, but this ‘React Native is Slow’ meme serves as a crutch that acts more like a hindrance, mentally preventing critical thought into our code’s behaviour.
Our UI is not so complex, so it should be a real concern to everyone involved that it’s not performing well.
I looked into this awhile back and it became very obvious that we haven’t done everything to make Status performant, I would like to revisit it.
5 min search, found some helpful links on how to look at performance within React Native.
https://medium.com/@tonyfaieta/android-optimization-in-react-native-bda1b5f25277
https://launchdrawer.com/i-made-react-native-fast-you-can-too-9e61c951ce0
and Profiling Android UI Performance for React Native , which isn’t loading a preview for some reason.
Overdraws
Overdraws basically see how many times you are drawing a pixel every frame, if you write the same pixel more than twice a frame it’s considered bad (I’d say more than once is bad imo)
If you’re on Android this is easy to see:
- Enable Developer Options (go into About and tap build number 6+ time or something)
- Settings > System > Developer Options > Debug GPU Draw = Show Overdraw Areas
- Open Status
- Blame React Native for being slow.
For your reference here is the colour chart:
Here is two screens of Pinterests Topic Chooser, a screen they claim is 100% in React Native on all platforms. One is Static and One is me Scrolling.
and here is Skype, which is also in React Native (although to be fair it might be in Microsoft’s variant now)
I found it interesting that the Skype login Webview overdraws are high, but the login screen and list itself isn’t, even when scrolling.
Now here is Status:
The Splash Screen is Native, the spinner and the rest is React Native afaik, it seems to me Status renders it’s entire screen more than 4 times, every frame. This isn’t React Native, this is our code. If we reduced this to under 2x overdraws we would likely see a 2x performance increase app-wide. If down to 1 would we get a 4x performance boost?
I’m not sure if this is a symptom of re-frame or some other library we use, I speculate there’s something wrong in one of our parent dom nodes (my guess is a use of transparency (???)). We need to identify the root cause of this and fix it.
Using console.log
statements
So Facebook recommends to include the babel plugin transform-remove-console
to strip the codebase of console.log statements as it seems to hinder performance, I don’t think we do this but I guess Closure or some other transpiler does this already for release builds?
Flatlist
Looks like we already use this which is great!
Static Animations & useNativeDriver: true ?
The Animated API currently calculates each keyframe on-demand on the JavaScript thread unless you set
useNativeDriver: true
, while LayoutAnimation leverages Core Animation and is unaffected by JS thread and main thread frame drops
I couldn’t find any references of using this in status-react, is there anywhere that makes sense for us to utilize this?
shouldRasterizeIOS
or renderToHardwareTextureAndroid
Moving a view on the screen (scrolling, translating, rotating) drops UI thread FPS. This is especially true when you have text with a transparent background positioned on top of an image, or any other situation where alpha compositing would be required to re-draw the view on each frame. You will find that enabling
shouldRasterizeIOS
orrenderToHardwareTextureAndroid
can help with this significantly.
I couldn’t find references to this either in our codebase, I’m not sure if the reason we don’t have the screens sliding is because it was unperformant. But maybe this could help if we decide to reintroduce it, it might also help with any transparency used in the application
Battery Consumption
We seem to be running the node in the background on Android, but not on iOS, afaik we are not taking full advantage of this, so can we improve battery life (and prevent the battery warnings) by not running the node in Background on Android?
Push Notifications to Chat Screen
The flow between tapping a push notification and landing in chat is pretty bad, it takes about 10-15 seconds to land in chat and have it’s history populate, feels very similar to the now resolved slow sign-in.
Fin’
Anyway, I’m not that familiar with our codebase, or how to squeeze the performance out of React Native, but it seems like the overdraw’s are definitely an issue, and there’s probably more we could be doing.
I hope we can make a more concerted effort to making Status as snappy and responsive as any other application. And once we have, and the UI performance still sucks, then our trash talk about React Native is justified and I’ll happily jump on the bandwagon.
If this is something we can’t solve, would love to know the reasoning.