<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mozilla Web Development &#187; Web Development</title>
	<atom:link href="http://blog.mozilla.com/webdev/category/web-development/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.mozilla.com/webdev</link>
	<description>Everybody Likes Ninjas</description>
	<lastBuildDate>Wed, 01 Feb 2012 16:41:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Today! Mozilla Webdev &#8220;Ask Me Anything&#8221; (AMA) on Reddit!</title>
		<link>http://blog.mozilla.com/webdev/2012/01/20/today-mozilla-webdev-ask-me-anything-ama-on-reddit/</link>
		<comments>http://blog.mozilla.com/webdev/2012/01/20/today-mozilla-webdev-ask-me-anything-ama-on-reddit/#comments</comments>
		<pubDate>Fri, 20 Jan 2012 09:00:23 +0000</pubDate>
		<dc:creator>Fred Wenzel</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/?p=2437</guid>
		<description><![CDATA[As promised, today, a bunch of Mozilla Webdevs are on reddit to answer your questions! For more information, check out the announcement. Click here to get to the Mozilla Webdev &#8220;Ask Me Anything&#8221; on Reddit. We will be there from 10am Central European Time to the evening, Pacific time, so in total about 18 hours. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.mozilla.com/webdev/2012/01/05/coming-up-webdev-ask-me-anything-ama-on-reddit/">As promised</a>, today, a bunch of Mozilla Webdevs are on reddit to answer your questions! For more information, check out the <a href="http://blog.mozilla.com/webdev/2012/01/05/coming-up-webdev-ask-me-anything-ama-on-reddit/">announcement</a>.</p>
<p><a href="http://www.reddit.com/r/IAmA/comments/oonrg/iama_member_of_the_mozilla_webdev_team_ama/"><strong>Click here to get to the Mozilla Webdev &#8220;Ask Me Anything&#8221; on Reddit.</strong></a></p>
<p>We will be there from 10am Central European Time to the evening, Pacific time, so in total about 18 hours. We hope this way people in most time zones will get the chance to get their questions answered.</p>
<p>Come by and ask us all you never dared to ask but always wanted to know!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2012/01/20/today-mozilla-webdev-ask-me-anything-ama-on-reddit/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Timing AMO user experience</title>
		<link>http://blog.mozilla.com/webdev/2012/01/06/timing-amo-user-experience/</link>
		<comments>http://blog.mozilla.com/webdev/2012/01/06/timing-amo-user-experience/#comments</comments>
		<pubDate>Fri, 06 Jan 2012 23:09:28 +0000</pubDate>
		<dc:creator>Andy McKay</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[statsd]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/?p=2410</guid>
		<description><![CDATA[There are lots of ways to measure the performance of a site. On addons.mozilla.org we measure a few of them: how long it takes to render pages, the cache performance and responsiveness for content delivery networks globally. But with the advent of the navigation timing API in Firefox 7 we&#8217;ve been able to add the [...]]]></description>
			<content:encoded><![CDATA[<p>There are lots of ways to measure the performance of a site. On <a href="http://addons.mozilla.org">addons.mozilla.org</a> we measure a few of them: how long it takes to render pages, the cache performance and responsiveness for content delivery networks globally. But with the advent of the <a href="http://www.w3.org/TR/navigation-timing/">navigation timing API</a> in <a href="http://hacks.mozilla.org/2011/09/whats-new-for-web-developers-in-firefox-7/">Firefox 7</a> we&#8217;ve been able to add the most important measurement of all &#8211; the actual performance in the browser.</p>
<p>Along with a few other Mozilla sites, we&#8217;ve been using <a href="https://github.com/jsocol/pystatsd">pystatsd</a> and Graphite for a while. This produces useful graphs of the site health and performance. For example, this graph plots HTTP responses we serve out from Python (this is not the amount of traffic to our site which is much larger).</p>
<p><a href="http://blog.mozilla.com/webdev/files/2012/01/Screen-Shot-2012-01-06-at-2.10.46-PM.png"><img class="alignnone size-full wp-image-2415" title="Traffic to addon.mozilla.org" src="http://blog.mozilla.com/webdev/files/2012/01/Screen-Shot-2012-01-06-at-2.10.46-PM.png" alt="" width="585" height="307" /></a></p>
<p>To facilitate using the timing API we wrote a module between statsd and Django called <a href="https://github.com/andymckay/django-statsd">django-statsd</a> that, amongst other things, provides a way to interface between the browser and Python backend. The library has support for <a href="https://github.com/yahoo/boomerang">boomerang</a>, a great front end timing library. I quickly wrote a much simpler service called <a href="https://github.com/andymckay/django-statsd/blob/master/django_statsd/static/stick.js">stick</a>, which sends a small subset of timings that we want.</p>
<p>Using stick is straightforward &#8211; once you&#8217;ve setup your Python backed and included your JavaScript, you call it in your page. For example:</p>
<pre>stick.send('https://to.your.site/record')</pre>
<p>The API returns with timestamps for each of the events. To give us meaningful numbers, we then subtract the timestamp for each of the events from <code>navigationStart</code> so we can tell the timings relative to that start point. And here&#8217;s the end result in our Graphite server:</p>
<p><a href="http://blog.mozilla.com/webdev/files/2012/01/Screen-Shot-2012-01-06-at-2.10.33-PM.png"><img class="alignnone size-full wp-image-2416" title="Navigation Timing" src="http://blog.mozilla.com/webdev/files/2012/01/Screen-Shot-2012-01-06-at-2.10.33-PM.png" alt="" width="585" height="309" /></a></p>
<p>For internal sites we collect 100% of the data. However, on our live site we get quite a lot of traffic, so we&#8217;ve rolled this out by collecting only 1% of traffic. We&#8217;ll start increasing this percentage once we are confident this won&#8217;t be causing problems. We&#8217;ll also be adding it to the about:addons page which gets quite a bit of traffic.</p>
<p>We&#8217;ll be tweaking things to ensure we pass through the right numbers and interpret them correctly. The amount of data is probably too low to be useful, right now, but I can&#8217;t help but wonder what the peak around 12.30pm today was&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2012/01/06/timing-amo-user-experience/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Coming up: Webdev &#8220;Ask Me Anything&#8221; (AMA) on reddit</title>
		<link>http://blog.mozilla.com/webdev/2012/01/05/coming-up-webdev-ask-me-anything-ama-on-reddit/</link>
		<comments>http://blog.mozilla.com/webdev/2012/01/05/coming-up-webdev-ask-me-anything-ama-on-reddit/#comments</comments>
		<pubDate>Fri, 06 Jan 2012 00:42:59 +0000</pubDate>
		<dc:creator>Fred Wenzel</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/?p=2378</guid>
		<description><![CDATA[Update, Jan 20: The Reddit AMA is going on today! Click here to join us and ask questions! As web developers at Mozilla, we take pride in making web applications that are used by millions of people every day. We work hard to promote the Open Web, both by showing off what the latest in [...]]]></description>
			<content:encoded><![CDATA[<p><em>Update, Jan 20:</em> The Reddit AMA is going on <strong>today</strong>! <a href="http://www.reddit.com/r/IAmA/comments/oonrg/iama_member_of_the_mozilla_webdev_team_ama/">Click here to join us and ask questions!</a></p>
<hr/>
<p>As <strong>web developers at Mozilla</strong>, we take pride in making web applications that are used by <a href="https://addons.mozilla.org">millions of</a> <a href="http://mozilla.org">people</a> <a href="http://support.mozilla.org">every</a> <a href="http://developer.mozilla.org">day</a>. We work hard to promote the Open Web, both by showing off what the latest in web technology can do and by actively developing our projects in the open: as <a href="https://github.com/mozilla/">open-source projects on github</a>.</p>
<p>Whenever we go to meetups, conferences, or chat with community members, people ask all sorts of questions, like:</p>
<ul>
<li>How do you make sure your websites are snappy for users across the globe?</li>
<li>I found a bug in one of your websites and would like to help fix it! How do I get started?</li>
<li>What frameworks do you use? And how many servers do you run certain projects on?</li>
<li>Why are you all <a href="http://www.flickr.com/photos/morgamic/5856161522/">so good-looking</a>?</li>
</ul>
<p>To open the conversation to a larger community, we&#8217;ve decided to run an <strong><a href="http://www.reddit.com/r/IAmA/">&#8220;IAmA&#8221; on Reddit</a></strong>, on <del>Wednesday, January&nbsp;18, 2012</del> <ins><strong>Friday, January&nbsp;20, 2012</strong></ins>.</p>
<p>We&#8217;ll open a thread there in the <em>morning, Central European Time</em>, and will have plenty of people on the Webdev team participating until the <em>evening, Pacific Time</em>, so we should be able to touch most time zones one way or another. </p>
<p>Whether you are a seasoned Mozillian or a &#8220;newbie&#8221; in the community, whether you are a passionate Firefox advocate or pragmatic browser user with an inquiring mind, step by and talk to us! We&#8217;d love to hear from you.</p>
<p><strong>We are Web Developers on the Mozilla Webdev team: Ask Us Anything.</strong></p>
<p>For a link to the actual &#8220;AMA&#8221; post on reddit, visit this blog on <del>January 18</del> <ins>January 20</ins> or <a href="https://twitter.com/#!/mozillaweb">follow us on Twitter</a>. If you have any questions, feel free to comment here or visit us in <a href="irc://irc.mozilla.org/#webdev">#webdev</a> on <a href="http://irc.mozilla.org">irc.mozilla.org</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2012/01/05/coming-up-webdev-ask-me-anything-ama-on-reddit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bringing Firefox Alive with Popcorn.js</title>
		<link>http://blog.mozilla.com/webdev/2011/12/27/popcornjs_is_a-maize-ing/</link>
		<comments>http://blog.mozilla.com/webdev/2011/12/27/popcornjs_is_a-maize-ing/#comments</comments>
		<pubDate>Tue, 27 Dec 2011 21:04:05 +0000</pubDate>
		<dc:creator>Gregory Koberger</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/?p=2327</guid>
		<description><![CDATA[For most people who work with computers for a living, holidays are a time for family… and providing endless tech support. As I was huddled over a half working computer, someone asked what an add-on was. I spend most of my time working with and on add-ons — so the concept seems obvious to me. [...]]]></description>
			<content:encoded><![CDATA[<p>For most people who work with computers for a living, holidays are a time for family… and providing endless tech support. As I was huddled over a half working computer, someone asked what an add-on was. I spend most of my time working with and on add-ons — so the concept seems obvious to me. As I found out this past Christmas, it&#8217;s not to everyone. My otherwise-fairly-computer-literate family had a hard time understanding where the browser ended and websites such as Facebook or Google started — so explaining the concept of add-ons was not nearly as easy as I thought it would be.</p>
<p>While over 85% of people using Firefox have at least one add-on installed, most people still don’t really know what an add-on is or the possibilities they provide. To fix this, the add-ons group teamed up with <a href="https://twitter.com/#!/MozCreative" target="_blank">Mozilla Creative</a> and an outside firm, <a href="http://www.pokelondon.com/" target="_blank">Poke</a>, to create a short video explaining what add-ons are and what they can do.</p>
<p>After seeing the video, we knew we had to do something awesome with Popcorn.js.</p>
<p style="text-align: center;"><a href="https://services.addons.mozilla.org/en-US/firefox/discovery/pane/8.0.1/Darwin" target="_blank"><strong>Watch The Video</strong></a><br />
<em>On the page, click &#8220;Learn More&#8221; to play the video.</em></p>
<p>I recommend watching it in Firefox, since we interact with the browser in ways we couldn’t with Chrome. You can also view the video directly inside Firefox, by going to <em>Tools &gt; Add-ons &gt; Get Add-ons &gt; Click &#8220;Learn More&#8221; / &#8220;Learn More About Add-ons&#8221;</em>.</p>
<h2><strong>Popcorn.js</strong></h2>
<p>For anyone unfamiliar, <a href="http://popcornjs.org/" target="_blank">Mozilla’s Popcorn.js</a> makes it easy to interact with video online using JavaScript. For anyone who has worked with jQuery or a similar library, it&#8217;s a breeze to pick up. Popcorn.js is the code part of <a href="http://mozillapopcorn.org/" target="_blank">Mozilla&#8217;s Popcorn</a>, which is a larger project that aims to supplement video and audio with rich web content.</p>
<p>Setting up Popcorn.js is incredibly simple:</p>
<p><code>var pop = Popcorn('#promo-video');</code></p>
<p>Popcorn.js has a plugin called <em>code</em>, which lets you run arbitrary code when the video hits certain points.</p>
<p><code>pop.code({'start': start, 'end': end, 'onStart': function(){…}, 'onEnd': function(){…});</code></p>
<p>That’s basically all you need to know to get started with Popcorn.js. Everything else we did used regular JavaScript.</p>
<p>Like I mentioned, we only used one of the many plugins. Popcorn.js is incredibly powerful, and our video barely scratched the surface of what <a href="http://popcornjs.org/popcorn-docs/plugins/" target="_blank">Popcorn.js plugins can do</a>.</p>
<h2>Showing Add-ons</h2>
<p>We started by making add-ons fade in on the right side of the video when they are mentioned.</p>
<p><em>Note: You will only see this in the video if your browser window is wide enough.</em></p>
<p><img src="http://blog.mozilla.com/webdev/files/2011/12/show-off.jpg" onmouseover="this.src='http://blog.mozilla.com/webdev/files/2011/12/show-on.jpg'" onmouseout="this.src='http://blog.mozilla.com/webdev/files/2011/12/show-off.jpg'"></p>
<h2>Previewing Personas</h2>
<p>We’re off to a good start. So far, we have add-ons showing up when they’re mentioned in the video. Now, wouldn’t it be cool if the video could interact with Firefox?</p>
<p>At one point the video talks about <a href="https://addons.mozilla.org/en-US/firefox/personas/" target="_blank">Personas</a>, which are basically skins or backgrounds for Firefox. Since it would be incredibly annoying if any site you visited had the ability to skin your Firefox, the ability to trigger a preview is whitelisted to just the Mozilla add-ons sites.</p>
<p><em>Note: You can add other sites to this whitelist by going into Preferences &gt; Security &gt; Exceptions.</em></p>
<p>We thought it would be fun to style the browser with the Persona being mentioned — especially since we’re the only site that is allowed by the browser to do this. We simply fire an event when the video hits a certain point. To make sure the Personas are displayed instantly, we pre-load the Personas when you first click “Play”.</p>
<p><img src="http://blog.mozilla.com/webdev/files/2011/12/persona-off.jpg" onmouseover="this.src='http://blog.mozilla.com/webdev/files/2011/12/persona-on.jpg'" onmouseout="this.src='http://blog.mozilla.com/webdev/files/2011/12/persona-off.jpg'"></p>
<h2>Blown Away</h2>
<p>Later in the video, we see a plane fly across the screen. The papers and other items on the desk start to blow away as this happens. If you scroll down a bit, the add-ons below the video also start to flutter and are eventually caught in a JavaScript-y wind and blown away.</p>
<p>This is done using <em><a href="https://developer.mozilla.org/en/CSS/CSS_animations" target="_blank">-moz-animation</a></em> and <em><a href="https://developer.mozilla.org/en/CSS/transform#section_7" target="_blank">-moz-transform: matrix()</a></em>. Each add-on is given a class of “flutter” (starting at a staggered interval), and the add-ons flutter back and forth until they eventually “blow away”.</p>
<p><script src="https://gist.github.com/1524972.js?file=mozilla-flutter.css"></script></p>
<p>This isn&#8217;t Firefox-only; I just left out the Webkit code in the example for the sake of brevity.</p>
<p>In the next scene, both the backdrop in the video and the add-ons on the site drop back into place.</p>
<p><img src="http://blog.mozilla.com/webdev/files/2011/12/flutter.jpg"></p>
<h2>Other Things to Watch For</h2>
<p>During the scene with the cameras, the page flashes as though a picture with a flash was being taken. The elements are simply hidden, then faded back in.</p>
<p>When the video talks about how add-ons can translate a page, some of the text on the page is translated along with the text in the video. (Note: This only works if you have fewer than three add-ons installed or you watch using <a href="https://services.addons.mozilla.org/en-US/firefox/discovery/pane/8.0.1/Darwin" target="_blank">this link</a>. Otherwise, the top bar is not displayed.)</p>
<p><img src="http://blog.mozilla.com/webdev/files/2011/12/translate-off.jpg" onmouseover="this.src='http://blog.mozilla.com/webdev/files/2011/12/translate-on.jpg'" onmouseout="this.src='http://blog.mozilla.com/webdev/files/2011/12/translate-off.jpg'"></p>
<h2>Uh-oh</h2>
<p>We learned a few things along the way. We used popcorn-complete.js, which we didn’t realize loaded a few CSS, JS and SWF files off of popcornjs.org&#8217;s servers when the file was loaded. We mistakenly DOS’d popcornjs.org, which in turn made the add-ons site load slowly. Thanks to <a href="http://jbuckley.ca/" target="_blank">Jon Buckley</a> and <a href="http://twitter.com/#%21/rwaldron" target="_blank">Rick Waldron</a>, we were able to figure out what was going on and push a fix fairly quickly.</p>
<p>I also owe Chris and Krupa a big hug when I get back to the Mozilla office — they helped me out a ton by finding and fixing a bunch of bugs as we were pushing to production, since I was an unfortunate 30,000 feet in the air as the video was going live.</p>
<h2>Looking Ahead</h2>
<p>I have no doubt that Popcorn.js is going to become huge as HTML5 video takes off. News sites will use it to show relevant links and tweets, fashion sites will link to online stores as a celebrity is shown wearing a dress or shirt, video sites will provide closed captioning and annotations, media sites will use it to sync viewing across multiple computers — the possibilities are endless. I cannot wait to see what Popcorn powered videos people make next.</p>
<p style="text-align: center;"> <a href="https://services.addons.mozilla.org/en-US/firefox/discovery/pane/8.0.1/Darwin" target="_blank"><strong>Watch The Video</strong></a><br />
<em>On the page, click &#8220;Learn More&#8221; to play the video.</em></p>
<p>Since the add-ons site is open source, be sure to <a href="https://github.com/mozilla/zamboni/blob/master/media/js/zamboni/discovery_video.js" target="_blank">view the code</a> if you&#8217;re interested.</p>
<p>As for my family: not all is lost. The next morning I got an excited text from my cousin, who had watched the video. &#8220;Guess what I just did! I installed one of those picture addons on the top!&#8221; Sure, it pains me a bit that a <em>Justin Bieber</em> Persona now graces her Firefox — but hey, it&#8217;s a step in the right direction.</p>
<p>&nbsp;<br />
<img src="http://blog.mozilla.com/webdev/files/2011/12/persona-on.jpg" width="1" height="1"><br />
<img src="http://blog.mozilla.com/webdev/files/2011/12/show-on.jpg" width="1" height="1"><br />
<img src="http://blog.mozilla.com/webdev/files/2011/12/translate-on.jpg" width="1" height="1"></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2011/12/27/popcornjs_is_a-maize-ing/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>An optimization story with Django &#8211; one thousand times faster!</title>
		<link>http://blog.mozilla.com/webdev/2011/12/15/django-optimization-story-thousand-times-faster/</link>
		<comments>http://blog.mozilla.com/webdev/2011/12/15/django-optimization-story-thousand-times-faster/#comments</comments>
		<pubDate>Thu, 15 Dec 2011 18:39:55 +0000</pubDate>
		<dc:creator>Peter Bengtsson</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/?p=2301</guid>
		<description><![CDATA[I&#8217;ve been working on a Django project that is going to be squeezed in as an external application under Pootle which is our tech of choice for the Mozilla Verbatim site which is where all awesome translations happen for Mozilla web projects. (translations for Firefox, Thunderbird, etc. is done by another project which I&#8217;ll blog [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working on a <a href="https://www.djangoproject.com/">Django</a> project that is going to be squeezed in as an external application under <a href="http://translate.sourceforge.net/wiki/pootle/index">Pootle</a> which is our tech of choice for the <a href="https://localize.mozilla.org/">Mozilla Verbatim</a> site which is where all awesome translations happen for Mozilla web projects. (translations for Firefox, Thunderbird, etc. is done by another project which I&#8217;ll blog about more in the next couple of weeks).</p>
<p>In Pootle, there are &#8220;Profiles&#8221; and that&#8217;s where the name and quick stats on contributions is stored. However, what I needed to do was to actually go through every &#8220;Suggestion&#8221;, &#8220;Submission&#8221; and &#8220;Review&#8221; and figure out who has contributed what on what project and language. Every such model has an overridden object manager that always joins on the &#8220;Users&#8221; model thus causing a &#8216;INNER JOIN&#8217; on every simple data query. Thus this would build up an accurate page of who has contributed to what on the fly. </p>
<p>There are 14 projects, 99 languages, 847 users, 37,681 suggestions (and reviews) and lastly 127,226 submissions. The task is to group these first by language and then by project and lastly for each project, list the contributors names in alphabetical order. After some getting used to the data model and where things are located this wasn&#8217;t difficult. I built a prototype that visually represents this and showed it to the stakeholder who wanted this built.<br />
The only problem is that due to the way the Django ORM and Pootle does this is that this takes on average: <strong>11 seconds and involves 2,544 SQL queries</strong>. Yikes!  </p>
<p>After some optimization (helped by my colleague Rob Hudson&#8217;s wonderful <a href="http://pypi.python.org/pypi/django-debug-toolbar">django-debug-toolbar</a>) I was able to turn <strong>11 seconds into 10 milliseconds</strong> (ie. <em><strong>one thousand times faster</strong></em>) and reduce the number of queries <strong>from 2,544 to 7</strong>! All it takes is just having to lessen some of the convenience of Django&#8217;s otherwise super practical ORM and get closer to the &#8220;SQL of things&#8221;. The code doesn&#8217;t express anything in raw SQL and everything is in Python with some very specific loops. </p>
<p>Why 7 queries and not 1, you might wonder. The reason is that the data I need to get to is spread across 7 different tables. Because some of them are large and joins are difficult what I do instead is pick only exactly what I want and need and nothing more. The logic kinda goes like this:</p>
<ul>
<li>Fetch all IDs and their Name (e.g. 52 and &#8220;Arabic&#8221;)</li>
<li>For relevant tables with foreign keys, only fetch its ID, the foreign key ID and keep this in a list or dictionary whose structure implies information</li>
<li>Sort and re-organize these lists and dictionaries in Python</li>
<li>Summarize and replace the IDs with the Names for the final template rendering</li>
</ol>
<p>I think the lesson here is that if your structures are big but not so big that you need a map/reduce job then getting closer to the raw SQL queries and doing the structure juggling in memory, you don&#8217;t need to replace your relational databases with NoSQL or typed raw SQL. Django&#8217;s ORM is fantastic. It&#8217;s slow because it chooses to be convenient but if it needs to be fast it&#8217;s just a few slight API calls away. If you&#8217;re curious, <a href="https://github.com/peterbe/mozilla-pootle-extras/blob/master/views.py">check out the code on Github</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2011/12/15/django-optimization-story-thousand-times-faster/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Guest Post: &#8220;I want to contribute, how do I start?&#8221;</title>
		<link>http://blog.mozilla.com/webdev/2011/11/24/guest-post-i-want-to-contribute-how-do-i-start/</link>
		<comments>http://blog.mozilla.com/webdev/2011/11/24/guest-post-i-want-to-contribute-how-do-i-start/#comments</comments>
		<pubDate>Thu, 24 Nov 2011 19:56:04 +0000</pubDate>
		<dc:creator>Matthew Riley MacPherson</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[community]]></category>
		<category><![CDATA[contributors]]></category>
		<category><![CDATA[guest post]]></category>
		<category><![CDATA[vagrant]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/?p=2287</guid>
		<description><![CDATA[Preface This is guest post from one of webdev&#8217;s awesomesauce community contributors: Nigel Babu. nigelb contributes to a bunch of Mozilla&#8217;s web apps including Firefox Input and Socorro. He writes about Mozilla and open source on his blog and hangs out on #webdev on IRC &#8212; where we often talk about motorcycles. At Mozcamp Asia, [...]]]></description>
			<content:encoded><![CDATA[<h3>Preface</h3>
<p>This is guest post from one of webdev&#8217;s awesomesauce community contributors: <strong>Nigel Babu</strong>. nigelb contributes to a bunch of Mozilla&#8217;s web apps including Firefox Input and Socorro. He writes about Mozilla and open source <a href="http://nigelb.me">on his blog</a> and hangs out on <code>#webdev</code> on IRC &#8212; where we often talk about motorcycles.</p>
<hr />
<p>At <a href="https://wiki.mozilla.org/AsiaCamp2011">Mozcamp Asia</a>, Tim Watts and I talked about contributing to Mozilla Webdev. When I met Tim, he asked me how I got started and what were some of the challenges I faced. This blog post is a summary of those challenges and a few solutions to help new contributors to Mozilla Webdev. This is also a condensed summary of our session, so if you missed it don&#8217;t feel too bad <img src='http://blog.mozilla.com/webdev/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<h2>Finding a Project</h2>
<p>Finding a project to work on is the first baby step. Everything from here down is easier if you know what you want to contribute to; of course, it&#8217;s perfectly normal to be clueless as well. Everyone is mildly lost at this step at first. It helps if you have a clear understanding about what kind of code you want to write. Webdev has lots of different projects requiring different skill sets: Python/Django, JavaScript, HTML/CSS, and PHP are all in use at Mozilla. Almost all new projects require Python and Django knowledge, but we still have a few projects on PHP that you could help with &#8212; like mozilla.org and Socorro. Talk to us in #webdev with what kind of code you want to write, and we can help you find a nice project that needs help. You can start with a smaller project with fewer moving parts if you feel like it&#8217;s too much to take in. But one tip I have is: the bigger the project, the greater the opportunities.</p>
<h2>&#8220;I Don&#8217;t Know What to Do&#8221;</h2>
<p>It&#8217;s not easy to find something to do. I can attest to that. I know I had some trouble as well. Once you have found a project to help with, it becomes easier finding something to do. You could look at bugs with [good first bug] in the whiteboard &#8212; they&#8217;re generally good to start with. Another idea is to follow all the bugs for that project (bugmail can be noisy: set a filter or get ready for inbox explosion), so you can pick new bugs as they come in. Being in the project&#8217;s IRC channel also helps immensely. When fellow webdevs and Web QA learn that you are a new contributor and want something to do, they&#8217;ll be happy to point you to easy bugs or subscribe you to easy ones they see.</p>
<h2>Finding a Mentor</h2>
<p>While finding a mentor is not strictly necessary; however, it helps when you can ping someone to help you. When you find a project, some of the developers on that project are good candidates to mentor you. Feel free to ping the maintainers/developers for help when you are stuck. There are also the Stewards (https://wiki.mozilla.org/Stewards/Webdev) who can help you find a match: don&#8217;t feel shy about asking them to help you out.</p>
<h2>Setting up Your Environment</h2>
<p>Earlier, this was a challenging experience, sometimes it even seemed downright impossible. With the recent work we&#8217;ve done with vagrant, everything is much easier! Almost all <a title="Developing with Vagrant, Puppet, and playdoh" href="http://blog.mozilla.com/webdev/2011/10/04/developing-with-vagrant-puppet-and-playdoh/">new projects have a vagrant-based setup</a> for the development environment and it should be much faster to get you off the ground. When in doubt, ask the project maintainers if there&#8217;s a vagrant setup for that project.</p>
<p>These were the 4 things that I faced and helped me start off. If you are interested in being a contributor and something ticked you off, talk to me &#8212; in the comments or on IRC. Feel free to reach us on <code>#webdev</code> on irc.mozilla.org with any questions or if you want to get started in contributing to Mozilla Webdev.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2011/11/24/guest-post-i-want-to-contribute-how-do-i-start/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Git: Using topic branches and interactive rebasing effectively</title>
		<link>http://blog.mozilla.com/webdev/2011/11/21/git-using-topic-branches-and-interactive-rebasing-effectively/</link>
		<comments>http://blog.mozilla.com/webdev/2011/11/21/git-using-topic-branches-and-interactive-rebasing-effectively/#comments</comments>
		<pubDate>Mon, 21 Nov 2011 15:58:11 +0000</pubDate>
		<dc:creator>kumar303</dc:creator>
				<category><![CDATA[AMO]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/?p=2245</guid>
		<description><![CDATA[When I first joined the webdev group at Mozilla I was a Mercurial refugee who had never used git or github. I was always daunted by git and suddenly I had to learn it really fast!  Fast forward to today and I can&#8217;t imagine working on a highly collaborative project without git or github.  Here [...]]]></description>
			<content:encoded><![CDATA[<p>When I first joined the webdev group at Mozilla I was a <a href="http://mercurial.selenic.com/">Mercurial</a> refugee who had never used <a href="http://git-scm.com/">git</a> or <a href="https://github.com/">github</a>. I was always daunted by git and suddenly I had to learn it really fast!  Fast forward to today and I can&#8217;t imagine working on a highly collaborative project without git or github.  Here is the workflow we use for the <a href="https://github.com/mozilla/zamboni/">addons.mozilla.org</a> project.  I highly recommend it and I&#8217;ll summarize exactly why at the end.  It&#8217;s pretty similar to how I&#8217;ve heard a lot of teams work but has some subtle differences.</p>
<h3>Using topic branches</h3>
<p>The first thing I do is sync up with master and create a topic branch for my new feature or bug fix:</p>
<pre>git checkout master
git pull
git checkout -b add-email-to-install</pre>
<p>Now I have a branch I can commit code into without affecting master.  Git checkout makes it super easy to switch between branches in the same repository clone if I&#8217;m multi-tasking or applying hot fixes.  In addition to git checkout, you can also use <a href="http://book.git-scm.com/4_stashing.html">git stash</a> to switch tasks.</p>
<h3>Commit messages</h3>
<p>It&#8217;s really important to write <a href="http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html">a well-formed git commit message</a>. We always include a ticket number into <a href="https://bugzilla.mozilla.org/">bugzilla</a>, our tracker, so that anyone can get the full back story about a change.</p>
<h3>Ask for a code review</h3>
<p>Once I&#8217;ve added my feature with passing tests I commit my changes, push to my personal fork of the repository, and ask someone on my team to review the code.  On <a href="https://github.com/mozilla/zamboni">addons.mozilla.org</a> we just ping each other in IRC with a link to the commit or a link to the <a href="https://github.com/blog/612-introducing-github-compare-view">compare view</a>.  If no one is around we <a href="http://help.github.com/send-pull-requests/">submit a pull request</a>.</p>
<p>Github has a sweet interface where you can write comments directly on the diff, like this:</p>
<p><a href="http://blog.mozilla.com/webdev/files/2011/11/github-code-review-example2.png"><img class="alignnone size-full wp-image-2251" title="github code review example" src="http://blog.mozilla.com/webdev/files/2011/11/github-code-review-example2.png" alt="" width="557" height="412" /></a></p>
<p>Whoops, another change is needed based on feedback from the code review.</p>
<h3>Fixing up the topic branch</h3>
<p>The nice thing about working in a topic branch is it&#8217;s isolated from master and no one else is tracking that branch so I can use git rebase to create the best commit before merging into master.  Let&#8217;s say I have some commits on my branch like this:</p>
<pre>$ git log --pretty=oneline -2
825d662cc69774e412119e1eb7ae0900c29d89a0 Fix: put code in a transaction
31378788f321b46f5e27f9fb51bdd19365636871 Adds email to the install record (bug #NNNNNN)</pre>
<p>What I really want is to combine those two commits into one.  I can do that with <a href="http://book.git-scm.com/4_interactive_rebasing.html">git rebase &#8212;interactive</a>. I type:</p>
<pre>git rebase -i HEAD~2</pre>
<p>Then I&#8217;ll get a prompt for rebasing my last two changes:</p>
<pre>pick 3137878 Adds email to the install record (bug #NNNNNN)
pick 825d662 Fix: put code in a transaction

# Rebase 194b59d..825d662 onto 194b59d
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#</pre>
<p>If I put the word fixup next to my second commit, it folds it into the first:</p>
<pre>pick 3137878 Adds email to the install record (bug #NNNNNN)
fixup 825d662 Fix: put code in a transaction</pre>
<p>Now I have one commit (it&#8217;s actually a new commit) that contains all of my changes:</p>
<pre>$ git log --pretty=oneline -1
c7846808c8296dd49d49612101aaed7cdfd6d220 Adds email to the install record (bug #NNNNNN)</pre>
<p>Pretty slick, right?</p>
<p>Typically you&#8217;d want to wait until everyone has had a chance to review your code before you start rebasing.  However, git pull requests do handle rebased changes.  You can push -f to your own fork and the pull request will remove the old commits from the conversation and add the new ones at the bottom.</p>
<h3>Merge into master</h3>
<p>When my changes are ready, I can merge my branch back into master.  However, I don&#8217;t need to make a merge commit if there&#8217;s only one commit to merge in.  That would clutter up the logs.  I can do this with a fast-forward merge:</p>
<pre>git checkout master
git merge --ff add-email-to-install</pre>
<p>Now I can close the ticket in our tracker with a direct link to my changes.</p>
<p>Sometimes I might actually make multiple commits on a single topic branch.  In this case I <em>would</em> want to retain the automatic merge commit.  That is, I wouldn&#8217;t do a fast forward merge in the case of multiple commits:</p>
<pre>git merge --no-ff add-email-to-install</pre>
<p>I can then close the ticket with a link to the single merge commit that shows all changes introduced by the branch.</p>
<h3>Fixups, for ninjas</h3>
<p>If you follow this pattern you&#8217;ll become accustomed to frequently fixing up your topic branch. I created a ninja alias for it in ~/.gitconfig like this:</p>
<pre>[alias]
    ...
    fix = "!f() { git commit -a -m \"fixup! $(git log -1 --pretty=format:%s)\" &amp;&amp; git rebase -i --autosquash HEAD~4; }; f"</pre>
<p>When on a topic branch with uncommitted changes I can then type:</p>
<pre>git fix</pre>
<p>That will automatically commit my change and pre-configure the rebase prompt to fold it into the last commit.</p>
<p><strong>UPDATE:</strong> AMO team member Allen Short pointed out in the comments that <code>git fix</code> is the same as <code>git commit -a --amend</code> if you&#8217;re just fixing up the last commit. Awesome!</p>
<h3>Synchronization with master, for ninjas</h3>
<p>If you&#8217;re on a project that has a lot of commit activity you&#8217;ll probably want to rebase your feature branch on top of master often.  I added a ninja alias to ~/.gitconfig for that too:</p>
<pre>[alias]
    ...
    sync = "!f() { echo Syncing $1 with master &amp;&amp; git checkout master &amp;&amp; git pull &amp;&amp; git checkout $1 &amp;&amp; git rebase master; }; f"</pre>
<p>When I&#8217;m on my feature branch and I want to synchronize it with all the latest changes on master, I type:</p>
<pre>git sync add-email-to-install</pre>
<p>The main benefit to syncing a branch before merging into master is that a fast-forward merge won&#8217;t create a new commit.  This helps you safely delete work branches later on since it won&#8217;t look like you have un-merged changes.  It&#8217;s also useful to do a last minute spot check before merging into master: do the tests still pass? do I need to adjust my SQL migration script? etc.</p>
<p><strong>UPDATE:</strong> Fernando Takai posted a simpler version of this in the comments using <code>git checkout -</code> to go back to the last branch you were on. You can then simply type <code>git sync</code> from the branch. Thanks!</p>
<h3>Why resort to all these ninja like git strategies?</h3>
<ul>
<li>Using git blame on a single line of code is more likely to give your team a full picture of all the reasons why that line of code was introduced. For this same reason, we at <a href="https://github.com/mozilla/zamboni/">addons.mozilla.org</a> always link to our bug tracker in each commit.</li>
<li>Your commit log will have a high signal to noise ratio making it easier to skim when looking at a compare view between releases.</li>
<li>Ninjas don&#8217;t make mistakes.  Ever.</li>
</ul>
<h3>Random Notes</h3>
<ul>
<li>Kernel hackers frown on using rebase but that&#8217;s probably because many people are committing to the same files and it&#8217;s important to see what the original starting tree was when work on a new feature started.  For web development, if two members on your team are working on the same line in the same file then your team isn&#8217;t communicating well enough.  I rarely see conflicts on my team that aren&#8217;t resolved automatically by a three way merge.</li>
<li>After committing to master you might discover a mistake.  That&#8217;s fine, make a new commit.  Be sure to <em>never fixup a commit on master</em> because everyone tracking master will be sad!</li>
<li>Where do your fixed up commits go?  They are still there but are detached from any branch and thus get deleted eventually by git&#8217;s garbage collector.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2011/11/21/git-using-topic-branches-and-interactive-rebasing-effectively/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Scrubbing your Django database</title>
		<link>http://blog.mozilla.com/webdev/2011/11/18/scrubbing-your-django-database/</link>
		<comments>http://blog.mozilla.com/webdev/2011/11/18/scrubbing-your-django-database/#comments</comments>
		<pubDate>Fri, 18 Nov 2011 23:05:38 +0000</pubDate>
		<dc:creator>Andy McKay</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/?p=2206</guid>
		<description><![CDATA[This is the second in a series of posts, focusing on issues around open sourcing your Django site and data privacy in Django. You&#8217;ll end up with production data in your Django database and that will likely contain different kinds of data such as: configuration data, required basic data (categories for example), collected data and [...]]]></description>
			<content:encoded><![CDATA[<p><em>This is the second in a <a href="http://blog.mozilla.com/webdev/2011/10/20/open-sourcing-your-django-site/">series of posts</a>, focusing on issues around open sourcing your Django site and data privacy in Django.</em></p>
<p>You&#8217;ll end up with production data in your Django database and that will likely contain different kinds of data such as: configuration data, required basic data (categories for example), collected data and personal user data. There&#8217;s a couple of reasons for taking that production data and copying it off your production servers:</p>
<ul>
<li>for developers and contributors you want a sample copy of the app with some key data in.</li>
<li>for testing or staging servers, you might want to copy down the database from the production server so you can test certain scenarios or load.</li>
</ul>
<h3>Extracting parts of your database</h3>
<p>For the first case, it&#8217;s nice to prepare a minimal copy of the database that contains key data. For example, for those wanting to develop or contribute to <a href="https://addons.mozilla.org">addons.mozilla.org</a> we have <a href="http://micropipes.com/blog/2011/03/29/welcome-to-the-landfill/">Landfill</a> by <a href="http://micropipes.com/blog/">Wil Clouser</a>.</p>
<p>Django comes with a nice facility for loading data, fixture dumping and loading. This can be used to pull data out of your database and then reload it. However the built in <a href="https://docs.djangoproject.com/en/dev/ref/django-admin/#dumpdata-appname-appname-appname-model">Django dumpdata</a> dumps all the records for your model (depending upon your default object manager). That might not be what you want for this scenario. So a useful utility for dumping just the records you want is provided <a href="https://github.com/davedash/django-fixture-magic">Django fixture magic</a> written by <a href="http://blog.mozilla.com/webdev/author/ddashmozillacom/">Dave Dash</a>.</p>
<p>A standard dumpdata looks like this:</p>
<pre>manage.py dumpdata users.UserProfile</pre>
<p>And will dump every <code>UserProfile</code>. By contrast:</p>
<pre>manage.py dump_object users.UserProfile 1</pre>
<p>Will just dump the <code>UserProfile</code> with primary key of 1. Django fixture magic also has a few other useful things such as merging and reordering fixtures.</p>
<p>This allows you to trim a set of fixtures from your live database down quickly. Then developers or contributors can load the key parts of the database that they need from those fixtures.</p>
<h3>Anonymising the database</h3>
<p>Sending the production database downstream to internal developers or internal test sites is a pretty common use case. This process does not require a complete clean of the database, but it does require some cleaning of database. If you stored credit card data, for example, you&#8217;d never want to copy that off your production database.</p>
<p>At Mozilla we use an <a href="https://github.com/davedash/mysql-anonymous">anonymising script</a>, written by <a href="http://blog.mozilla.com/webdev/author/ddashmozillacom/">Dave Dash</a> again. There are few options: to truncate, nullify, randomize or selectively delete. The format is a simple YAML file, for example:</p>
<pre>
   tables:
        users:
            random_email: email
            nullify:
                - firstname
</pre>
<p>This is a snippet from <a href="https://github.com/mozilla/zamboni/blob/master/configs/mysql-anonymous/anonymize.yml">the config script</a> for <a href="https://addons.mozilla.org">addons.mozilla.org</a>.</p>
</p>
<p>When the IT copies the databases down from production, this script is run against the database. Ensuring that when us developers access the backups to investigate certain issues, we&#8217;ll be getting the bits we want and not the bits that might expose user data.</p>
<p><em>In the next blog post we&#8217;ll look at logs and tracebacks.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2011/11/18/scrubbing-your-django-database/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using localtunnel to do web development on actual mobile devices</title>
		<link>http://blog.mozilla.com/webdev/2011/11/10/localtunnel-on-actual-mobile-devices/</link>
		<comments>http://blog.mozilla.com/webdev/2011/11/10/localtunnel-on-actual-mobile-devices/#comments</comments>
		<pubDate>Thu, 10 Nov 2011 17:36:25 +0000</pubDate>
		<dc:creator>Peter Bengtsson</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/?p=2209</guid>
		<description><![CDATA[Surely you&#8217;re convinced too now that developing for the mobile web is important. It certainly is for us here at Mozilla. Mobile web development isn&#8217;t just about making a ultra-slim stripped down version with no images or Javascript widgets. It&#8217;s also about taking regular full powered web applications and making stepwise adjustments to make sure [...]]]></description>
			<content:encoded><![CDATA[<p>Surely you&#8217;re convinced too now that developing for the mobile web is important. It certainly is for us here at Mozilla. Mobile web development isn&#8217;t just about making a ultra-slim stripped down version with no images or Javascript widgets. It&#8217;s also about taking regular full powered web applications and making stepwise adjustments to make sure they work responsively on all mobile devices which means everything from tablets to regular cell phones over 3G. </p>
<p>There are numerous good guides such as this for <a href="http://www.hongkiat.com/blog/designing-for-mobile-devices/">Designing for Mobile Devices</a> and there are great <a href="https://addons.mozilla.org/">add-ons for Firefox</a> such as the <a href="https://addons.mozilla.org/en-US/firefox/addon/user-agent-switcher/">User Agent Switcher</a>. And don&#8217;t miss Jason&#8217;s wonderful blogs from the archive <a href="http://blog.mozilla.com/webdev/2011/05/04/approaches-to-mobile-web-development-part-1-what-is-mobile-friendliness/">part 1</a>, <a href="http://blog.mozilla.com/webdev/2011/05/13/approaches-to-mobile-web-development-part-2-separate-sites/">part 2</a>, <a href="http://blog.mozilla.com/webdev/2011/05/27/approaches-to-mobile-web-development-part-3-responsive-design/">part 3</a> and <a href="http://blog.mozilla.com/webdev/2011/06/27/approaches-to-mobile-web-development-part-4-%e2%80%93-a-hybrid-approach/">part 4</a>. But ultimately, nothing beats actually testing it on a real physical device. </p>
<p>That&#8217;s where <a href="http://progrium.com/localtunnel/">localtunnel</a> (by <a href="http://progrium.com/">Jeff Lindsay</a>) comes in. What it does is that it binds a local port (e.g. port 8000) on your desktop to a real domain name (e.g. xyz123.localtunnel.com) all over <a href="http://en.wikipedia.org/wiki/SSH">SSH</a>. So, you start your local Django server locally and then start a local tunnel and after waiting 1-2 seconds you get a real domain name to type into your iPhone, Android, Nokia smartphone, whatever and you can test away as much as you like. </p>
<p>Granted, you can use it not just for mobile device development but for anything such as telling a colleague over IRC to visit your site running locally on your laptop. And also, if you are in an office where you connect to the same local WiFi with your laptop as you do with your mobile device then you can just use a local IP address. But that&#8217;s often not the case especially when working with people in different locations. </p>
<p>An added, yet strange, benefit with using localtunnel to test your mobile device is that it is naturally slow. That&#8217;s because the traffic has to go via SSH over the network and your local network won&#8217;t be as fast as a real data center. However, in real life, the network connection will be slow when using a mobile device so it&#8217;s important to see how your mobile web app behaves with a limited bandwidth.  </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2011/11/10/localtunnel-on-actual-mobile-devices/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>From 80 Seconds to 6: Optimizing Our Asset Compression</title>
		<link>http://blog.mozilla.com/webdev/2011/10/25/go-speed-racer/</link>
		<comments>http://blog.mozilla.com/webdev/2011/10/25/go-speed-racer/#comments</comments>
		<pubDate>Tue, 25 Oct 2011 23:15:29 +0000</pubDate>
		<dc:creator>Gregory Koberger</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/webdev/?p=1994</guid>
		<description><![CDATA[Before pushing our CSS and JavaScript assets to our CDN, we run them through jingo-minify to concat and minify the files, as well as cache bust them and any resources (such as images) contained inside them.  Turns out, this was by far the slowest part of our push process — it took  between 80 and [...]]]></description>
			<content:encoded><![CDATA[<p>Before pushing our CSS and JavaScript assets to our CDN, we run them through <a href="https://github.com/jsocol/jingo-minify">jingo-minify</a> to concat and minify the files, as well as cache bust them and any resources (such as images) contained inside them.  Turns out, this was by far the slowest part of our push process — it took  <strong>between</strong> <strong>80 and 160 seconds </strong>for addons.mozilla.org (AMO) assets.  It wasn&#8217;t a huge priority, since most of the time this happens in the background and nobody really notices.  However, I wanted to see how fast I could get it.<span id="more-1994"></span></p>
<p><em>Note: All times are based on AMO being compressed on a MacBook.  On our build server, those 80 seconds took about 160 seconds.  Most times are averages and/or estimates, and are based on an initial 80 seconds.<br />
</em></p>
<h3>UglifyJS and clean-css (-43s)</h3>
<p>This was the low hanging fruit.  YUICompressor is slow.  We managed to cut off over half our original time by switching to <a href="https://github.com/mishoo/UglifyJS">UglifyJS</a> for JavaScript and <a href="https://github.com/GoalSmashers/clean-css">clean-css</a> for CSS, both of which are written in Node.  This switch means less errors (we were getting a lot with YUI), smaller files and much faster build times — and none of us are sad to see our Java dependency disappear.  (I benchmarked all our options before we chose them.  If you&#8217;re interested, you can <a href="https://github.com/gkoberger/compare-minifiers">run them yourself</a>.)</p>
<p>Unlike YUICompressor, UglifyJS builds an abstract syntax tree, compresses the AST, then converts the whole thing back to (minified) JavaScript.  So far, this has meant that UglifyJS has been much more resilient against our sometimes-misformed JavaScript. Missed semicolons no longer take down the whole site&#8217;s JavaScript. The build times are about the same by my benchmarks, but the results are far superior. [<a href="http://pastie.org/2564736">JS Benchmark results</a>]</p>
<p>Clean-css works much like YUI (lots of regex), which is a bit unfortunate.  However, it does so much faster — 10x as fast, to be exact.  [<a href="http://pastie.org/2571130">CSS Benchmark results</a>]</p>
<p><strong>Original Time:</strong> 80s<strong><br />
New Time: </strong>37s<br />
<strong>Difference:</strong> -54%</p>
<h3>Saving File Hashes (-2s)</h3>
<p>We were fetching the hash (originally the git commit id, now hash of the actual file) for the same files fairly often.  By sticking the already-computed hashes into a dict, we were able to shave off a small but significant amount of time.</p>
<p><strong>Original Time:</strong> 37s<strong><br />
New Time: </strong>35s<br />
<strong>Difference:</strong> -11%</p>
<h3>Use File Hashes For Image Cache Busting (-12s)</h3>
<p>When I first wrote cache busting for individual images in our CSS files, I used the image&#8217;s most recent git commit as the cache-busting hash.  As it turns out, your script gets really slow when you&#8217;re looking up the history for dozens of images using <a href="http://gitorious.org/git-python">GitPython</a>.  So, I switched to using a hash of the file.  The end result is the same — the hash is only updated if the image is changed.  However, using file hashes instead of git commits shaved a good chunk of time off our build process.</p>
<p><strong>Original Time:</strong> 35s<strong><br />
New Time: </strong>23s<br />
<strong>Difference:</strong> -34%</p>
<h3>Only Minify When Necessary (up to -17s)</h3>
<p>I got down to 23 seconds, and was stuck.  The biggest time sink in the process was the minifying of files, which I couldn&#8217;t do much about without touching the UglifyJS or clean-css code.  Even if I wanted to, I doubted I could do much to speed either of them up.  After thinking about it for a bit, I realized that there was no reason for us to be minifying every file each time.  We only needed to minify the files that had actually changed.  So, jingo-minify now writes the concatted file out to a temporary location, and compares it to the preexisting concatted file.  If they&#8217;re the same file, we have no need to re-minify.</p>
<p>Since we push to preview every time anyone commits and most commits don&#8217;t modify more than one or two JS or CSS files (if any), we can save between 15 and 17 seconds each time.</p>
<p><strong>Original Time:</strong> 23s<strong><br />
New Time: </strong>6s<br />
<strong>Difference:</strong> -74%</p>
<h3>Overall Results</h3>
<p>So, that&#8217;s how I managed to speed up our asset compression by over an order of magnitude —<strong> from 80 seconds down to about 6</strong>.  <em>(Note: Time is based on the script on a MacBook.  On the slower build server, it&#8217;s closer to 160 seconds down to 9.)</em>  Hopefully this means much smoother pushes for AMO, SUMO and anyone else using jingo-minify to compress their assets.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/webdev/2011/10/25/go-speed-racer/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

