Arla Rosenzweig & Lin Wang | Performance TPM, Performance engineer
As engineers, we intuitively know that a faster app is a better experience for Pinners, but we also have proof that when web pages load faster, user growth improves. Last year, we doubled down on performance across our platforms so that wherever our 200 million monthly active users were around the world, and regardless of their device, Pinterest would help them discover and do what they love — hopefully without waiting too long.
Globally connection speeds vary wildly across devices, but two things were consistent:
- The majority of smartphones worldwide are Android devices (just under 90 percent).
- Pinterest was consistently slower on Android.
With more than 75 percent of Pinterest signups coming from outside the U.S., we needed to speed up our Android app and maintain that speed even under constant development and new feature additions that might slow things down. This post will cover the four key lessons we learned will improve performance on Pinterest.
1. Defining a user-centric metric ensured we actually improved the experience.
We thought carefully about how we could make the biggest difference based on what we know matters the most to Pinners. For every main action on Pinterest — like loading the home feed, tapping to see a Pin closeup or searching — we defined a metric called Pinner Wait Time (PWT). Each metric measured the time from when a Pinner initiated an action (e.g. tapping a Pin) until the action was considered complete from the Pinner’s perspective (i.e. the Pin closeup view loaded).
2. Preventing regressions is the #1 way to keep an app fast.
Once we had a baseline measurement for each interaction, we wanted to make sure we weren’t slowing things down. Seeking testing precision and alert capabilities, we chose to use NimbleDroid, a cloud-based continuous performance testing tool that easily integrated with our process and produced actionable results. With their framework, we created regression tests that run on Android builds generated from code changes and alert us when a PWT metric has increased within designated thresholds. When there were no alerts, we knew our app was good to go, boosting confidence in merging pull requests and releasing it to Pinners. When we did receive alerts, we resolved the regressions in ~21 hours, which is far less time than the multiple days it previously took to identify and fix a regression.
Since these tests ran on builds with all A/B experiments disabled, we also needed a way to detect the impact of new experiences. We added performance data and more regression alerts to our in-house experiment dashboard which allowed us to identify which experiments were slowing down the app and see how the latency increase affected Pinners’ engagement across various surfaces.
Between NimbleDroid and experiment alerts, we detected ~30 slowdown regressions over the course of six months. Since our alert threshold was 100 milliseconds, these regressions, if released to our production app, would have accounted for at least three seconds of additional wait time. Aggregated over the hundreds of millions of actions taken each day, it had the potential to be a significant amount of of time wasted. By catching regressions early in the cycle, they were never released to Pinners.
3. Develop best practices in optimization performance.
Beyond regression tests, NimbleDroid also provided the opportunity to profile each interaction. For example, we found that while loading the Pin closeup view, we weren’t using the data already available from the initial feed response to display all the necessary information. This oversight was causing an extra round-trip and slowing down the overall load time. Submitting a fix and running it through NimbleDroid tests confirmed the improvement made Pin closeup load times 60 percent faster.
In line with this, we configured NimbleDroid to send alerts when things became faster, which helped validate optimizations and bug fixes like the above scenario. These alerts also helped catch a functional regression in our search feature that passed QA testing.
We also wanted to improve the experience of the “cold start”–the time it takes for the app to open and the home feed to load for the first time. Through tests, we found that reflective type adapters in Gson are expensive for the cold start of an application, so we generated type adapters at compile time and made the JSON parsing more efficient, saving ~30 milliseconds in a Pinner’s cold start time.
Visibility into speed is crucial, especially for key interactions that make Pinterest so useful. We rely on NimbleDroid for insight into how we’re doing against our goals to not only maintain but also improve PWT across our platforms.
Exploring these optimizations reinforced the importance of parsing data efficiently and that the fewer (and smaller) network requests we make, the better. Whether loading the initial home feed or a Pin closeup, the more we can use locally-stored data, the faster a Pinner will be able to see the content they’re looking for. This effect is compounded in international countries where each network round-trip adds extra time to the overall PWT.
4. A faster app encourages more engagement.
We saw a consistent pattern wherever we optimized. Decreasing the amount of time it took to complete an action led to more engaged Pinners:
- When the home feed loads quicker, more Pinners scrolled past the first page of Pins and viewed more Pins overall.
- When we sped up the time to view a Pin closeup, people were less likely to impatiently tap the screen twice, which ultimately was leading to accidental Pin click-throughs.
Encouraged by these results, we’re beginning to focus our performance efforts with other interactions to continue exploring the relationship between improving performance and engagement. We’ll continue to monitor every critical user flow for every pull request to detect any performance regressions. This peace of mind from preventing regressions gives us the space and time to focus on what matters most to us–delivering an amazing experience to Pinners around the world.
Special thanks to Effie Barak, Ryan Cooke, Mallika Potter and Cal Rueb