The following post outlines the links, tools and articles I mentioned in my 3rd party footprint talk
Shared Links and Articles
- HTTP Archive: httparchive.org
- Big queries: interesting stats: http://bigqueri.es/t/what-is-the-distribution-of-1st-party-vs-3rd-party-resources/100/4
- The impact of third party content on retail web performance: http://intechnica.co.uk/the-impact-of-third-party-content-on-retail-web-performance.aspx
- Nielsen and promotional space http://www.useit.com/alertbox/response-times.html
- Pat Meenan: Front-end SPOF: http://www.slideshare.net/patrickmeenan/frontend-spof and http://blog.patrickmeenan.com/2011/10/testing-for-frontend-spof.html
- Government UK, adding social buttons did not increase their traffic dramatically: https://insidegovuk.blog.gov.uk/2014/02/20/gov-uk-social-sharing-buttons-the-first-10-weeks/
- Steve Souders, Caching policies: http://www.stevesouders.com/blog/2012/03/22/cache-them-if-you-can/
- Steve Souders, Don’t doc write: http://www.stevesouders.com/blog/2012/04/10/dont-docwrite-scripts/
- Asynchronous List: https://developers.google.com/speed/docs/insights/UseAsync
Tools and Tricks
- Ghostery plugin: https://www.ghostery.com/en/
- 3 D Tilt Firefox Plugin: https://addons.mozilla.org/en-US/firefox/addon/tilt/
- Philips’ script loader pattern: http://www.lognormal.com/blog/2012/12/12/the-script-loader-pattern/ or Method Queue Pattern: http://www.speedawarenessmonth.com/the-non-blocking-script-loader-pattern/
- Stoyan’s dynamic script tag: http://www.phpied.com/social-button-bffs/
- SPOF-O-Matic: https://chrome.google.com/webstore/detail/spof-o-matic/plikhggfbplemddobondkeogomgoodeg
- 3PO plugin: http://www.phpied.com/3po/
- Continuos integration: Ebay & SPOF: http://www.ebaytechblog.com/2013/01/22/early-detection-of-frontend-single-points-of-failure/#.UyTqyeddW_I
- Command Line Interface SPOF: https://github.com/lafikl/spof?utm_content=buffer3bda5&utm_source=buffer&utm_medium=twitter&utm_campaign=Buffer
- Heise’s 2-click button: http://www.heise.de/extras/socialshareprivacy/
- JSManners: https://github.com/triblondon/thirdpartysla
- Herold Sun: www.webpagetest.org/result/140222_EA_J3R/
- Wired: www.webpagetest.org/domains.php?test=140222_NH_J10&run=1&cached=0
- TechCrunch: http://www.webpagetest.org/video/compare.php?tests=140323_P3_GRK,140323_37_GRM
- SPOF Wired: http://www.webpagetest.org/video/compare.php?tests=140224_7X_28Q,140224_4K_28R
- Alexa AUS 139: myshopping.au.com http://www.webpagetest.org/video/compare.php?tests=140317_NE_P%2C140317_ZN_Q&thumbSize=200&ival=5000&end=visual
- Home Depot: http://www.webpagetest.org/video/compare.php?tests=140317_KM_5D%2C140317_EB_5E&thumbSize=200&ival=5000&end=visual
- TechCrunch: http://www.webpagetest.org/video/compare.php?tests=140319_9B_EKD%2C140319_00_EKE&thumbSize=150&ival=5000&end=visual
- Walmart passes SPOF test: http://www.webpagetest.org/video/compare.php?tests=140319_0S_HN4,140319_GJ_HN5
- Weather Network: http://www.webpagetest.org/video/compare.php?tests=140321_4B_DJ2%2C140321_9H_DJ3&thumbSize=200&ival=5000&end=visual
ESI stands for Edge Side Include and is an XML-based markup language. ESI support is offered by content delivery network (CDN) vendors like Akamai and F5 and also now Varnish (but only a very limited subset). If you use any of these vendors, you have ESI at your disposal. ESI can be used for caching purposes, however, in today’s post I will focus on how it could help you with your mobile strategy and performance.
The W3C states:
“ESI allows for dynamic content assembly at the edge of the network, whether it is in a Content Delivery Network, end-user’s browser, or in a “Reverse Proxy” right next to the origin server.” (http://www.w3.org/TR/esi-lang)
So, let’s pay attention to “dynamic content assembly” in the context of the title’s blog post.
If you are familiar with Server-Side-Include (SSI) and XML/XSLT, you will have no problem understanding ESI. It also supports the same access to variables based on HTTP request attributes, e.g. you can easily check for HTTP_USER_AGENT or HTTP_HEADER. ESI can also include fragments or snippets of additional content via an include command. To make this even more powerful, ESI supports conditional processing, which means logic can be applied to execute specific content
<include/>s based on specific conditions, e.g. user agents. All of this is done at the edge; the user will never get content they are not supposed to receive. Additionally, when processing ESI, there is no need to go back to the origin for processing, hence the load at the origin is cut down.
What is (your) Mobile Strategy?
A mobile strategy or approach could range from “We don’t have one”, or “We swear on responsive web design” to “We take mobile very seriously and have dedicated sites”. If you opt for the first statement, please read this and then come back. If you opt for the second or third statement, please continue reading. While there are several options out there to do device detection via PHP or any other server-side language, I’d like to provide several insights on how the same can be achieved with ESI. Similar to other redirect strategies out there, ESI can be used to redirect users to a different site based on the visitor’s user agent. The redirect occurs at the edge and is faster than putting the redirect logic at the origin, hence, you experience performance improvements. ESI is powerful and cheap tool, and your way to a proper mobile device strategy could work by following the steps below.
To continue, please go to my guest post for Stoyan’s perf calendar, December 3: http://calendar.perfplanet.com/2013/esi-mobile-strategy-performance/
Performance optimization has been more than ever in the spotlight of web developers, especially for mobile web developers who have to understand and know by heart the challenges and constraints of mobile devices: these devices run off a battery that e.g. drains faster if performance is not taken seriously. The devices are powered by smaller CPUs than desktop devices. Unknown factors like latency and network connectivity challenge developers to build slim, light-weight and fast websites. Data plans still remain expensive and inconsiderate use of served data by web developers should not be ignored.
Clearly, performance is (and should) not (be) an after-thought anymore. When web developers create websites, performance can influence the success or failure of a web product. We’ve been hearing from leading performance advocates like Ilya Grigorik that speed is a feature and should not only be thought of just before a product hits production but rather as an essential part of the web product development cycle.
In today’s blog post I will be sharing some of the plugins for Grunt that can be used to speed up and automate performance optimization. At the end of the blog post, I will present performance results that will show that frontend optimization (FEO) can be fun and easily be automated to cut page load time.
Note: The post assumes that you’ve worked with Grunt before and know how it’s been installed, and how to install plugins (I won’t go into details, however links at the bottom will help you)
“Let’s grunt it up”
(All plugin headings in this post are clickable links to their appropriate pages)
Montage helps you sprite images to reduce HTTP requests. You will need ImageMagick to be installed. Alternatively, you can also try out grunt-spritefiles.
<!-- build:js js/magic.min.js --> <script src="js/1.js"></script> <script src="js/2.js"></script> <script src="js/3.js"></script> <script src="js/4.js"></script> <!-- endbuild -->
You can use grunt-processhtml instead.
Same logic and idea than uglify, once your CSS files are all concatenated, use cssmin to shrink several lines of CSS code into one single one.
imagemin minifies JPG and PNG images. It’s a handy Grunt plugin if you don’t know if the assets you got handed from your designer (or yourself) are optimized for web yet. By using this tool, you have the piece of mind that you use image files in an efficient way. Alternatively, you could use grunt-smushit, it’s based on Yahoo’s great smushit tool that is available in the YSlow plugin for several browsers.
This plugin encodes images as base64 and leverages the technique of data URIs for images, something that can be used inline with CSS to reduce HTTP requests and hence reduce page load time. I’ve written a blog post where this is explained in more detail.
Use grunt-exec to run the SPOFcheck. An excellent tool to identify bad 3rd party scripts includes, developed by the eBay team. I didn’t include the scripts asynchronously, hence SPOFcheck complaints to avoid SPOF.
“It’s Magic” Sample Page
I created a simple page themed “It’s magic” where I applied all mentioned plugins. You can find the files including Gruntfile.js here. Please note, I intentionally didn’t put a lot of effort into the styling (It is supposed to look as simple and cheesy as it feels to you)
This file is the one that Grunt will create for you. Visually, the file doesn’t look that different, besides the fact that the title has changed….see yourself
Below are screenshots of the two pages (and links) side by side, the one on the left before Grunt tasks were applied. The right one shows the page after Grunt tasks were applied. For the user they both look the same (except for the heading).
Can you spot the differences?
- The logo was being transformed into a data URI
- The title has changed from It’s not magic to It’s magic
- The HTML was being compressed, comments were taken out automatically
- The next and previous buttons were converted to a sprite file
- On build, SPOFcheck was applied and gave us the following warnings so we could address possible SPOF issues
Let’s take a look under the hood
Here are the waterfalls for both versions:
I ran WebpageTest for both files with 9 runs for IE8 with a DSL connection to retrieve the median. Here are the performance results:
- HTTP requests dropped by ~48%
- Page load time (PLT) dropped by ~10%
- File sizes dropped by ~10%
Even if those numbers are not that high (mostly due to the simplicity of the experiment), it shows that Grunt can help you automatically optimize your deployment process.
As you can tell by the sample code, there are many mix and match options available, depending on the magnitude and granularity of your page structure. Nevertheless, this little sample shows how to use Grunt to optimize performance and to illustrate what is possible. Feel free to use the code as a starting point, and tweak or customize it to your likings.
General references and info to get you started with Grunt
If you landed here because you’ve typed in the URL after attending my talk, great! Thanks for making it all the way here. I hope you enjoyed my talk.
If you landed here via Google, Twitter or any other sites, I welcome you too, of course! You might want to first have a look at my slides (see link below) before clicking on any of the other links below.
Either way, feel free to leave a comment or contact me via twitter with my handle @bbinto.
Slides available on SlideShare
Links and articles, recommended content
- NYC Times: Why waiting in line is torture
- Perception of Speed
- The New Multi-Screen World Study
- Chris Heilmann: HTML5 mythbusting
- Who killed my battery: Analyzing Mobile Browser Energy Consumption
- CSSEmbed – automatically data: URI-ize (200ms HTTP request rule)
- CSS WebKit reference
- The Evolution of Web Development for Mobile Devices
- Google Closure Compiler
- PhantomJS and Confess
- Compass for data URI
Continuos Integration Tools (<3)
Be honest, have you ever wanted to play Steve Souders for a day and pull some revealing stats or trends about some web sites of your choice? Or maybe dig around the HTTP archive? You can do that and more by setting up your own HTTP Archive.
httparchive.org is a fantastic tool to track, monitor, and review how the web is built. You can dig into trends around page size, page load time, content delivery network (CDN) usage, distribution of different mimetypes, and many other stats. With the integration of WebPagetest, it’s a great tool for synthetic testing as well.
You can download an HTTP Archive MySQL dump (warning: it’s quite large) and the source code from the download page and dissect a snapshot of the data yourself. Once you’ve set up the database, you can easily query anything you want.
You need MySQL, PHP, and your own webserver running. As I mentioned above, HTTP Archive relies on WebPagetest—if you choose to run your own private instance of WebPagetest, you won’t have to request an API key. I decided to ask Patrick Meenan for an API key with limited query access. That was sufficient for me at the time. If I ever wanted to use more than 200 page loads per day, I would probably want to set up a private instance of WebPagetest.
To find more details on how to set up an HTTP Archive instance yourself and any further advice, please check out my blog post.
Going back to the scenario I described above: the real motivation is that often you don’t want to throw your website(s) in a pile of other websites (e.g. not related to your business) to compare or define trends. Our digital property at the Canadian Broadcasting Corporation’s (CBC) spans over dozens of URLs that have different purposes and audiences. For example, CBC Radio covers most of the Canadian radio landscape, CBC News offers the latest breaking news, CBC Hockey Night in Canada offers great insights on anything related to hockey, and CBC Video is the home for any video available on CBC. It’s valuable for us to not only compare cbc.ca to the top 100K Alexa sites but also to verify stats and data against our own pool of web sites.
In this case, we want to use a set of predefined URLs that we can collect HTTP Archive stats for. Hence a private instance can come in handy—we can run tests every day, or every week, or just every month to gather information about the performance of the sites we’ve selected. From there, it’s easy to not only compare trends from httparchive.org to our own instance as a performance baseline, but also have a great amount of data in our local database to run queries against and to do proper performance monitoring and investigation.
The beautiful thing about having your own instance is that you can be your own master of data visualization: you can now create more charts in addition to the ones that came out of the box with the default HTTP Archive setup. And if you don’t like Google chart tools, you may even want to check out D3.js or Highcharts instead.
The image below shows all mime types used by CBC web properties that are captured in our HTTP archive database, using D3.js bubble charts for visualization.
Querying the Database
Sometimes, you want to get some questions answered without creating a chart. That’s when you can query the MySQL tables directly. Let’s run a simple query on the
For example, some of the CBC sites use YUI, some use jQuery—but we would really like to avoid having pages serve both. A simple sample query like the one below could help identify those sites:
WHERE url LIKE "%/jquery_.js%" OR url LIKE "%/i/l/yui/%"
GROUP BY req_referer
And More …
We will share more of the queries and insights we’ve gathered from our HTTP Archive instance that helped us identify bottlenecks. In addition, we will also discuss how this setup came in very handy to discover problems with some unnecessary page weight that we thought we didn’t have.
Join our talk at the Velocity conference in Santa Clara in June titled “The Canadian Public Broadcaster on A Diet: Slimming Down for A Whole Nation.” The talk will not only cover the private HTTP Archive instance but furthermore cover many other aspects of how to focus on (mobile) web fitness and how to “slim down.”
Related Posts to our Talk
I have attended several conferences in the last few years. The first one that really changed my “developer life” was the Velocity 2011 conference in Santa Clara. I have always been interested in optimizing and being diligent about the web, however, my learning during those three days in Santa Clara has influenced my every day life and the way I see performance.
I truly admire each and every speaker and attendee at the conference because they all share the same passion: Optimizing the web and making performance count. I am honoured to announce that it is my turn this year to give back to that same community of people and share what I have learned over the last few years and what I have been applying at Canada’s public broadcaster, the CBC.
Our talk “The Canadian Public Broadcaster On A Diet: Slimming Down For A Whole Nation“ will focus on (mobile) web fitness and how to “slim down”. Tips and tricks will be shared about how to stay in shape when developing (mobile) sites for millions of people.
My talented co-worker Blake and I will be talking about how we apply performance optimization at the CBC, one of Canada’s largest web properties with over 5 million pages. As a publicly funded organization, all Canadian eyes are on us making sure we stay on budget and deliver quality and optimized content to users.
While Blake will be talking more about the backend, server and CDN aspects of performance optimization and tips, I will be sharing information about how we optimize and tweak performance from a frontend development and automated deployment perspective, basically – how to get and stay in shape.
Don’t worry; this definitely will not be your typical boring and horrifying boot-camp experience! Our talk will utilize fun and catchy analogies to explain the weight and performance of pages. I will be your honest CBC “fitness trainer”, telling the audience about the page weight of our sites on multiple platforms, how we measure performance and set budgets. However, putting our content on a scale will tell the truth: a content breakdown of our pages will help the audience understand how content is structured and where we can “slim down”, but also where a fitness routine cannot help.
Keep us company while we share some insights about setting up our own HTTP Archive instance as a tool – or how I would describe it: the BMI of web sites – to compare our own weight to the public HTTP Archive instance. We will share some queries from our HTTP Archive database to help identify bottlenecks, and we will tell you about how we discovered problems with some unnecessary weight that we thought we didn’t have.
Additionally, sweet and dangerous temptations will be placed in front of your eyes, the kinds that we all have to deal with when creating high traffic sites, including, 3rd party scripts that could significantly harm the performance of our sites when not properly implemented. We compare client-side versus server-side 3rd party implementation. We will also reveal the amount of improvement we saw in load time once we turned off all ads on our mobile touch site for a weekend.
During our talk, you will also hear about our fitness stack regarding how we monitor our fitness level, and why it is so important to stay on a strict exercise schedule and avoid gaining too much unwanted weight, which can happen without even knowing it. If you want to exercise and stay in shape, there are tons of great tools out there to help you achieve that. We will cover how we organize and optimize our sites, our releases and deployment and how easily you can include tools in your deployment process to automate performance optimization.
If you want to know how we use RUM in combination with synthetic testing, and what our RUM numbers reveal, then you shouldn’t miss out on our talk.
Lastly, we will explain the challenges that we have faced, as the national news broadcaster in a world of ever changing news, with the potential for a breaking news story at any moment, that could drive our traffic to the roof, and how we need to respond to that.
Come join our talk and if you like, wear your favorite running shoes because you never know, you might want to start exercising right after.
We look forward to meeting you all!
More details to our scheduled talk and location: http://velocityconf.com/velocity2013/public/schedule/detail/27973
There is always room for improvement. Period.
Think about the 100 meter men’s sprint. I am amazed how it continues to be possible for human beings to still become faster and improve their performance.
I’m not Usain Bolt – I can’t run 100 meters in 9.58 seconds but I might be able to run (mobile) websites under 10 seconds.
Today, I want to focus on a technique I first heard about at the Velocity Conference in 2011 in Santa Clara and how to compare it with other ways to serve images in HTML pages.
Data URI is based on base64 encoding and basically encodes data (e.g. images) into bites. It can be used to improve performance.
Data URI as “Performance Enhancer”
Instead of requesting for example a PNG image, you could encode it as base64 and serve it inline with your HTML code. That way, you reduce one HTTP request – right there – 200ms saved. Instead putting it inline, you could also put it encoded in an external stylesheet.
Watch out for caching limitations though. Data URIs can’t be cached as they don’t have a standalone cache policy, they are part of the file that includes them. So they can only piggy-bag on other cacheable assets, e.g CSS or HTML files.
As Nicholas explains, if you put data URI images inline with HTML, they can only be cached as part of the HTML cache control header. If the HTML is not cached, the entire content of the HTML markup, including the inline data URI will be re-downloaded every single time. That approach, if the image is big in size, can slow down and weight down your page. Hence, one option is to to put it in stylesheets because they can have an aggressive cache while the HTML page can have no cache or a very limited cache.
Limitations and Browser Support
Think about the browser audience of the site you want to leverage data URIs for. If you target modern browsers, including new mobile devices because that’s where you really want to focus on performance the most, you might be able to ignore the following limitations and accept the little restricted list (thanks to Fire) of supported browsers.
- Firefox 2+
- Opera 7.2+ – data URIs must not be longer than 4100 characters
- Chrome (all versions)
- Safari (all versions)
- Internet Explorer 8+ (data URIs must be smaller than 32KB)
Motivation for Comparison
I’ve been reading a lot about web performance techniques and for some reason the data URI practice got stuck with me. I started off by creating the CBC gem (logo) in CSS to verify if CSS performs better than serving images. While I was playing around with that, I thought why not adding another dimension to the test and check the performance of the CBC logo as data URI. Voilà, I had my basic scenario for the test:
Check the performance of the CBC logo as
- An image in pure css
- A plain PNG image as background image
- A data URI (in CSS and inline with HTML)
Setting up the Test
The purpose of the test was to figure out what kind of presentation for the CBC gem would be the fastest and slimmest.
Prerequisites and Conditions
- All HTML and CSS files were minified and use the same markup (despite the logo in pure CSS which needed to have a few more div classes to render the circles)
- Each HTML version was tested with empty cache
- Performance results were performed with WebPagetest (10 runs on an 3G simulated browser) to find the Median.
1. Logo in pure CSS (30px x 30px)
|Description: Thankfully, the CBC gem consists of circles, 1/2 and 1/4 circles, those shapes can easily be created with CSS. I used this page to help me get started. Instead of setting up a fixed size and color, I decided to use SASS to help me be more flexible with my settings for the logo. The scss file lets me define color and size of the gem.
Note: Maybe the pure CSS logo has a bit of issues with some of the 1/4 circles but that’s probably due to some math formulas I didn’t do right in the SASS, I believe this can be ignored. Hence, This version cannot be used as the official CBC gem.
2. Plain PNG Image (30px x 30px)
|Description: Simple PNG file included in the CSS as a background image. CSS included in main HTML.|
3. Data URI in CSS (30px x 30px )
|Description: I used Nicholas’ tool to create my CSS files including data URI. However there are many tools to help you create your own data URI encoded files.|
You can see from the browser screenshots above that all logos look pretty much the same to the user.
The results show that the median load times serving the logo as pure CSS in comparison to the Data URI solution are being almost the same whereas the logo as a background image in CSS took the longest.
I looked at the base64 string and thought how big it would be if I had used a bigger image. So I googled and found the following “It’s not worth to use data URIs for large images. A large image has a very long data URI string (base64 encoded string) which can increase the size of CSS file.” (source). I decided to test it out myself. So, my next question was “How would the test above turn out if I used a bigger CBC gem logo”. I picked a width and height of 300px. While I was preparing the 300px x 300px pages, I also decided to create another version of the Data URI, not part of the CSS but inline within the HTML.
1. Logo in pure CSS (300px x 300px )
There was not much of a different in terms of markup and setup for the pure CSS and PNG in CSS version. I updated the SASS for the cbcgem.scss to accomodate a logo of 300px x 300px instead of 30px x 30px. The file size didn’t change much because it is all based on math calculations
2. Plain PNG Image (300px x 300px )
Instead of loading gem-30.png, I created a version gem-300.png and updated the CSS.
3a. Data URI in CSS (300px x 300px)
I noticed that the size of the Data URI encoding as expected increased dramatically from a 30px x 30px encoded image to a 300px x 300px image (almost 10 times, see full view of screenshot on the left).
3b. Data URI inline within HTML (300px x 300px)
I used WebPagetest again to run 10 tests to find the Median.
Observations & Take-Aways
- Creating simple shapes in CSS (via SASS) is highly scalable because it doesn’t influence the size of the CSS file significantly. The size of the CSS file won’t change much if I choose to produce a 300px x 300px logo or a 10px x 10px logo. For all tests performed this solution seems to be the most efficient and fastest one.
- I didn’t find the observation true that if the encoded image is bigger than 1-2kB it wouldn’t be worth using Data URI to improve performance. When looking at the last test round (300px x 300px), we can see in the results that the page with the encoded image is still faster than the page with a 300px x 300px PNG image.
- It is interesting to note that the inline data URI version is faster than the data URI CSS version (and almost as fast as the pure CSS version). Having to serve 2 HTTP requests with a total size of 4kB, the median load time was faster than the one serving the data URI via CSS.
Further Readings and References
- Data URIs explained (by Nicholas C. Zackas)
- Data URI Sprites
- Data URIs explained
- High Performance Web Apps. Use Data URIs. Theory
- High Performance Web Apps. Use Data URIs. Practice
CBC Gem 30px x 30px
- Pure CSS: http://www.webpagetest.org/result/130417_5Q_179
- PNG: http://www.webpagetest.org/result/130417_4S_181
- Data URI: http://www.webpagetest.org/result/130417_9S_16K
CBC Gem 300px x 300px
How realistic is it really that a script that you didn’t even write could dramatically slow down your site and other major sites as well? Keep reading….scripts can slow down sites and it hurts to watch!
I watched the Fluent talk by Steve Souders from 2012 about High Performance Snippets (must-watch for all SPOF fans) and got inspired to test out how an “innocent” 3rd party script (btw. I call them 3rd party monsters), not loaded properly could result in a single point of failure (SPOF) and to make a site very slooooooow to load.
Developers are always proud and optimistic about their code, and when it comes to including 3rd party scripts, basically code they don’t usually touch, they assume those 3rd party providers like Google never go down, a non-responsive ad server like DoubleClick won’t hurt or Twitter won’t have server failures. 3rd party script developers try their best to make it easy and painless for us to include their high performing scripts into our sites. That’s a fact. True but also not true. They can only do so much. If you don’t properly include the script on your end and their service goes down, their high performing code won’t be able to help you at all. The rule of thumb is to include those scripts asynchronously. That way you make sure that your content won’t be blocked from rendering in case the 3rd party service is down.
It’s kind of like the elephant in the room to me; you pray e.g. that Twitter doesn’t go down meanwhile you are too afraid to test it out or are over-confident that it won’t break your page or you basically don’t really know how you would test this scenario in the first place. Am I right? Well, what if you could run a quick test on a web site and pretend all of their 3rd party scripts and providers were down. Let’s play the “3rd party scripts game“: would your web site still render…how confident are you?
Simulating SPOF – Slow down your own site until it really hurts
Are you ready for this? First, edit your hosts file to point to a blackhole IP address for simulation (I used the blackhole IP address Steve shared in his talk on slide 9).
sudo vi /etc/hosts
While setting up my test, I don’t want to play the really bad gal (yet) and assume all 3rd party providers were down. I’d like to start with the simplest but yet most used and harmful domain ads.doubleclick.net. A lot of web sites include ads and use DoubleClick.
So let’s use this domain for our blackhole test. By all means, you can add more 3rd party scripts to your hosts file.
// add this line to your hosts file
Once you’ve updated your host file, remember to flush your DNS cache after.
Now, open your browser (with cache disabled so your browser is not using any DoublClick scripts from the cache). Type in your site’s URL and be prepared for the worst. How long will it take for the website to load?
That’s a very easy (scary) and quick way of evaluating what is on your critical rendering path and obviously (now) what should not be on it anymore!
I ran this test on our site and let me tell you, it hurt. Period. It took almost 1.5 min for cbc.ca to display useful content faking that DoubleClick was down. The browser finally gave up.
I wasn’t ready to stop the game. I wondered if it’s just our site that doesn’t properly handle the outage of one single domain such as ads.doubleclick.net. So I continued and tried the following random websites and measured the time it took so see useful content on those.
|URL||Time past to see useful content|
|http://www.amazon.com||Fine, didn’t seem to use DoubleClick|
|http://www.cnn.com||Fine, they seemed to be doing the proper handling|
|http://www.facebook.com||Surprise, surprise Facebook doesn’t use DoubleClick. They use their own, so no real delay here.|
If you don’t want to edit your hosts file and want to get more concrete waterfall and timing information as well as video captioning, try out what Steve Souders suggested in his Fluent talk by using the scripts (now SPOF) box at webpagetest.org to include DNS changes. The results will give you great details on how the website performed, with and without SPOF.
Note: I’ve tried WebPagetest SPOF myself and didn’t notice a big difference between non-SPOF and SPOF version; my suspicion is that WebPagetest might not be using empty cache for SPOFs setting. The tests I ran manually on my local machine showed more visible negative impact of the SPOFs (I shall confirm this).
3rd party scripts are everywhere
It was verified last month that 18% of the world’s top 300K URLs load jQuery from Google hosted libraries. So that means in theory if that service goes down and a web site uses JQuery from ajax.googleapis.com (and doesn’t have a fallback), the site might not work at all. Isn’t that scary? If you develop for a web site that already uses a CDN, don’t use Google’s CDN for scripts like JQuery. Avoid those 3rd party dependencies as much as possible.
I ran two queries on my local HTTP Archive database (dump from March 2013) and followed the same filter that Steve Souders used above. I restricted the query to only look at 292, 297 distinct URLs from the March 1 2013 crawl (with their respective unique pageid’s). I wanted to see how many of the top 300K URLs use Twitter widgets and any sort of Facebook scripts (without a distinction if they were loaded synchronously or asynchronously).
13% of the Top 300K URLs include Twitter scripts somewhere on their page.
29% of the Top 300K URLs include Facebooks scripts somewhere on their page.
Feel free to extend this exercise to include more 3rd party domains.
Cached 3rd party scripts
You can’t really rely much on the cache settings of your 3rd party scripts to ignore their outage if it happens for less than a few hours. 3rd party providers tend to set a very low cache time on their scripts to make it flexible for them to change the file frequently.
That setup plays against you in the case where you don’t load 3rd party scripts asynchronously. For example Twitter’s widget.js has a cache time set to 30 mins (only). I wonder what change could be so important for Twitter that can’t wait for more than 30min to be loaded on sites consuming this widget.js file.
So imagine the following: You go to a site with the Twitter widget loaded synchronously at the top of the page (bad!) at 9 AM (getting the latest, freshest version of widget.js). Twitter goes down at 9:10 AM. You go back to the site you visited at 9 AM, now at 9:15 AM, everything is still fine, you won’t see any problems because you are getting the cached Twitter widget script from the browser cache. What if Twitter is still down at 9.40 AM and you visit the same page again, you now are past the cache modified time and your browser will request a new version of the Twitter script, trying to reach the Twitter server that is still down. You are now getting a time out response for the Twitter script that (with the setup described above) will block the page content from rendering. Bottom line, you wouldn’t be able to see any content until Twitter is back up (and the cache has expired). It’s easy to check those cache times yourself, e.g. use Chrome dev tools and check out the response headers from those 3rd party scripts.
The screenshot below shows Twitter and Facebook’s cache-control settings:
In order to really focus on your site’s performance, you need to isolate (potential bad) performance of 3rd party monsters (the ones that you decided to invite to your site). Don’t make your users wait for your own content if a 3rd party provider is down.
I read “mobile is not different” and I childishly take it personal – Why? – I dig deeper as if I was my own therapist – Why does it affect me the way it does – It feels like hopeful idealism and the need to generalize complicated things. Not a bad idea, but only if I could take that 2MB desktop site and serve it to all mobile users and think they would be happy…my job would be done! It’s not that easy, when developing web sites, you need to overcome many more obstacles for mobile than for desktop sites that are served on a high-speed, crazy powerful CPU device, a.k.a. desktop computer able to present any kind of content (text, image, audio or video). I wish I didn’t have to worry so much about performance, formats or codecs, I wish I didn’t have to think about latency and bandwidth issues, packet loss, data usage or energy consumption when delivering pages to small battery-driven devices, a.k.a. smart phones. I wish the performance budget we manifest for page size and load times would be the same for desktop and mobile, well on “one web”.
I am a big fan of consolidating so if we want to consolidate “everything web” into “one web” let’s consolidate the “proper” way then, make the “desktop” or call it “one” web follow the same strict rules that mobile or any other platform has to follow. Let’s clean up this mess (but my only wish), let’s do it properly this time please….!
What does “one web” mean to us? Deliver content to all devices, make it accessible and working for all platforms – Check, yes!
In order to get there, can we just pick one platform, develop for it and assume all the other ones will just magically start working? – Check? Unfortunately no.
Technically and realistically, I have a problem wrapping my head around this term of “there is only one web”, “mobile is not that different” or “there is no mobile web”. It is though, unless I am misunderstanding what “one” means.
I think we all perceive the notion of “one web” differently, depending on what issues we want to solve and what job title we own at present time. For example, a performance advocate would say “One web – I wish one common web to develop for, no screen real estate issues, load time or page sizes issues when developing for mobile devices! Yah!” But that’s not the case. You have way more flexibility and allowance on browser with an high-speed home internet connection. Let’s continue, if you ask the sponsor of the site or a content strategist, they’d say “yeah, one web, I want e v e r y t h i n g and I want it e v e r y w h e r e” – Is that what people mean by “one web”?
I’m not sure if we can generalize so much. Think about it, how often do we use a 3G connection on our desktop browser? Or for example, data plans for cell phones (in Canada at least) cost a lot, and going over the usage allowance by e.g 100MB costs you way more on your mobile data plan than going over 100MB on your high-speed home internet package. Also, we can’t make use of touch gestures on a desktop computer (yet) the way they come in handy e.g when swiping through photos on a mobile device.
Also, what about context aware strategies and sites. While your big iMac might want to show you all 35000 clothing items served as high-resolution photos, as a data plan payer, I would appreciate if the smart developers would not send those to my mobile device because all I want to do at the bus stop is to see where the nearest stores is and their opening hours.
Stephanie Rieger has talked about the trouble with context before. And how does “Mobile First” fit in here? Does that mean that Luke wrote a whole book for nothing if mobile is not different or should be a platform to value anymore?
It’s about adaption, no?
Let the experts comment, the W3C Mobile Web Best Practices talk about “one web” as follows:
One Web means making, as far as is reasonable, the same information and services available to users irrespective of the device they are using. However, it does not mean that exactly the same information is available in exactly the same representation across all devices. The context of mobile use, device capability variations, bandwidth issues and mobile network capabilities all affect the representation.
Hands down – I totally agree with that.
I would love to not make an iWatch (?) or iPhone or a SmartTV “different” when it comes to designing and developing web experiences for them but unfortunately they come with different challenges to deliver the same web content. When developing for touch devices you might want to use gestures, maybe you don’t want to load those gestures for your non-touch SmartTV. Your UX might break because your web site design and screen reale state rely on gestures. Your iMac might not need to know where you’re physcially at right now unless you’re taking it with you (it’s so pretty I know) while passing a Starbucks store that has free “grande iced half caf triple mocha latte macchiato” today. Do you think you would want to know about this offer while sitting with a glass of red wine, at night, at home?
May I take a stab at this and rephrase this a bit. There is the web and it is accessible and part of more and more devices (toaster, I look at you, yes I am waitin’ ….), all different in their setups, browsers, their connection limitations, their size, their CPU. Of course you need to adapt and adjust the web to each and every platform because they are different but sometimes also share characteristics. The user experience of viewing a website on a 320px wide screen in contrast to an 50inch screen is different. I believe you still have to meet different requirements at least from a design perspective.
Or even see it the other way around. Value the differences and benefit from them. Mobile devices are smarter than desktop devices. Use their advantages to your own advantages, why wouldn’t you?
I am not saying that anybody I’ve mentioned or cited in this post is wrong, we all have different perspectives and problems to solve. On that note, I’d appreciate constructive criticism because in my opinion, that only shows that we actually end up caring and worrying about the same issue, don’t you think? It’s a good thing.
In an ideal world, the web just works everywhere and serves everything but I fear we are not there yet. We sure can work towards that by creating solid back-end systems with solid and structured content and media sources that each and every platform can pull from whenever and however they want.
It’s not that “mobile is not different”, it is that “platforms are different” or “mobile is just another platform”.
Httparchive.org is an excellent tool to track, monitor and review how the web is built. You can dig into trends around page size, page load time, CDN usage, distribution of different mimetypes and many other stats.
You can download an HTTP Archive MySQL dump and the source code from the download page and play around yourself with the current data. For example, do what Stoyan Stevanov did by asking yourself some questions: “Hm, I wonder what are common mime types these days”. Once you’ve setup the database, you can easily query anything you want.
However, what I personally find the most intriguing and fun is applying all of this to sites of of your choice. Alright, let’s break this down: if you’re famous and your site is listed under the Top * Alexa sites, then you can use the official dump, if your target site is a wee bit less famous and not part of any of the crawled sites, you might want to start using your own database and local instance of HTTP Archive. That way, you can run this handy tool on any of the web sites you want to test.
Things to consider before you get started
You need MySQL, PHP and your own webserver running. If you choose to run your own private instance of WebPagetest, you won’t have to request an API key. I decided to ask Patrick Meenan (pmeenanATwebpagetestDOTorg) for an API key with limited query access. That’suffcient for me for now, if I ever wanted to use more WebPagetest runs per day, I’d probably want to setup a private instance of WebPagetest. I’ve done this before but my computer had to be replaced, and I haven’t had the time after to set this up again.
- Check out the latest source code
- Get the latest DB schema and some real data from here
- settings.inc: Setup your database info
- dbapi.inc: Setup of table names (you can leave this mostly as is)
bulktest: That’s the folder you really want to understand and work with when setting up your own little HTTP Archive baby.
- bulktest/README.txt: This file gives you a general intro on how to use the folder, I recommend to read this.
- bulktest/bootstrap.inc: In case you choose to us a private API key for WebPagetest, you will need to update this file with the provided key
To run a nice little batch, you want to execute the following scripts after each other via CLI (default setup for security reason)
- bulktest/batch_start.php: This script takes pre-defined list of URLs (importurls.php) that you can specify or change. By default it’s downloading the latest Alexa list (downloadAlexList()) and imports those into the urls table. I’ve changed this so it’s picking up my own csv file with the urls I want to crawl but you can also customize this the way you want it (default setup needs to run via CLI)
- bulktest/batch_process.php: Run this as often after each other until you get confirmation that your runs were successfully recorded (default setup needs to run via CLI)
- bulktest/statscompute.php: This is needed for the rendering of the stats under your local URL, e.g. http://localhost/httparchive (default setup needs to run via CLI)
More detailed steps on how to install HTTP Archive can be found under the blog post Setting up HttpArchive private instance. As suggested by the README.txt file and this blog post, it’s probably useful if you setup cronjobs in your environment to automate the batch steps.
Front-end piece: Visualizing your trends and stats by filling the charts
Congrats! Assuming you’ve successfully setup your own HTTP Archive instance – wasn’t that fun and the bit of pain worthwhile? Now you can start viewing those charts and investigating trends and stats targeted to your defined URLs. The beautiful thing about having your own instance is that you can be your own master of data visualization: you can now create additional charts beside the ones that came out of the box provided by the default HTTP Archive setup.
From now on, the sky is the limit. Nobody can stop you now, my friend – you can even run some kick-ass raw database queries if you don’t really care much about the front-end visualization (I do ;))
Back-end piece: Querying the database directly
Sometimes, you want to get some questions answered without creating a pie or a chart. That’s when you can make use of the MySQL tables directly that have been setup for you (via schema sql file and filed by your batches).
Let’s run a simple query on the requests table.
For example, some of our sites use YUI, some use JQuery – but we would really like to avoid having pages serve both.
A simple sample query like the one below could help identify those sites:
select req_referer from requests where url like '%/i/l/yui%' or url like '%jquery-%.js' group by req_referer
Be prepared, some setup time is required
I’m not going to lie, it took me some after-work evenings, many debug statements via PHP to set everything up so I could run proper batch_start and a proper batch_process commands and fill in those pies and trends. Here are a few things to watch out for
- I hadn’t installed pcntl with my PHP version, so I needed to set this up first. You will need this to run batch_process.php. Installing pcntl for php on osx Lion blog post helped a lot – Thank you Jacob!
- You might have to adjust some of the tables values, I got lots of mysql insert/update errors regarding default values not set for certain fields
- After I received my API key, I still had to change the WebPageTest URL after Patrick pointed me to the correct URL (Thanks again). The $gWPTUrl variable was set to http://httparchive.webpagetest.org as default instead of http://webpagetest.org in settings.inc
- Some of the tables require you to have a temp/dev version of it as well, e.g. requests, urls, statsdev etc. Some of the scripts look for e.g. requestsdev. You might have to copy a few of the original tables during setup process. You can setup the naming convention in dbapi.inc
Where am I at? Well, I just finished a few successful batch_processes on a selected number of URLs. It’s fun to monitor trends based on the URLs I put in. I will be collecting more ideas and uses cases over the next few months, possibly also adding some more charts applicable to my needs.
If time permits, I hope to be sharing more of my customization and use cases of HTTP Archive at this year’s Velocity conference in San Jose. And if not there, I’ll try to update this blog post as best as possible. If you have any questions or suggestions, please leave a comment below.
I am always happy to receive feedback or happy help out with some roadblocks while setting this all up.
- sundergs for their helpful blog post Setting up HttpArchive private instance
- Stoyan’s post http://www.phpied.com/digging-into-the-http-archive/
- Patrick Meenan for providing me with a WebPagetest API key and helping sort out some API call issues I had