Until recently, Dropbox had a technical strategy to use common C ++ code for iOS and Android mobile applications. The idea is clear: write code once in C ++ instead of duplicating it separately in Java and Objective C. We adopted this strategy back in 2013, when the group of mobile development engineers was relatively small and had to quickly develop the product. Such a solution allowed to produce a large amount of code on both Android and iOS by the forces of a small team.
Now we have completely abandoned this strategy in favor of the native languages of each platform (primarily Swift and Kotlin, which did not exist when we started). The solution involves the (not so) hidden costs of code sharing.
All the problems stem from the main thing
: the overhead turned out to be more than just writing the code twice
Before analyzing various types of overhead, I would like to clarify that we never got to the point where most of the code base was in C ++. Costs actually prevented us from moving in that direction.
It's also worth noting that much larger companies such as Google and Facebook have been developing scalable code sharing solutions for several years now. Such solutions are not very common. Although third-party systems like React Native or Flutter avoid some of the overhead, some costs still remain (at least until one of these technologies becomes popular and mature enough). For example, Airbnb refused to use React Native
for many of the same reasons that are outlined in this article.
All costs can be grouped into four main categories.
Overhead of custom frameworks and libraries
The easiest way to predict the costs of creating frameworks and libraries. They are roughly divided into two subcategories:
- Frameworks that allow you to interact with the host environment to create a full-fledged mobile application. For example:
- Djinni , a tool for creating interlanguage declarations of connection types and interfaces
- A framework for performing tasks in the background against the main thread (trivially in the native languages of the platform)
- Libraries to replace language standards or open source solutions that could be used in native languages, for example:
- json11 for (de) serializing JSON
- nn non-null pointers for C ++
None of this is necessary if you stay in the native languages of the platform. And our participation in open source projects in our native languages would probably bring more benefit to the developers. In the C ++ community, the open source culture was (and is it?) Not as developed as in the mobile developer community, all the more so since the C ++ mobile
community practically does not exist.
Please note that these overheads are especially high for C ++ (unlike other possible non-native languages such as Python or C #), because there is no one fully functional standard library. However, only C / C ++ has a compiler supported by both Google and Apple, so switching to another language causes a number of other problems.
Oversized custom development environment
There are many tools in the mobile ecosystem to improve development efficiency. Mobile IDEs are very functional, and Google and Apple have invested a lot of resources to make them ideal on their platforms. Moving away from defaults, we give up some advantages. First of all, native language debugging usually outperforms C ++ debugging in the IDE by default.
I especially remember one error that caused a blocking of the background streaming structure, which led to accidental application crashes. Such errors are difficult to track even with a simple, standard stack. Since the problem involved debugging multi-threaded code running between C ++ and Java, it took weeks to track!
In addition to losing the standard tools, I had to invest time in creating my own tools to support common C ++ code. Most importantly, a custom build system was required to create libraries that contain C ++ code, as well as Java and Objective-C shells. It should generate goals that both Xcodebuild and Gradle understand. Creating such a system took us a lot of resources, because it had to be constantly updated to support changes in the two build systems.
Platform Override for Platform Differences
Although iOS and Android are “mobile applications” that usually provide the same features, there are certain differences in the platforms themselves that affect the implementation. For example, how an application performs background tasks. Even similar things can start to differ greatly over time (for example, interacting with the camera).
As a result, you cannot just write code once and run it on another platform. You need to spend a lot of time integrating and coding for a specific platform, and sometimes this code ends right at the C ++ level!Theoretical savings from writing code only once does not correspond to reality, which immediately greatly reduces the effectiveness of this approach.
Overhead for hiring, training and retaining developers
Last, but not least, is the cost of training and / or hiring developers to work with our very peculiar stack. When Dropbox started using this mobile strategy, we had a core group of experienced C ++ developers. This group launched the C ++ project and trained other mobile developers.
Over time, these developers went to other teams and other companies. The remaining did not have enough experience to fill the gap in technical leadership, and it became increasingly difficult to find experienced engineers with the appropriate C ++ experience who are interested in developing for mobile devices.
As a result, we were faced with a real lack of critical knowledge to maintain the C ++ code base. Only two options remained, and each required significant effort:
- Find and hire candidates with a very specific set of skills (we tried unsuccessfully for a year).
- Train your own mobile (or C ++) developers, which is almost impossible to do in the absence of seniors with the right set of skills to complete the training. Even when the main group had not yet dispersed, mobile developers were usually not interested in C ++, so finding people to learn was also a big problem.
In addition to hiring, the release of its own technology stack created a holdover problem - mobile developers simply did not want to work on a C ++ project. This caused many talented engineers to leave the project instead of continuing to suffer with a poorly maintained custom stack. In general, the community of mobile developers is very dynamic - new technologies and models appear frequently and are implemented quickly. Top engineers love to keep their skills up to date.
A mature product with a standard stack is not easy to keep up to date. You sacrifice novelty for stability. This problem increases significantly if you lock yourself in a custom stack outside the wider mobile ecosystem.
Once, writing code once for different platforms seemed like a great deal, but the associated costs outweighed its advantages (which in any case were less than expected). In the end, we no longer use a common code base through C ++ (or any other non-standard way), but write code in our native languages for each platform.
In addition, we want our engineers to feel good and be able to contribute to the community. That is why we have decided to bring our practice into line with industry standards.