In June 2018, Quintype approached Obvious to help them improve the performance of their reader-facing web frontend as well as their customer engagement platform.
Working together, we achieved the following goals within a span of two weeks:
- Improved the Google Lighthouse score of Quintype’s reader-facing web frontend by ~20 points
- Discovered the cause for an input latency of ~500 milliseconds in one of their products and outlined the fixes required to eliminate it
- Trained two of their developers in the art of profiling and optimising React applications
- Led a 60-minute hands-on workshop at their office that introduced their entire development team to the performance tools built into Google Chrome
We also worked with the engineering teams and product managers across Quintype to show the importance of working within performance quotas and making performance measurements a part of the development process.
Quintype is a digital publishing tool that powers some of the largest online publications in India, including The Quint, National Herald, Fortune India, and Climate Desk.
Quintype also offers publishers a user-engagement platform called Metype, which allows readers to comment on, react to, and discuss any story published on any web publishing platform.
This engagement centred around optimising the load time and performance of Quintype’s user-facing web products:
- Drift, which is the reader-facing web frontend to Quintype’s publishing platform
- The reader-facing part of Metype, their user-engagement platform
Quintype found that the performance of both Drift and Metype could be vastly improved on the mobile hardware and networks commonly available in India. They wanted to engage us for a two-week contract during which they wanted to meet the following goals:
- Discover performance problems in Drift and Metype
- Either fix these performance problems or help the development teams understand how to fix them
- Discover violations of common web engineering best practices in the Drift and Metype codebases
- Train some of their developers in the art of profiling and fixing performance issues
- Help engender a performance-first development mindset within their web engineering teams to stay competitive in the Indian market
Internet in India
India is one of the fastest-growing markets for internet services in the world. Between 2014 and 2017, nearly 200 million Indians connected to the Internet for the first time, and the total number of internet users in the country is expected to touch 650 million by the year 2020. A large percentage of these new users are using budget Android phones that do not always have access to fast mobile networks.
In this context, any organisation that targets internet users in India must treat good performance on bandwidth- and CPU-starved mobile phones as a core feature of their product, not simply a nice-to-have.
Being in the business of attracting and holding the attention of digital consumers, the product team at Quintype understands this fact very well. In June 2018, they initiated an organisational push to put web performance at the centre of their development efforts, and our engagement with them was part of that same push.
Our web engineering team spent June 11 to June 22, 2018 working in the Quintype office in Bangalore. During these two weeks, we studied the performance of the company’s codebase:
- Using automated tools, such as WebPage Test and Google Lighthouse, to discover the most pressing performance problems
- Using the profiling tools built into Google Chrome and Safari to trace the root cause of performance issues back to specific areas of the codebase
- Using React-specific profiling tools, such as why-did-you-update, to discover issues that specifically plague React applications
We used two other techniques to help meet Quintype’s larger goals: pair profiling and a company-wide workshop.
Profiling code to discover performance issues is like solving a Holmesianmystery. It is a non-linear process that involves a lot of measuring, testing, hypothesising, and writing a ton of throw-away code until the root cause of a problem is found. Since we have been doing performance optimisation for many different clients, we have developed an intuition for this process.
One of the stated goals of Quintype’s leadership was to develop this intuition in their team. To achieve this goal, our engineers sat next to two engineers from Quintype’s web team and talked through what they were doing as they profiled Drift and Metype. The process they followed was not dissimilar to pair programming or job shadowing, hence the moniker “pair profiling”.
At the end of these pairing sessions, both engineers were able to proficiently use the Chrome DevTools to debug and profile existing code, analyse Webpack bundles, follow React best practices, and make measurable improvements to their code based on the reports generated by WebPageTest and Google Lighthouse.
For those who could not be part of our pairing sessions, we conducted a 60-minute workshop on performance profiling in the second week of our engagement. During this workshop, we used findings from our first week of work as practical examples of how common performance killers show up in the Chrome profiler.
We made a case for improving software performance from a design and business standpoint. We even talked about when not to focus on performance, where we discussed the kinds of applications that gain no business advantage by improving load times.
Throughout the workshop, we used Chrome’s CPU profiler, memory profiler, and timeline view to analyse the performance of real-world web properties powered by Quintype’s software. We also looked at the reports produced by WebPageTest and Google Lighthouse and talked about how to use those numbers to guide the development of the entire application.
Let’s delve into some technical details.
Quintype scored well on most checklists of web performance best practices. However, we found issues on some pages that we were able to trace back to either third-party libraries or simple misconfigurations.
For instance, we discovered that a few resources served by one of Quintype’s CDNs had an incredibly high time to first byte (TTFB). On contacting the CDN provider, we discovered that this was because of a very minor misconfiguration. Fixing the configuration reduced loading times by ~200ms for several resources served from that CDN.
We also reviewed parts of the React code responsible for rendering stories, collections, and pages on Drift, and we made sure that the most critical parts of the code followed the currently recommended best practices for React performance. This was a quick-and-easy win in terms of improving load times.
Bundle sizes were not an issue for Drift, but they were a big problem on Metype. Several third-party dependencies were pulled into the codebase even though they were used in only one or two places across the project. Some of these libraries had native alternatives.
The bootstrap script is loaded on each page that uses any of the features provided by Metype. After it loads, it detects what features the page has requested and requests all the bundles required to enable the requested Metype features from the server.
By carefully using webpack-bundle-analyzer and whybundled, we removed a large number of extraneous dependencies from Metype’s bootstrap script and reduced its bundle size by over 90%. As of this writing, the Metype team used the same tools and techniques to drastically reduce the bundle sizes of the rest of the Metype suite as well.
Third-party libraries often cause performance issues in web applications, especially when they interact badly with the existing code or accidentally trigger undefined behaviour.
We found another such issue with third-party code in Metype. Clients had been complaining for a long time that typing into the comment box in the Metype commenting widget was very slow. On cheaper Android devices, registering a single keystroke could sometimes take an entire second.
Two third-party libraries interacting badly with each other caused this issue:
- iframe-resizer, a library used for managing the size of the embedded iframe that contains the commenting widget on a third-party web page
- Quill.js, a rich text editor used in Metype’s commenting widget
iframe-resizer uses a MutationObserver to observe changes to the DOM of the iframe that contains the commenting widget and resizes it so that its dimensions on the host page are the same as the size of the content it contains. On the other hand, Quill.js stores all the text entered into its rich text field directly in the DOM.
In Metype, every time a user entered something into the Quill.js field, it triggered a change in the DOM. This forced iframe-resizer to recalculate the size of the commenting iframe, which caused an expensive re-layout, and hence the ~1s delay between the user entering a character and it appearing on the screen.
It is important to consider the impact of third-party libraries before adding them to a project. After adding a new dependency, its performance impact should be measured in terms of code size, CPU usage, and memory usage.
At the end of the two-week engagement, Drift’s score on Google’s Lighthouse improved by ~20 points, Metype’s bundle size was reduced by over 90%, Metype’s input latency decreased by several seconds, and two of Quintype’s developers were trained in the art of profiling and optimising Web performance.
We also educated the organisation on why web performance is critical, engendering a culture of working within performance quotas, regularly measuring performance as a part of the development process, and considering the impact of third-party libraries.