<?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>All Night Diner &#187; code</title>
	<atom:link href="http://micropipes.com/blog/tag/code/feed/" rel="self" type="application/rss+xml" />
	<link>http://micropipes.com/blog</link>
	<description>because at 3am anything sounds good</description>
	<lastBuildDate>Mon, 03 May 2010 17:34:44 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>addons.mozilla.org ♥s unit tests.  Again.</title>
		<link>http://micropipes.com/blog/2010/05/03/addons-mozilla-org-%e2%99%a5s-unit-tests-again/</link>
		<comments>http://micropipes.com/blog/2010/05/03/addons-mozilla-org-%e2%99%a5s-unit-tests-again/#comments</comments>
		<pubDate>Mon, 03 May 2010 17:34:44 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=142</guid>
		<description><![CDATA[AMO has had an on-again off-again relationship with unit tests.  A little over a year ago we had a thousand unit tests that sort of, mostly, ran.  The problem is, PHP unit testing just isn&#8217;t as good as it should be.  CakePHP relies on SimpleTest, one of the main PHP test suites. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="https://addons.mozilla.org">AMO</a> has had an on-again off-again relationship with unit tests.  A little over a year ago we had <a href="http://micropipes.com/blog/2009/04/09/addonsmozillaorg-celebrates-1000-passing-unit-tests/">a thousand unit tests</a> that sort of, mostly, ran.  The problem is, PHP unit testing just isn&#8217;t as good as it should be.  CakePHP relies on <a href="http://www.simpletest.org/">SimpleTest</a>, one of the main PHP test suites.  It worked relatively well for a small number of tests, but as our suite grew, so did our troubles.</p>
<p>Our main issue was hitting a memory limit or the max execution time.  We hit the limits often for a variety of reasons, some legitimate bugs, and some because we tried to hack around things to make the tests run.  If we change the limits we affect the tests because they are running within the same environment.  There wasn&#8217;t really a concept of fixtures then, although it looks like <a href="http://bakery.cakephp.org/articles/view/testing-models-with-cakephp-1-2-test-suite">CakePHP has stepped up there</a>.  The simple test web runner was hard to use and the mock objects were sometimes a little too mocked and missing some attributes.</p>
<p>All in all it was a heroic effort to get that many tests, but we didn&#8217;t maintain it because they were so slow to write and difficult to run.  Testing can be a pain to write, sure, but it shouldn&#8217;t be a burden like that.  Enter <a href="http://docs.djangoproject.com/en/dev/topics/testing/">Django&#8217;s testing suite</a> (built on top of <a href="http://docs.python.org/library/unittest.html">Python&#8217;s unittest</a>).  It has most of our complaints handled out of the box.  It&#8217;s very well documented, considers a lot of aspects of testing, supports fixtures, a built-in client, etc.  It&#8217;s a well thought out framework to build tests on.</p>
<p>We&#8217;re being more vigilant about requiring tests this time around, but they also aren&#8217;t as frustrating to write.  When you write them they actually work and they stay working.  Most of what you want is built in already.  For example, I wrote the password reset form we needed on AMO in Django.  With CakePHP and SimpleTest I&#8217;d have no idea how to test that the email was actually working.  It&#8217;s apparently possible <a href="http://www.curioussymbols.com/simplemail/">with a SimpleTest add-on</a> and enough code that I have to scroll in my browser.  With Django&#8217;s test suite the actual code was 5 lines, 3 of which were assertions:</p>
<pre><code class="python">
    def test_request_success(self):
        self.client.post('/en-US/firefox/users/pwreset',
                        {'email': self.user.email})

        eq_(len(mail.outbox), 1)
        assert mail.outbox[0].subject.find('Password reset') == 0
        assert mail.outbox[0].body.find('pwreset/%s' % self.uidb36) > 0
</code></pre>
<p>With the power of the new test suite we&#8217;re once again writing and maintaining our unit tests &#8211; currently at around 390 tests and increasing steadily.  Plenty of people have written about why unit tests are important so I won&#8217;t belabor the point, but I will mention that it&#8217;s a great feeling to be able to commit something and be confident it hasn&#8217;t affected other parts of the site.  It&#8217;s almost as good of a feeling when you write your code and a completely different test fails pointing out a case that you didn&#8217;t even consider but one that would soak up developer time trying to debug down the road.  </p>
<p>Building on a foundation that takes testing seriously is great.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2010/05/03/addons-mozilla-org-%e2%99%a5s-unit-tests-again/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Continuous Integration comes to AMO</title>
		<link>http://micropipes.com/blog/2010/04/07/continuous-integration-comes-to-amo/</link>
		<comments>http://micropipes.com/blog/2010/04/07/continuous-integration-comes-to-amo/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 14:54:13 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[statistics]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=139</guid>
		<description><![CDATA[It&#8217;s time to hail another milestone for AMO in our epic push for improvements in 2010.  This time I&#8217;m happy to announce our Hudson continuous integration server which has been humming along for a few months.

Hudson Integration Screenshot.  Click to enlarge.
AMO is the first Mozilla Webdev site to use continuous integration, and it&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s time to hail another milestone for <a href="https://addons.mozilla.org/">AMO</a> in our <a href="http://micropipes.com/blog/2009/11/17/amo-development-changes-in-2010/">epic push for improvements in 2010</a>.  This time I&#8217;m happy to announce our <a href="https://hudson.mozilla.org/job/preview.addons.mozilla.org/">Hudson continuous integration server</a> which has been humming along for a few months.</p>
<p><a href="http://micropipes.com/blog/wp-content/img/hudson_screenshot.png"><img src="http://micropipes.com/blog/wp-content/img/hudson_screenshot_small.png" title="Hudson Summary Screenshot" style="border:1px solid #000; padding:10px;" /></a></p>
<caption>Hudson Integration Screenshot.  Click to enlarge.</caption>
<p>AMO is the first Mozilla Webdev site to use continuous integration, and it&#8217;s been a long time coming.  With the way it&#8217;s currently configured we&#8217;ve got <a href="https://hudson.mozilla.org/job/preview.addons.mozilla.org/512/cobertura/?">code coverage trending</a>, <a href="https://hudson.mozilla.org/job/preview.addons.mozilla.org/512/testReport/?">unit test trending</a>, <a href="https://hudson.mozilla.org/job/preview.addons.mozilla.org/512/violations/?">code quality trending</a>, as well as detailed reports for all the above for every single check in.</p>
<p>If anything fails or oversteps a threshold our IRC bot complains and we can get it fixed up quickly.  It&#8217;s a boon to productivity to know that all the code being checked in is being tested automatically, plus it gives everyone a stable state to compare to.</p>
<p>Thanks to everyone that helped get Hudson going, from the <a href="http://blog.hudson-ci.org/">people that write it</a>, to <a href="http://blog.mozilla.com/it/">the IT team that keeps it alive</a>, to <a href="http://blog.mozilla.com/webdev/">the webdev team</a> that helped work out the kinks.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2010/04/07/continuous-integration-comes-to-amo/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Libraries to connect to a Citrix NetScaler or Zeus Traffic Manager</title>
		<link>http://micropipes.com/blog/2010/03/23/libraries-to-connect-to-a-citrix-netscaler-or-zeus-traffic-manager/</link>
		<comments>http://micropipes.com/blog/2010/03/23/libraries-to-connect-to-a-citrix-netscaler-or-zeus-traffic-manager/#comments</comments>
		<pubDate>Tue, 23 Mar 2010 18:56:57 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[scalability]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=133</guid>
		<description><![CDATA[The first front end cache we used on AMO was the Citrix NetScaler.  I&#8217;ve complained about it&#8217;s API before but apparently never announced the library I wrote to purge items from the cache.  So, a little late, but I have some reusable PHP code that will talk to your NetScaler and let you [...]]]></description>
			<content:encoded><![CDATA[<p>The first front end cache we used on <a href="https://addons.mozilla.org/">AMO</a> was the <a href="http://www.citrix.com/English/ps2/products/product.asp?contentID=21679">Citrix NetScaler</a>.  I&#8217;ve <a href="http://micropipes.com/blog/2008/07/14/planning-your-api-is-important/">complained about it&#8217;s API before</a> but apparently never announced the library I wrote to purge items from the cache.  So, a little late, but I have <a href="http://viewvc.svn.mozilla.org/vc/libs/ns-api/">some reusable PHP code that will talk to your NetScaler</a> and let you expire objects.</p>
<p>We hit some limitations with the NetScaler that we weren&#8217;t happy with.  Cost aside, it ignored some pretty standard stuff like the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44">HTTP Vary Header</a>.  After working around that for years we switched to the horizontally scalable <a href="http://www.zeus.com/products/traffic-manager/index.html">Zeus Traffic Manager</a> (at that time, referred to as ZXTM).  We&#8217;ve been pleased with our choice and six months ago I wrote a <a href="http://viewvc.svn.mozilla.org/vc/libs/zxtm-api/">similar PHP library that allows you to connect to Zeus&#8217;s API</a>.  Time and priorities being what they are, we never implemented it in production.</p>
<p>Finally, the real point to this post, last night I wrote a <a href="http://github.com/clouserw/hera">python library that will expire content from Zeus</a>.  We&#8217;ll roll this into our migration and waiting on content to expire from Zeus should be a thing of the past.</p>
<p>As always, if you can use the libraries, feel free.  They all have READMEs with examples.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2010/03/23/libraries-to-connect-to-a-citrix-netscaler-or-zeus-traffic-manager/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Maintaining localization between Python and PHP (it&#8217;s not fun)</title>
		<link>http://micropipes.com/blog/2010/03/08/maintaining-localization-between-python-and-php-its-not-fun/</link>
		<comments>http://micropipes.com/blog/2010/03/08/maintaining-localization-between-python-and-php-its-not-fun/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 22:42:00 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[L10n]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=115</guid>
		<description><![CDATA[I reached my hand into the barrel of problems our migration to Python is going to cause and came up with Localization.  It figures.
First out of the chute was the .po files.  It turns out the actual formatting is different between the two languages.  PHP uses %1$s for its substitutions, but python [...]]]></description>
			<content:encoded><![CDATA[<p>I reached my hand into the barrel of problems <a href="http://micropipes.com/blog/2009/11/17/amo-development-changes-in-2010/">our migration to Python</a> is going to cause and came up with Localization.  It figures.</p>
<p>First out of the chute was the .po files.  It turns out the actual formatting is different between the two languages.  PHP uses <em>%1$s</em> for its substitutions, but python uses either named variables like <em>(num)s</em> or integers like <em>{0}</em>.  For the record, they both support <em>%s</em> when you don&#8217;t need to order the substitutions.<br />
PHP example:<br />
<code>I have %2$s apples and %1$s oranges</code><br />
Python example:<br />
<code>I have {1} apples and {0} oranges</code></p>
<p>Since I&#8217;ve worked with the <a href="http://translate.sourceforge.net/wiki/">Translate Toolkit</a> before, I decided to write a script to convert between the two formats.  If you find yourself in the same unfortunate boat as me, behold<br />
<a href="http://translate.svn.sourceforge.net/viewvc/translate/src/trunk/translate/tools/phppo2pypo.py?view=markup">phppo2pypo</a> and <a href="http://translate.svn.sourceforge.net/viewvc/translate/src/trunk/translate/tools/pypo2phppo.py?view=markup">pypo2phppo</a> to convert between the two types.</p>
<p>Crisis averted, right?  Oh, that&#8217;s just scratching the surface.  Remember <a href="http://micropipes.com/blog/2008/07/09/adding-context-to-amo-po-files/">how happy I was that PHP finally started supporting msgctxt</a>?  Well, Python has had <a href="http://bugs.python.org/issue2504">a patch for it since 2008</a> but no one has bothered to land it.  I wrote a new <a href="http://github.com/clouserw/tower/blob/master/l10n/__init__.py">ugettext() and ungettext()</a> that recognizes context in the .po files.  To use simply do: <em>from l10n import ugettext as _</em> at the top of your file.</p>
<p>Along with adding msgctxt support, those two functions also collapse consecutive white space.  We&#8217;re using <a href="http://jinja.pocoo.org/2/">Jinja2</a> with <a href="http://babel.edgewall.org/">Babel</a> and the <a href="http://jinja.pocoo.org/2/documentation/extensions">i18n extension</a> as our template engine.  Jinja2 has a concept of stripping white space from the beginning or end of a string but does nothing about the middle.  A paragraph of text in a Jinja2 template would look like:<br />
<code><br />
  {% trans -%}Mozilla is providing links to these applications<br />
  as a courtesy, and makes no representations regarding the<br />
  applications or any information related thereto. Any questions,<br />
  complaints or claims regarding the applications must be<br />
  directed to the appropriate software vendor.<br />
  {%- endtrans %}<br />
</code></p>
<p>That&#8217;s a decent looking template, right?  Yeah, well, when Babel extracts that, it includes all the line breaks too, giving you something <a href="http://bitbucket.org/plurk/solace/src/tip/solace/i18n/messages.pot#cl-625">like this</a>.  The localizers would revolt if I sent them that, so I added in auto white-space collapsing.  Getting Babel to use the new functions means <a href="http://github.com/clouserw/tower/blob/master/tower/management/commands/extract.py">a new extraction script</a>.</p>
<p>At this point, we&#8217;re extracting strings from our new code and we can convert between Python and PHP files.  All we need now is a Frankenstein mix of xgettext functions to act as glue.  Meet the <a href="http://github.com/clouserw/tower/blob/master/l10n/management/commands/amalgamate.py">amalgamate script</a> that uses the pypo2php scripts, concatenates the .pot files, and merge updates each locales .po file.  After that it&#8217;s <a href="http://viewvc.svn.mozilla.org/vc?revision=63671&#038;view=revision">quick tweaks to the build scripts</a> to create z-messages.po files and we&#8217;re done.</p>
<p>So, all that said, the new process for L10n, while we&#8217;re in this transitional phase, is:</p>
<ol>
<li>From the PHP code, run <em>locale/extract-po-remora.sh</em>.  That pulls everything from all the PHP files, creates <em>locale/r-keys.pot</em>, updates the messages.po file for each locale, and compiles them.  Life used to be so simple.</li>
<li>From the python code, make sure you&#8217;re up to date, then run <em>./manage.py extract</em>.  That will pull everything from the python code and templates and create <em>locale/z-keys.pot</em>.</li>
<li>Run <em>./manage.py amalgamate</em>.  That will merge the z-keys.pot into the PHP messages.po files.</li>
<li>Localizers can make their changes as usual, and commit back to messages.po.</li>
<li>From PHP, <em>locale/copy-to-zamboni.py locale</em> will create z-messages.po files in the Python format. We could skip right to .mo files, but in case something goes wrong I want to see the .po files.</li>
<li>Then, like today, <em>locale/compile-mo.sh locale</em> will compile all the .po files.</li>
</ol>
<p>After all those steps are done, we&#8217;ve got duplicate .mo files, aside from formatting, and each application can look at its own .mo to get the strings it needs.  All this code is just a big band-aid and there are plenty of things that are more fun than juggling L10n between two applications across two <abbr title="Revision Control Systems">RCS</abbr>s.  But we knew what we were getting in to.  I&#8217;ll post something more positive later to help justify it. <img src='http://micropipes.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2010/03/08/maintaining-localization-between-python-and-php-its-not-fun/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Automating &#8220;Thinking of you&#8221;</title>
		<link>http://micropipes.com/blog/2009/07/20/automating-thinking-of-you/</link>
		<comments>http://micropipes.com/blog/2009/07/20/automating-thinking-of-you/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 17:53:39 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[personal]]></category>
		<category><![CDATA[mail]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=81</guid>
		<description><![CDATA[I had an idea a few weeks ago.  I&#8217;ve got a bunch of great photos on my computer that no one ever sees unless we meet in person.  Sure, we&#8217;ve got flickr and social networking sites, but I&#8217;m talking about an old photo that someone only saw once in passing, or a favorite [...]]]></description>
			<content:encoded><![CDATA[<p>I had an idea a few weeks ago.  I&#8217;ve got a bunch of great photos on my computer that no one ever sees unless we meet in person.  Sure, we&#8217;ve got <a href="http://www.flickr.com/">flickr</a> and social networking sites, but I&#8217;m talking about an old photo that someone only saw once in passing, or a favorite shot from summer while you&#8217;re huddled over your heater wondering when the sun is coming back.</p>
<p>I can look at them any time, and there are a few on flickr that other people can look at, but what about people that aren&#8217;t tech savvy or are really busy and get caught up in the daily grind?</p>
<p>I was thinking, the answer can be a really simple script running from cron, say, weekly.  It picks a random photo from a directory and emails it to a group of people.  That&#8217;s it.  The idea is:</p>
<ul>
<li>it&#8217;s low tech compared to RSS feeds and social networking sites.  This &#8220;just works&#8221; with the tools people (potentially, low-tech people) are already used to using.</li>
<li>in a similar vein, commenting and discussion are built in if you feel like it.</li>
<li>it&#8217;s focused on the people on the CC list.  Sending out an old photo that is relevant just to those people has a lot more effect than one scrolling by on flickr.  It&#8217;s got a personal touch.</li>
<li>it&#8217;s automatic.  You wake up Monday morning, drag yourself to work, and there is a photo from 15 years ago in your inbox and you can laugh about how bad your hair was.  Awesome.</li>
</ul>
<p>So, I thought I would try it and cooked up <a href="http://svn.micropipes.com/audreytoo/audreytoo.py">audreytoo</a>.  Basically, you seed a directory with <em>copies</em> of the pictures you want to send out, add the script to a cron job, and it does it&#8217;s thing.  There are a couple other features in the script that you could look at if you want to get fancier.</p>
<p>I realize there is some irony in using an automated script to say &#8220;I&#8217;m thinking of you&#8221; but as long as I&#8217;m on the CC list it&#8217;s still true. <img src='http://micropipes.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   Anyway, I&#8217;m sharing the code in case anyone else can find value in it.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2009/07/20/automating-thinking-of-you/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Committing to SVN securely from a web application</title>
		<link>http://micropipes.com/blog/2008/09/19/committing-to-svn-securely-from-a-web-application/</link>
		<comments>http://micropipes.com/blog/2008/09/19/committing-to-svn-securely-from-a-web-application/#comments</comments>
		<pubDate>Fri, 19 Sep 2008 22:29:58 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[SVN]]></category>
		<category><![CDATA[Verbatim]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=56</guid>
		<description><![CDATA[Verbatim is the second project I&#8217;ve been the lead on recently where the requirements included people committing to SVN as themselves via the application.  At first glance this means storing the authentication tokens of the user in plain text since we&#8217;ll need to pass them along to SVN whenever they commit.  I wasn&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://wiki.mozilla.org/Verbatim">Verbatim</a> is the second project I&#8217;ve been the lead on recently where the requirements included people committing to <abbr title="Subversion">SVN</abbr> as themselves via the application.  At first glance this means storing the authentication tokens of the user in plain text since we&#8217;ll need to pass them along to SVN whenever they commit.  I wasn&#8217;t happy with that solution so after a bit of thinking we came up with an idea that leaves everything encrypted and doesn&#8217;t cache any credentials.  It involved minimal code in Verbatim and minor work on the SVN server.</p>
<p>On the SVN server the first thing we did was to create a special Verbatim user that can commit to SVN via SSH using a generated key.  We copied this key to the Verbatim host which allowed us to commit as the verbatim user without typing a username or password.</p>
<p>The only thing that was added to the Verbatim code was <a href="http://sourceforge.net/mailarchive/forum.php?thread_name=ADA2D058-904B-44F0-8301-21334A7B6E02%40mozilla.com&#038;forum_name=translate-pootle">a patch that Dan Schafer cooked up</a> that sets an SVN revision property, <em>translate:author</em>, to the name of the current user.  When the user clicks &#8220;commit&#8221; this property is set and sent along with the commit.</p>
<p>At this point we could commit from the application but it still goes to the application as the Verbatim user.  We used <a href="http://svnbook.red-bean.com/en/1.4/svn-book.html#svn.ref.reposhooks">SVN&#8217;s hooks</a> to take the next step.</p>
<p>The first script we changed was the pre-revprop-change hook.  This controls what special revision properties a user can modify when they commit.  <a href="https://bugzilla.mozilla.org/attachment.cgi?id=337775">Our script</a> adds the ability to modify svn:author and translate:author.  Before allowing the modifications the script checks if the user committing is the special verbatim user to prevent anyone from committing as someone else.</p>
<p>Next we added a <a href="https://bugzilla.mozilla.org/attachment.cgi?id=339184">post-commit script</a> that looks for the translate:author property.  If it&#8217;s found it will take that value, replace svn:author, and remove translate:author; effectively making whatever was in translate:author the real author.  This is a non-versioned change which means there is no commit that needs to happen &#8211; the new author is set immediately.</p>
<p>With these scripts in place we can commit as anyone from the application and everyone&#8217;s credentials stay encrypted and secure.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2008/09/19/committing-to-svn-securely-from-a-web-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Planning your API is important</title>
		<link>http://micropipes.com/blog/2008/07/14/planning-your-api-is-important/</link>
		<comments>http://micropipes.com/blog/2008/07/14/planning-your-api-is-important/#comments</comments>
		<pubDate>Mon, 14 Jul 2008 07:04:34 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[scalability]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/?p=55</guid>
		<description><![CDATA[I&#8217;m upgrading some code I wrote to talk to a new version of the Citrix NetScaler&#8217;s API.  The NetScaler&#8217;s manuals (that&#8217;s right, plural) weigh in at a combined 1114 pages so documentation isn&#8217;t a problem and their implementation is a breeze using WSDL over SOAP.  However, some of the core changes left me [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m upgrading some code I wrote to talk to a new version of the <a href="http://www.citrix.com/English/ps2/products/product.asp?contentID=21679">Citrix NetScaler</a>&#8217;s <abbr title="Application Programming Interface">API</abbr>.  The NetScaler&#8217;s manuals (that&#8217;s right, plural) weigh in at a combined 1114 pages so documentation isn&#8217;t a problem and their implementation is a breeze using <abbr title="Web Services Definition Language">WSDL</abbr> over <abbr title="Simple Object Access Protocol">SOAP</abbr>.  However, some of the core changes left me scratching my head.  Case in point:</p>
<p>To get an object out of the cache in the previous version the method signature was:</p>
<blockquote><p>getcacheobject(string $url, string $host, unsignedInt $port)</p></blockquote>
<p>$url in this case is what is commonly referred to as the &#8220;path&#8221; in a standard <abbr title="Uniform Resource Locator">URL</abbr>; e.g. /en-US/index.html.  That&#8217;s simple enough to use, let&#8217;s see what the new version has:</p>
<blockquote><p>getcacheobject(string $url, unsignedLong $locator, string $host, unsignedInt $port [...]</p></blockquote>
<p>$locator is an internal id for a cache object which is defintitely something I should be able to use to expire content, but what is it doing in the middle of my url+host pair?  The error messages are happy to let me know that I <b>can&#8217;t</b> pass both $url and $locator to the same call and if I pass $url I <b>must</b> pass $host.  That means I will always have be passing a null value in either the first or second parameter.</p>
<p>And if you&#8217;re thinking it&#8217;s for consistency with other methods, think again.  To flush an object we&#8217;ve got:</p>
<blockquote><p>flushcacheobject(unsignedLong $locator, string $url, string $host, unsignedInt $port [...]</p></blockquote>
<p>Moral of the story: planning and consistency makes happy programmers; particularly with an API.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2008/07/14/planning-your-api-is-important/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CakePHP makes upgrading easy</title>
		<link>http://micropipes.com/blog/2008/04/01/cakephp-makes-upgrading-easy/</link>
		<comments>http://micropipes.com/blog/2008/04/01/cakephp-makes-upgrading-easy/#comments</comments>
		<pubDate>Wed, 02 Apr 2008 05:32:53 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/2008/04/01/cakephp-makes-upgrading-easy/</guid>
		<description><![CDATA[Laura attended CakeFest a couple months ago and got to meet some core Cake developers in person.  In doing so she let slip that AMO was running on a pretty old version (1.1.12 &#8211; Released in December of 2006).  Apparently 1.1.15 had some major performance boosts and since we melted the cluster a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.laurathomson.com/">Laura</a> attended <a href="http://cakefest.org/">CakeFest</a> a couple months ago and got to meet some core Cake developers in person.  In doing so she let slip that <abbr title="addons.mozilla.org">AMO</abbr> was running on a pretty old version (1.1.12 &#8211; Released in December of 2006).  Apparently 1.1.15 had some major performance boosts and since we melted the cluster a few times recently (the <a href="http://wiki.mozilla.org/Update:Remora_API_Docs">new <abbr title="Application Programming Interface">API</abbr></a> was the culprit) we thought it would be a good idea to investigate upgrading.</p>
<p>I downloaded 1.1.15 and 1.1.19, set up a couple symlinks to swap them into my dev copy and looked at how hard it would be to upgrade.</p>
<p>Hats off to the CakePHP developers.  After merging in a short patch to the core CakePHP session code, most of the site worked right out of the box.  I made a few minor tweaks to our code for things that had changed (and filed <a href="https://trac.cakephp.org/ticket/4140">ticket 4140</a> for them) but all in all it was pretty painless.  Nice work guys.  It shows a lot of planning and foresight to make a framework that doesn&#8217;t have a bunch of code-breaking changes after years of development.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2008/04/01/cakephp-makes-upgrading-easy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>When is a TINYINT(1) not a TINYINT(1)?</title>
		<link>http://micropipes.com/blog/2008/03/07/when-is-a-tinyint1-not-a-tinyint1/</link>
		<comments>http://micropipes.com/blog/2008/03/07/when-is-a-tinyint1-not-a-tinyint1/#comments</comments>
		<pubDate>Fri, 07 Mar 2008 23:50:30 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[o rly]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/2008/03/07/when-is-a-tinyint1-not-a-tinyint1/</guid>
		<description><![CDATA[When you&#8217;re using CakePHP!
Turns out CakePHP considers a TINYINT(1) to be a Boolean.  Judging from all the support tickets that have been filed, I&#8217;m not the first person to get taken off guard by this behavior.  When I asked about it on IRC, the response was that since MySQL considers a TINYINT(1) to [...]]]></description>
			<content:encoded><![CDATA[<p>When you&#8217;re using <a href="http://cakephp.org/">CakePHP</a>!</p>
<p>Turns out CakePHP considers a TINYINT(1) to be a Boolean.  Judging from all <a href="https://trac.cakephp.org/ticket/1253">the</a> <a href="https://trac.cakephp.org/ticket/3903">support</a> <a href="https://trac.cakephp.org/ticket/4026">tickets</a> that have been filed, I&#8217;m not the first person to get taken off guard by this behavior.  When I asked about it on IRC, the response was that since MySQL considers a TINYINT(1) to be a Boolean, CakePHP does too.  That&#8217;s not true.</p>
<p>From the <a href="http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html">MySQL manual</a>:</p>
<blockquote><p>As of MySQL 5.0.3, a BIT data type is available for storing bit-field values. (Before 5.0.3, MySQL interprets BIT as TINYINT(1).)</p></blockquote>
<p>That&#8217;s saying if I request a BIT it will make it a TINYINT, not if I request a TINYINT it will make it a BIT.  Having a framework change the definitions of my database columns sounds crazy to me, but judging from <a href="https://trac.cakephp.org/ticket/1253">the ticket filed in 2006</a> this has been CakePHP&#8217;s policy for a long time.  Despite the long standing precedent I can&#8217;t find any documentation about it online other than the closing remarks of those support tickets.  </p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2008/03/07/when-is-a-tinyint1-not-a-tinyint1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Frameworks that start sessions for every visitor make me sad</title>
		<link>http://micropipes.com/blog/2008/03/06/frameworks-that-start-sessions-for-every-visitor-make-me-sad/</link>
		<comments>http://micropipes.com/blog/2008/03/06/frameworks-that-start-sessions-for-every-visitor-make-me-sad/#comments</comments>
		<pubDate>Thu, 06 Mar 2008 07:00:48 +0000</pubDate>
		<dc:creator>Wil Clouser</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[scalability]]></category>

		<guid isPermaLink="false">http://micropipes.com/blog/2008/03/06/frameworks-that-start-sessions-for-every-visitor-make-me-sad/</guid>
		<description><![CDATA[I might have played the devil&#8217;s advocate when Lars was hating on frameworks at the barcamp last weekend, but that doesn&#8217;t mean I don&#8217;t see his point.  The latest in a series of frustrations with frameworks kept me up until 3am last night.  What better way to cap it off than complaining on [...]]]></description>
			<content:encoded><![CDATA[<p>I might have played the devil&#8217;s advocate when <a href="http://staff.osuosl.org/~lohnk/blog/">Lars</a> was hating on frameworks at the <a href="http://barcamp.org/BeaverBarCamp">barcamp</a> last weekend, but that doesn&#8217;t mean I don&#8217;t see his point.  The latest in a series of frustrations with frameworks kept me up until 3am last night.  What better way to cap it off than complaining on the internet?</p>
<p>Today&#8217;s subject is anonymous sessions.  Frameworks (and developers) love them because they are simple and convenient, but it comes at a cost.  Keeping track of sessions for every visitor on a high traffic site is far too expensive to be practical.  Developers should know how to work around this, but their frameworks need to support them.</p>
<p>The first framework on my mind is <a href="http://drupal.org/">Drupal</a>.  I filed <a href="http://drupal.org/node/201122">an issue</a> last year that Drupal should support disabling anonymous sessions.  It&#8217;s still unassigned so I&#8217;m guessing it&#8217;s not a high priority, but it was one of the main things that made me choose not to use Drupal on mozilla.com.  I <a href="http://drupal.org/node/183006">wrote some ideas</a> on how to handle it and got some responses from people suffering the same fate.  No word on any progress though.</p>
<p>The second framework, <a href="http://cakephp.org/">CakePHP</a>, has an AUTO_SESSION variable that, <a href="http://micropipes.com/blog/2008/01/07/cakephps-cache-that-wouldnt-quit/">just like $cacheQueries</a>, is far to easy to misplace faith in.</p>
<p>By setting AUTO_SESSION to false, you can&#8217;t read or write to the session.  Working as advertised?  Not so much.  If you take a closer look at what&#8217;s actually happening you&#8217;ll see that the session is still getting started, it&#8217;s just that CakePHP is blocking your access to it.  Even with AUTO_SESSION off, a cookie with a unique ID is set, and <strong>a row is still inserted into the sessions table</strong>.  That last part almost brought down <a href="https://addons.mozilla.org/">AMO</a> last night.  I wrote <a href="http://viewvc.svn.mozilla.org/vc/addons/trunk/site/cake/libs/controller/components/session.php?r1=10970&#038;r2=10969&#038;pathrev=10970">a patch that disables anonymous sessions for real</a>, but anyone that has talked to me about patching core code knows I don&#8217;t like to do it.</p>
<p>When you&#8217;re writing code, framework or not, don&#8217;t forget about scalability.</p>
]]></content:encoded>
			<wfw:commentRss>http://micropipes.com/blog/2008/03/06/frameworks-that-start-sessions-for-every-visitor-make-me-sad/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
