Startup Time: Your App’s Make or Break Moment
- Published on
Introduction
Dream11 has revolutionised the way fans engage with their favourite sports in India. We host a community of over 220 million sports fans. During IPL 2024, we had more than 15 million fans concurrently playing on our platform.
The Dream11 engineering team ensures a best-in-class experience for our users. Given the time-sensitive nature of our business, an interactive and efficient mobile app is a must. It is worth noting that at Dream11, we use React Native to develop our mobile app.
In this blog, we will deep dive into the optimisations we have done to enhance the startup time of our app.
Deciphering Startup Time
Startup time can be defined using two key metrics: TTID (Time to Initial Display) and TTFD (Time to Fully Drawn).
TTID represents the time taken to display the initial frame of the app. We consider the moment when the first frame of the splash screen is displayed as TTID.
TTFD signifies the duration required for the app to become fully interactive. For us, it is when the most critical component of the home screen is loaded.
Why does it matter?
User experience
- Users lose interest or are left frustrated while using slow-performing apps, leading them to explore alternative platforms or express dissatisfaction through negative reviews
Business Impact
- Reducing startup time results in a faster home screen display, allowing users to participate in more contests seamlessly, thereby positively impacting business metrics
Cracking open the Startup Time
Before optimizing, it is crucial to identify factors causing delays.
We broke down the problem into smaller, more manageable segments as shown in the below illustration. It was crucial to attribute time spent on each segment. Furthermore, creating the right benchmarks to measure the impact of our optimizations was one of our biggest challenges. We will deep dive into the details of our benchmarking setup in subsequent blogs.
Optimizations
Harnessing the Power of Hermes Binary Bundle
- Hermes is a JavaScript engine specifically designed to enhance the performance of React Native applications
- When an app adds a JS bundle into its production environment (Necessary for a React Native app), the Hermes compiler transforms the JS bundle into a binary bundle. However, this transition can be computationally heavy and cause delays. By adopting the Hermes binary bundle, we effectively run this transition at compile time, resulting in significant improvement in performance
- To enable Hermes in your project, you can include the following line in your app-level Gradle file
def enableHermes = project.ext.react.get(“enableHermes”, true);
Prefetching data
- As the initiation of the app involves computationally intensive tasks, the network module is largely idle
- Leveraged this to predict and proactively fetch data the app might need to display on the start
- Led to a massive improvement in our TTFD - We also plan to run more such optimisations by analyzing production data and predicting user behaviour
Deferring function execution until required
Functions which are executed immediately tend to add to startup time due to the time it takes to interpret and run its compute
Calling functions globally (for example: at the top of a file) can cause an unintended increase in startup times
Let’s explore this with a real-world example:
- We use GraphQL for type safety, API composition, and network optimisation.
- GraphQL Code Generator can output code by analyzing the schema and documents and parsing them.
- These generated documents are decorated with the `gql` tag, which runs compute on a string literal and returns an object.
- In our case, we had hundreds of such functions generated in a single file which were executed as soon as the bundle loaded, resulting in increased startup time.
- To address this, we eliminated the immediate execution of such functions. Instead, we deferred their execution until they were used, leading to a notable improvement in both bundle load time and the app's TTFD.
Enable Inline require flag in Metro
- Metro, React Native's default bundler, packages JavaScript code and dependencies into a single file for execution on mobile devices
- Enabling the metro inline require flag in the metro.config.js file delays the loading of modules or files until they are needed.
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
…………
inlineRequires: true,
…………
},
}),
},
}
Lazy initialization of Android content providers
- During app launch, initializing Android content providers adds to startup time.
- Fortunately, the Android startup time library offers a solution. We've lazily initialized content providers that are not required on the home screen, effectively reducing startup time
Enhancing App Performance with Baseline Profile Optimization
- The baseline profile improves code execution speed by avoiding interpretation and just-in-time compilation for specified paths in the startup profile
- Baseline profiling with the startup path in the app allows Android Runtime (ART) to optimize specific code paths through Ahead-of-Time compilation, enhancing startup time
Optimising OnCreate of Application and launcher activity
- Excessive workload carried out in the onCreate method of the application and the onCreate method of the launcher activity are often the primary causes of slow startup time
- To address this issue, we conducted a thorough investigation, and our approach involved offloading time-consuming tasks to background threads
- Additionally, whenever feasible, we implemented lazy class. These measures have proven effective in mitigating overall sluggishness
Android viewStub
- Android viewStub is a powerful tool that enables the deferral of complex view inflation until they are required, speeding up the initial app load. It was particularly valuable in scenarios involving intricate layouts or resource-intensive views that are not immediately visible to the user
- For us, this was useful in loading native(Android implementations) parts of our home page faster
After implementing the optimizations mentioned, we've effectively reduced our app's startup time, as demonstrated below:
Conclusion:
In conclusion, optimizing startup time directly impacts business success. Implementing advanced strategies ensures a high-quality user experience in today's cluttered digital landscape. We stay ahead of the curve by listening to feedback and valuing customer reviews, thereby building a loyal community of passionate sports fans. Our team continuously analyze user engagement to innovate and deliver adaptive strategies. Stay tuned for more on our commitment to crafting exceptional user experiences.