BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News The Ten Year Journey of Facebook's App for iOS

The Ten Year Journey of Facebook's App for iOS

Facebook rewrote its iOS app in 2012 to take advantage of native performance and improve reliability and usability over its previous HTML5-based cross-platform implementation. In the ten years since the rewrite, the app codebase has evolved non-stop to account for the introduction of new features, to circumvent SDK limitations, and to keep up with changes in the iOS platform, explains Facebook engineer Dustin Shahidehpour.

Two years after its native rewrite, Facebook's app for iOS started to show reliability issues related to the use of Core Data. Core Data models are intrinsically mutable, says Shahidehpour, and this makes it hard to use them in a multithreaded app.

Ultimately, this design exacerbated the creation of nondeterministic code that was very difficult to debug or reproduce bugs. It was clear that this architecture was not sustainable and it was time to rethink it.

Facebook engineers implemented then ComponentKit, a React-inspired declarative framework to define UIs. ComponentKit used immutable data, which simplified reasoning about the code and provided a 50% performance improvement over the previous implementation. ComponentKit has been hugely successful within Facebook, where it still is the default choice to create iOS UIs.

In 2015, the Facebook app saw what Shahidehpour describes as a "feature explosion", which had the net effect of degrading launch time up to the point where the app could risk being killed by iOS. This led to the effort of modularizing the codebase using dynamic libraries (dylibs) so that part of the code could be loaded lazily, thus reducing the number of tasks to execute before main.

While the adoption of dylibs solved the issue with launch time, it introduced a different class of reliability problems, mostly related to the possibility of a runtime error when trying to access some code in a not-yet-loaded dylib. To fix this problem, Facebook engineers decided to leverage the build graph produced by Buck, their own build system.

Each ‘target’ lists all information needed to build it (dependencies, compiler flags, sources, etc.), and when ‘buck build’ is called, it builds all this information into a graph that can be queried.

Using that information, the app was able to create a mapping from classes and functions to dylibs and then automatically generate code to ensure a dylib was loaded into memory when some functions tried to access it.

This further led to the creation of a plugin system that made it possible to detect dependency graph-related errors at build-time instead of runtime.

It was not until 2020 that Facebook started using Swift in their mobile apps, prompted by a growing number of Swift-only API appearing in the iOS SDK. This represented a radical change from the previous stance of accessing SDK functionality only through some kind of wrapper. While motivated by the goal to improve developer efficiency, this approach was made more complicated by the lack of interoperability between Swift and C++. The solution to this was requiring that UI-related code should not contain any C++ so that engineers could use current and future Swift APIs from Apple, while C++ was reserved for infrastructure code.

Overall, the evolution of Facebook's app for iOS shows a number of strategies that can be useful to overcome platform limitations and to adapt to the changing nature of requirements and of the underlying platform. Do not miss the original article if you are interested in the full details.

About the Author

Rate this Article

Adoption
Style

BT