Preface
In 2018, Airbnb gave up continuing to use React Native, mainly for two reasons:
-
Technical: Maturity, supporting facilities/library construction costs, first-screen performance shortcomings, etc. were not well resolved
-
Team organization: High engineer requirements, cross-technology stack/cross-team debugging/testing, etc. also created new problems
In fact, the problems encountered by cross-platform solutions are far more than these, sometimes Write Once, Run Everywhere is just a beautiful vision
1. Technical Dilemma
In a word, before touching the capability boundary, everything in cross-platform solutions is beautiful
Taking React Native as an example:

The Bridge layer connects the JavaScript world with the Native world through message communication
Shadow Tree is used to define UI effects and interaction functions, Native Modules provide Native capabilities (such as Bluetooth), and the two communicate with each other through JSON messages
P.S. The diagram is somewhat old, but doesn't affect understanding the principle, see React Native Architecture Evolution for updated React Native architecture diagram
In such a technical architecture, what's written and actually executed is JavaScript, calling view rendering capabilities and platform-specific capabilities provided by Native, Facebook calls this Scripting native solution, let's call it Containerized Native Cross-Platform Solution:
Transform Native App into a standardized container, thereby allowing one set of code to run across multiple standard containers, such as React Native/Weex, Flutter
(From Changes and Invariants Under Mobile Cross-Platform Technology)
Container capabilities largely determine development efficiency, within the scope of consistent standard support provided by the container, one person can happily handle multiple platforms. However, once the capability boundary is touched, it will face high-cost multi-layer joint development (Native layer, JavaScript engine layer, specific business domain layer, business layer...), there's no advantage in human efficiency. On the other hand, how to maintain multi-platform consistency is also an extremely complex and technically challenging problem
In addition, related supporting capabilities also directly affect development efficiency:
-
Debugging: Cross-technology stack debugging has always been a difficult problem, problem troubleshooting costs are getting higher
-
Performance: Cross-thread, cross-page time-consuming analysis is difficult, performance toolchain is missing
-
Engineering chain: Due to the particularity of technical solutions, many supporting facilities need to be tailored (including but not limited to IDE, debugging, performance, CI/CD, monitoring) to reduce costs in all links
In general, the biggest technical dilemma lies in:
-
Multi-platform differences that cannot be smoothed out
-
JavaScript engine cover that cannot be lifted
-
Supporting capabilities that cannot keep up
Multi-platform consistency is almost a bottomless pit in technical investment, underlying platform architecture differences (UI rendering methods, event mechanisms, system APIs) are deeply rooted, with the current maturity of various cross-platform solutions only covering a very limited part, leaving a very large blank that needs to be filled by extending container capabilities, including general basic capabilities (such as UI, interaction), and specific capabilities oriented to business domains (such as multimedia, positioning)
Introducing JavaScript engine, although gaining the ability to dynamically execute code, also brings technical uncertainty, almost impossible to track and solve crashes or abnormal behaviors inside the JavaScript engine
Most general infrastructure cannot be directly used in cross-platform scenarios, every corner of supporting capabilities needs effort to build, and to meet rapid business growth, core key capabilities are always prioritized for construction, supporting support is usually lagging, also affecting efficiency
Can Flutter Bring Some Differences?
In fact, Flutter (as it currently appears) also faces these technical dilemmas, changes in technical implementation have not completely changed the situation
According to 2020 Q1 survey results, Flutter developers believe the 6 most important problems are:
-
Debugging errors and crashes
-
Testing to ensure App can run across multiple platforms
-
Choosing state management solution
-
Understanding and handling layout problems (such as text overflow)
-
Creating UI according to design drafts
-
Troubleshooting specific platform problems
At the same time, the 6 most difficult problems are:
-
Troubleshooting specific platform problems
-
Diagnosis and repair of memory problems
-
Diagnosis and repair of CPU usage problems
-
Accessing existing Native APIs
-
Diagnosis and repair of UI stuttering problems
-
Developing Flutter plugins for specific platforms
Therefore, the pain of debugging and performance in cross-platform solutions continues in Flutter, the dilemma of multi-platform differences and supporting capabilities has not changed
2. Team Organization Dilemma
Compared with single-platform development mode, cross-platform solutions have higher collaboration costs, reflected in:
-
Cross-team
-
Long chain
-
High pressure on container team
-
Unclear responsibility boundaries
Under cross-platform solutions, cross-team collaboration has become the main collaboration method, requirement briefing, development, joint debugging, problem troubleshooting and other links all require cross-team communication/collaboration, communication costs cannot be ignored
Long chain means technical details are scattered across multiple layers, each only owns a small part of knowledge:
Surface business logic
-----------------------------
Specific business domain framework
-----------------------------
General frontend framework/library
-----------------------------
JavaScript engine (extension)
-----------------------------
Native Module | Specific business domain capabilities
-----------------------------
Native general framework
-----------------------------
Native View
-----------------------------
Platform operating system
Since each team can't see the full picture, every problem whose cause is not so obvious needs to be investigated layer by layer downward, even parts involving specific business domain capabilities are divided into many layers...
On the other hand, so many layers also cause complexity accumulation, the lower the layer, the higher the complexity, because the more uncertain variable inputs, the harder it is to understand the ins and outs, and the higher the cost of troubleshooting problems
Ideally, filter layer by layer according to funnel model, each layer only needs to check its own input and output, but lagging supporting capabilities make it difficult for surface business to identify the scope of problems, so container team becomes the filter valve for problem flow, connecting numerous JavaScript businesses above and complex specific domain capabilities below, a lot of time is spent on figuring out the ins and outs, container capability expansion is forced to slow down, repeatedly troubleshooting known problems...
From business perspective, the division of responsibilities for layers below business is not very clear, so it's easy to find the wrong layer/person, producing invalid "redirection". And the container layer also doesn't have a panoramic view, problem flow trajectory becomes quite tortuous, communication costs are filled in all links, constraining development efficiency
3. Individual Dilemma
For individuals, the biggest difficulty faced is cross-platform solutions have some differences from Web standards, and these differences are not as clearly written as W3C standards:
Weex enables developers to use modern web development skills to build Android, iOS, and Web apps with a single codebase.
That is to say, general Web experience is not fully applicable, learning curve is not very friendly, for example:
-
Adaptation experiences like rem, media queries, scale/zoom may not all be applicable
-
Regular optimization measures like reducing DOM operations, merging JavaScript files, enabling hardware acceleration may not necessarily produce obvious performance optimization effects
-
(Like learning Web) only understanding standard capabilities above browser is not enough, to truly efficiently complete business development work, container principles and even some implementation details must be understood
Just like developers with Native background learning [TypeScript](/articles/typescript 简介-typescript 笔记 1/), initially contact and self-taught, familiar [Class](/articles/类-typescript 笔记 4/), Interface, [static types](/articles/基本类型-typescript 笔记 2/) are used with ease... However, developers who know TypeScript well must know how many strange places exist in the details
4. What is the True Meaning of Cross-Platform?
React Native's original starting point was:
Hope Native development can also Move fast like Web
- Rapid iteration cycle: Web two versions a day, product iteration cycle is shorter
- Immediate testing feedback: Web release immediately reaches users, A/B test and other experiment results are immediately available, product evolution is faster
- Rapid development velocity: Refresh browser to take effect, no need to wait for App recompilation
(From A Brief History of React Native)
Therefore, from demand perspective, development efficiency is secondary, dynamic flexibility, rapid iteration helping business win first is its main significance for cross-platform, or rather pursuing production efficiency, not just development efficiency, shorter iteration cycles, faster user reach are all direct production efficiency improvements
However, under the three major dilemmas, development efficiency actually also seriously affects production efficiency, but not enough to offset the major progress of rapid iteration and dynamic release, waxing and waning is also a kind of balance, an acceptable compromise
5. Finding a Way Out in the Dilemma
Ideally, container should tend towards standardization, providing multi-platform consistent, rich and stable capability support, business stack above rarely touches container capability boundary, thereby allowing container layer to continuously optimize and explore, better meeting business development needs
On the other hand, cross-platform solutions only sink the complexity brought by multi-platform inconsistency to the container layer, language environment independent of platform (JavaScript engine, Dart virtual machine, etc.) can guarantee consistency of upper business logic, but container layer still needs to implement a set on each platform, how to guarantee multi-platform consistency of container capabilities is still a big problem, and not much easier than under non-cross-platform solutions
Therefore, first need to solve the problem of container capability richness, widen the boundary, reduce problems from the root. Then concentrate firepower on real difficult problems, conquer the most valuable difficult parts. Simultaneously establish full-function business support teams through virtual architecture and other methods, reduce communication costs:
-
Business must have self-research capabilities: Resolve lower-level resource bottlenecks, jointly enrich container capabilities
-
Focus on points that must invest great effort: debugging capabilities, standardization, performance analysis and continuous tracking, engineering supporting facilities
-
Must have full-function business support teams: Capable of holding all problems, truly providing one-stop solutions, eliminating meaningless communication redirection
Among them, business self-research capabilities must first have standard extension methods, requiring container implementation to be easy to extend, business developers don't need to understand too many details to quickly enter development. Debugging capabilities are crucial under long-chain technology stacks, the lower the problem identification cost, the higher the accuracy, the higher the efficiency, the more resources that can be released
From business development perspective, what's more needed may be a gateway layer, requests go over and responses come back, rather than a series of routing tables, needing to track hop by hop. Full-function business support teams form a local area network, allowing traffic behind the gateway to flow quickly, improving business development happiness while collaborating efficiently
No comments yet. Be the first to share your thoughts.