<?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"
	>

<channel>
	<title>Graceful Exits &#187; efficiency</title>
	<atom:link href="http://www.jpstacey.info/blog/category/efficiency/www.jpstacey.info/blog/category/efficiency/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jpstacey.info/blog</link>
	<description>Garbage collection, in a very real sense</description>
	<pubDate>Tue, 30 Sep 2008 20:10:32 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>Belated and potentially unreliable discussion of Google Chrome</title>
		<link>http://www.jpstacey.info/blog/2008/09/14/belated-and-potentially-unreliable-discussion-of-google-chrome/</link>
		<comments>http://www.jpstacey.info/blog/2008/09/14/belated-and-potentially-unreliable-discussion-of-google-chrome/#comments</comments>
		<pubDate>Sun, 14 Sep 2008 12:21:22 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[advertising]]></category>

		<category><![CDATA[business]]></category>

		<category><![CDATA[design]]></category>

		<category><![CDATA[discussion]]></category>

		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[useability]]></category>

		<category><![CDATA[alpha]]></category>

		<category><![CDATA[beta]]></category>

		<category><![CDATA[browser]]></category>

		<category><![CDATA[chrome]]></category>

		<category><![CDATA[google]]></category>

		<category><![CDATA[marketing]]></category>

		<category><![CDATA[notplug]]></category>

		<category><![CDATA[performance]]></category>

		<category><![CDATA[plug]]></category>

		<category><![CDATA[release]]></category>

		<category><![CDATA[stability]]></category>

		<category><![CDATA[ui]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/?p=206</guid>
		<description><![CDATA[I feel it's important to tell it like it is, even in the restricted space of a post title; but maybe I need a lesson from Google in self-presentation.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m typing this from <a href="http://www.google.com/chrome" >Google Chrome</a>. Since it was released almost two weeks ago I&#8217;ve wanted to blog about it, but have been mostly hampered by no easy access to Vista or XP. I&#8217;ve temporarily rediscovered my XP partition, though, and as mountains of Windows security updates download in the background I now feel frankly safer in Chrome than in IE7 (or the cranky old FF2.x I&#8217;m about to update while I&#8217;m here).</p>
<h3>Why this might be a plug, although it probably isn&#8217;t</h3>
<p>I&#8217;ve also been waiting to categorically declare a very minor conflict of interest, which I can now do: yesterday a lovely paper copy of the <a href="http://www.google.com/googlebooks/chrome/small_00.html" >Google Chrome comic</a> arrived in my letterbox. So if you think I&#8217;m blogging because of that, you can navigate elsewhere now.</p>
<p>Certainly a product&#8217;s incompatibility with X/Linux would normally make me avoid it, so perhaps I <em>have</em> being persuaded by the marketing. But a large part of Chrome is marketing, and what makes it most interesting is what it reveals about Google&#8217;s marketing internals and about whether or not they matter; but more about that later.</p>
<h3>How Google Chrome feels and acts</h3>
<p><a href="http://www.hicksdesign.co.uk/journal/initial-thoughts-on-google-chrome" >The ever-lucid Jon Hicks has already posted some thoughts</a>, so my delay in writing has saved me time on that score. I don&#8217;t have a great eye for design, but I feel like Chrome&#8217;s appearance is interesting if less revolutionary than the promotional material might suggest. Tabs sit in a blue surrounding background, making them look like a half-hearted IE7 reskin. Menus have, as in IE7, been relegated to two weird buttons on the right of the address bar. Full-screen mode is nice, though, as the tabs sit over the top window bar, combining Windows chrome and Chrome chrome&#8212;does that make sense?&#8212;to increase the window size.</p>
<p>Browsers are browsers and, as with word processors and spreadsheet software, they should really be free and open-source by now, leaving proper software companies with time to develop the next generation of applications. So in a sense most of what Google Chrome does, it does well: unobtrusively and unremarkably, and that&#8217;s how it should be; but quite hard to comment on. What&#8217;s most noticeable is the speed: it&#8217;s faster than any browser I&#8217;ve used on XP, ever. Opening new tabs and windows&#8212;although in Chrome <a href="http://developers.slashdot.org/article.pl?sid=08/09/10/196224" >there&#8217;s very little difference under the hood, as they&#8217;re all processes</a>&#8212;is nippy, despite the extra overhead that Google have decided is essential to Chrome&#8217;s distributed stability. Pulling a tab out of one window; letting it drop as a new window, or dropping it into a different window; maximizing windows and general rendering of content: these are all sharp and impressive. But again, they shouldn&#8217;t be as obvious as they are, and it merely reflects on other browsers that Chrome feels so fast.</p>
<p>There&#8217;s a kind of Firebug-like inspector in Chrome, and it&#8217;s nice enough, although it ought to be extracted as a plugin before long, otherwise my guess is it will end up neglected. And popup blocking&#8212;represented in the promotional bumf as the window swallowing the popup, and you the user pulling it out in a reactive way&#8212;is just a case of a popup window appearing in the main tab so that only its bar is visible. There&#8217;s no obvious feeling of resistance as you pull the hidden window up to be visible. Maybe that&#8217;s the point, but after the reaction of tab dragging and dropping you feel like you&#8217;re moving popups around using an entirely different UI. Also, as I&#8217;ve just discovered, text search doesn&#8217;t look in form textareas, which makes proofreading your blogposts difficult.</p>
<p>Generally, though, Chrome has at least run rings around anything that Microsoft can produce in the browser market, and then Google managed to completely open-source the code which, like some old John McCain company, Microsoft can neither do nor understand why it should. It&#8217;s astonishing to see one huge company outmanoeuvre another like this, and suggests interesting times still ahead</p>
<h3>What packaging Chrome has been wrapped in</h3>
<p>As regards the marketing, Google has also managed to completely confound the other big player Microsoft is intent on gradually rebranding itself as something in between the silver-and-blueblack chunky mens&#8217; toiletries packaging that make it acceptable to possess both moisturisers and Y chromosomes, and transparent, flashy interfaces of the sort that IE6 always fucks up and means web developers have to work around. Google, on the other hand, has essentially presented itself through Chrome as a kind of retro-yet-futuristic 1950s take on a science-fiction OSX, all meals-in-a-tablet and egg-shaped seats.</p>
<p>Much of this has been down to the artistic skills of <a href="http://www.scottmccloud.com/" >Scott McCloud</a>. I never know what to think about him. On the one hand he&#8217;s got this unique, flowing, clean style that&#8217;s something like a scrubbed <a href="http://images.google.co.uk/images?q=daniel%20clowes" >Daniel Clowes</a>; on the other, his drawings can sometimes feel washed out, pretentious and affected. On the one hand, he&#8217;s tried to revolutionize the way that people think about comics, often by exposing what good comics have been doing for years; on the other, very few people have got rich on the micropayment model he espouses, and <a href="http://ogn.s3.amazonaws.com/8-RhodriMarsden.mp4" >if it isn&#8217;t working for musicians it&#8217;s unlikely to work for graphic novelists</a>.</p>
<h3>Where that backlash came from</h3>
<p>By portraying itself as different from other industry behemoths&#8212;which, to be fair, it is in some ways&#8212;Google has left itself in a bind. It still has shareholders, and on one level legally has to conduct itself as a responsible company, however much it wants to be treated like, or possibly with, <a href="http://www.ubuntu.com/" >Ubuntu</a>. Fronting what&#8217;s essentially a business exercise with a divisive figure like McCloud leaves you ripe to parody, and The Register has tried to step in with <a href="http://www.theregister.co.uk/2008/09/02/google_chrome_comic_funnies/" >Google Chrome comic funnies</a>. They fly in the face of the no-alteration Creative Commons licence that Google/McCloud released the work under, but that&#8217;s fine because the uniquely American concept of fair use lets them do that if it&#8217;s satire.</p>
<p>Except they don&#8217;t work as satire, because <a href="http://www.theonion.com/content/node/39320" > they&#8217;re not funny</a>. And yet at the same time the font they&#8217;ve used makes it look eerily reminiscent of the shockingly explicit <a href="http://jerkcity.com/" >Jerk City</a>, which hints at a far better way of parodying the style: the <a href="http://valleywag.com/5045109/uh-oh-the-b+tards-got-their-hands-on-googles-chrome-comic" >4chan/yayhooray parodies</a> are in a way more honest and hence funnier: probably because they&#8217;re more anarchic and less interested in squeezing out another humourless Googlebashing.</p>
<p>No product launch is smooth, and there&#8217;ve been bumps in the otherwise smooth journey that Chrome has made to mass testing (if not mass acceptance). The <a href="http://tech.slashdot.org/article.pl?sid=08/09/10/144202" >end-user licence turned out to contain mad MyPlace-like terms of use</a> which was sort of an accident, although it&#8217;s drawn attention to the fact that <a href="http://tech.slashdot.org/article.pl?sid=08/09/10/144202" >they still exist in other Google products</a>. Whoops. The original beta&#8212;or, given that everything from Google is a beta, maybe we should just call it an alpha and be done&#8212;was <a href="http://www.theregister.co.uk/2008/09/09/google_chrome_update/" >susceptible to Safari-like carpetbombing, and The Register criticized the rather flaky bugfix and its rollout procedure</a>.</p>
<p>I love <abbr title="The Register" >el Reg</abbr> and its journalistic instincts. It&#8217;s more than happy to puncture someone&#8217;s silly bubble, and it displays a dogged tenacity in pursuing the &#8220;real&#8221; story: although they&#8217;re basically wrong about climate change, in the way that Private Eye turned out to be wrong about MMR; and their grammar and sub-editing is atrocious for an outlet that considers itself to be conducting serious journalism. </p>
<p>But I think they&#8217;re being unfair on Google: what other open-source product would launch to such scrutiny? What other <abbr title="Free and Open Source Software" >product</abbr> has had seamless security procedure baked into it from its alpha, and why should that matter? Google are big, but they can only cover so many bases: there&#8217;s so much infrastructure glossed over by McCloud&#8217;s comic, and maybe a FOSS-like boring list of features and a changeset would have led people to underestimate less the sheer amount of stress testing, and the sheer amount of work that can only now be stress-tested, now there&#8217;s a user base and the animosity of the press to contend with.</p>
<p>Google did after all still manage a big reveal&#8212;only two weeks before <a href="http://code.google.com/intl/en_uk/events/developerday/2008/home.html" >London&#8217;s own Google Developer Day</a>&#8212;in their usual manner. But I do wonder about the timing. Was there a danger in letting crowds into Google UK while Chrome was still secret? Did someone want Chrome to be out&#8212;prematurely, if need be&#8212;for the coup of having people drool over it at a GDD? Was the news about to leak anyway, and did damage limitation dictate the software&#8217;s release? If that&#8217;s the case, though&#8230; does it matter? Google gets its theatre; the world gets an interesting FOSS project; early adopters get an unstable pre-release: everyone&#8217;s happy. Ish.</p>
<h3>Which hand is on Google&#8217;s tiller</h3>
<p>Pessimistic journalists&#8212;and in my honest-to-goodness opinion there&#8217;s no better sort&#8212;always point to Google&#8217;s lack of revenue from its non-core offerings and suggest that it&#8217;d be far better for Google to concentrate on the products that directly earn it money. But they forget that Google&#8217;s profitless products exist as a perpetual rebranding and repositioning of Google: indirectly, they maintain Google&#8217;s status as a company that other companies, developers and end users actively want to be associated with, and actively trust. While they&#8217;ll never entirely remove the <a href="http://www.theregister.co.uk/2006/01/27/google_doesnt_censor/" >patina and dust collecting on their &#8220;don&#8217;t be evil&#8221; statement</a>, they can at least act like a company that trusts open source, and whom open-source communities trust in turn.</p>
<p>Google <em>can</em> keep on pushing things like Chrome out, and its launch cycle <em>can</em> be dictated by something other than the developers&#8217; whims, because: its main rival has nothing like Chrome, or GMail, or Google Docs; and successful FOSS projects like Django or Ubuntu have hardly suffered from bleeding-edge alphas or crotchety betas, as long as community, or honesty, or image, has been there to prop them up.</p>
<h3>Who the hell am I to be telling you this anyway</h3>
<p>I quite like Chrome. But I completely accept that receiving personalized communication from the company taints my status as a reliable blogger. So don&#8217;t take my opinion on Chrome at face value. </p>
<p>I certainly won&#8217;t: I&#8217;m about to reboot into a proper operating system, and I&#8217;ll lose Chrome as I do so. It&#8217;s a nice addition to the existing ranks of browsers, but not <em>that</em> nice.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/09/14/belated-and-potentially-unreliable-discussion-of-google-chrome/feed/</wfw:commentRss>
<enclosure url="http://ogn.s3.amazonaws.com/8-RhodriMarsden.mp4" length="72837626" type="video/mp4" />
		</item>
		<item>
		<title>Improving REST performance is all about negotiation</title>
		<link>http://www.jpstacey.info/blog/2008/09/04/improving-rest-performance-is-all-about-negotiation/</link>
		<comments>http://www.jpstacey.info/blog/2008/09/04/improving-rest-performance-is-all-about-negotiation/#comments</comments>
		<pubDate>Thu, 04 Sep 2008 09:31:50 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[formats]]></category>

		<category><![CDATA[layers]]></category>

		<category><![CDATA[network]]></category>

		<category><![CDATA[quickies]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[architecture]]></category>

		<category><![CDATA[resource]]></category>

		<category><![CDATA[rest]]></category>

		<category><![CDATA[royfielding]]></category>

		<category><![CDATA[roytfielding]]></category>

		<category><![CDATA[state]]></category>

		<category><![CDATA[understandable]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/?p=200</guid>
		<description><![CDATA[Ceci n'est pas un obj&#233;t... nécessairement.]]></description>
			<content:encoded><![CDATA[<blockquote><p>
Web architects must understand that resources are just consistent mappings from an identifier to some set of views on server-side state. If one view doesn’t suit your needs, then feel free to create a different resource that provides a better view (for any definition of “better”). These views need not have anything to do with how the information is stored on the server, or even what kind of state it ultimately reflects. It just needs to be understandable (and actionable) by the recipient.
</p></blockquote>
<p>&#8212; Roy Fielding on <a href="http://roy.gbiv.com/untangled/2008/paper-tigers-and-hidden-dragons" >creating new resources for REST architectures</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/09/04/improving-rest-performance-is-all-about-negotiation/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Variable assignment in Django templates, sort of</title>
		<link>http://www.jpstacey.info/blog/2008/05/29/variable-assignment-in-django-templates-sort-of/</link>
		<comments>http://www.jpstacey.info/blog/2008/05/29/variable-assignment-in-django-templates-sort-of/#comments</comments>
		<pubDate>Thu, 29 May 2008 13:08:33 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[hacking]]></category>

		<category><![CDATA[layers]]></category>

		<category><![CDATA[paradigms]]></category>

		<category><![CDATA[assignment]]></category>

		<category><![CDATA[django]]></category>

		<category><![CDATA[equals]]></category>

		<category><![CDATA[hack]]></category>

		<category><![CDATA[include]]></category>

		<category><![CDATA[template]]></category>

		<category><![CDATA[variable]]></category>

		<category><![CDATA[with]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/05/29/variable-assignment-in-django-templates-sort-of/</guid>
		<description><![CDATA[Use and abuse of the "with" programmatic statement to make your Django template code less mad.]]></description>
			<content:encoded><![CDATA[<p>Django&#8217;s templating language is intentionally quite restrictive. The idea is that you have to do all your data munging in the control-ish sublayer of the view layer, in the method registered as handling the view in <code>urls.py</code>. In principle this simplifies templates, but in practice it can make life for the developer more difficult: you have to really think ahead, and assemble your variables properly, so that the templating language can use simple iterative loops to prepare your HTML.</p>
<p>What if you want the same output for several different data structures? Let&#8217;s say we have three people, and we&#8217;d like to run the following <a href="http://www.djangoproject.com/documentation/templates/#include" >include</a>, saved as <code>name.html</code>, on all three:</p>
<blockquote class="code"><p>&lt;p>{{ person.firstname }} {{ person.surname }}&lt;/p></p>
</blockquote>
<p>Ideally you&#8217;d have the three people in a structure called <code>people</code>, and be able to run:</p>
<blockquote class="code"><p>{% for person in people %}{% include &#8220;name.html&#8221; %}{% endfor %}</p>
</blockquote>
<p>But what if the order matters? What if you need <code>account_director</code> to do different things in the template from <code>project_manager</code>? You&#8217;d want to send them through as separate data structures, and this:</p>
<blockquote class="code"><p>{% include &#8220;name.html&#8221; %}<br />
{% include &#8220;name.html&#8221; %}<br />
{% include &#8220;name.html&#8221; %}</p>
</blockquote>
<p>would just do nothing, because it references <code>person</code> and not <code>account_director</code>. An alternative is to turn <code>name.html</code> into a custom tag, taking arguments; but if the content of <code>name.html</code> were any more HTML-heavy then you might want to abstract it into the include nonetheless, and then you&#8217;d just be running a custom tag method, to pass variables to a template fragment, to render the fragment, to pass it back up to the template. It&#8217;d be nicer if we could do this with core functionality instead.</p>
<p>Using the <a href="http://www.djangoproject.com/download/" >latest development version of Django</a>, we can implement basic variable assignment&#8212;getting <code>person</code> to reference whatever we want in the template layer&#8212;using the <a href="http://www.djangoproject.com/documentation/templates/#with" ><code>with</code> template tag</a>. This means that we can wrap each <code>include</code> tag to produce the required output:</p>
<blockquote class="code"><p>{% with account_director as person %}<br />
&nbsp;&nbsp;{% include &#8220;name.html&#8221; %}<br />
{% endwith %}<br />
{% with project_manager as person %}<br />
&nbsp;&nbsp;{% include &#8220;name.html&#8221; %}<br />
{% endwith %}<br />
{% with lead_developer as person %}<br />
&nbsp;&nbsp;{% include &#8220;name.html&#8221; %}<br />
{% endwith %}</p>
</blockquote>
<p>It seems like overkill for our <code>name.html</code> example, but there are plenty of situations&#8212;I just found one, hence this post&#8212;where it makes sense to factor out code into an include: being able to fiddle with the template context before including it is a lightweight alternative to template tags and a tidy alternative to dumping the HTML right there in the primary template.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/05/29/variable-assignment-in-django-templates-sort-of/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Django laziness at all levels</title>
		<link>http://www.jpstacey.info/blog/2008/05/12/django-laziness-at-all-levels/</link>
		<comments>http://www.jpstacey.info/blog/2008/05/12/django-laziness-at-all-levels/#comments</comments>
		<pubDate>Mon, 12 May 2008 19:03:55 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[hacking]]></category>

		<category><![CDATA[layers]]></category>

		<category><![CDATA[chaining]]></category>

		<category><![CDATA[django]]></category>

		<category><![CDATA[evaluation]]></category>

		<category><![CDATA[filter]]></category>

		<category><![CDATA[forms]]></category>

		<category><![CDATA[lazy]]></category>

		<category><![CDATA[modelform]]></category>

		<category><![CDATA[newforms]]></category>

		<category><![CDATA[orm]]></category>

		<category><![CDATA[queryset]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/05/12/django-laziness-at-all-levels/</guid>
		<description><![CDATA[Lazy evaluation in Django means you can wait till the last possible moment before modifying what you want from the database.]]></description>
			<content:encoded><![CDATA[<p>Following on from Simon Willison&#8217;s <a href="http://simonwillison.net/2008/May/1/orm/">recent post about Django&#8217;s ORM</a>, I&#8217;ve found both the lazy evaluation and chaining properties of Django&#8217;s querysets to be really useful quite deep within Django&#8217;s own view-layer framework.</p>
<p>Django has its own library for building forms, currently called <code>newforms</code> (to distinguish it from the old library, deprecated but left around for compatibility reasons). The <code>ModelForm</code> class in this library interrogates a particular class from the model layer and builds an HTML form&#8212;complete with post-submit validation, field widgets, the lot. The beauty of this is that you can run:</p>
<blockquote class="code"><p>
import django.newforms as forms<br />
from myproject.models import MyObject</p>
<p>class MyForm(forms.ModelForm):<br />
&nbsp;&nbsp;&nbsp;&nbsp;class Meta:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;model = MyObject
</p>
</blockquote>
<p>and <em>that&#8217;s it</em>: you can then use an instance of MyForm anywhere in your view layer to add or edit MyObject instances in the database.</p>
<p>Problems arise, of course, when the automatically generated form doesn&#8217;t provide exactly what you want. It might, for example produce select dropdowns for you with thousands of items, whereas with better knowledge of the page your user is on then you might be able to whittle that list down to a handful of items. </p>
<p>Let&#8217;s imagine your objects can belong to Django users i.e. in your <code>models.py</code> you have:</p>
<blockquote class="code"><p>
class MyObject(models.Model):<br />
&nbsp;&nbsp;&nbsp;&nbsp;owner = models.ForeignKey(User)
</p>
</blockquote>
<p>This means that when you try to create an object, the HTML from <code>newforms</code> will give you a select dropdown of all the users in the database. But what if you have loads of inactive users, cluttering up the dropdown? How do you get rid of them with the minimal amount of coding i.e. without having to build your own form if possible?</p>
<p>Luckily, <code>newforms</code> sticks the queryset it creates somewhere that you can fiddle with it. With lazy evaluation, you get a chance to change the queryset before it hits the database; with chaining, you don&#8217;t have to worry about rebuilding the queryset yourself, but can just add to it instead. </p>
<p>In the <code>MyForm</code> class, you can override the inherited <code>__init__</code> method as follows:</p>
<blockquote class="code"><p>
def __init__(self, *a, **kw):<br />
&nbsp;&nbsp;&nbsp;&nbsp;forms.ModelForm.__init__(self, *a, **kw)<br />
&nbsp;&nbsp;&nbsp;&nbsp;self.fields['owner'].queryset = self.fields['owner'].queryset.filter(is_active=True)
</p>
</blockquote>
<p>This calls the existing superclass constructor first, passing along any values. Then, after the queryset has been created for the select dropdown <em>but before it&#8217;s been evaluated</em>, the queryset is modified to whittle down the resultant set of users to only those where the &#8220;is_active&#8221; flag is set to True.</p>
<p>Laziness and chaining make Django&#8217;s ORM layer very effective; <code>forms</code> and <code>newforms</code> help to greatly reduce the amount of coding required by the view and control layers; together they can really simplify a codebase.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/05/12/django-laziness-at-all-levels/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Deserving of a serious LAMPing</title>
		<link>http://www.jpstacey.info/blog/2008/03/31/deserving-of-a-serious-lamping/</link>
		<comments>http://www.jpstacey.info/blog/2008/03/31/deserving-of-a-serious-lamping/#comments</comments>
		<pubDate>Mon, 31 Mar 2008 11:09:47 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[culture]]></category>

		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[layers]]></category>

		<category><![CDATA[subtleties]]></category>

		<category><![CDATA[constrain]]></category>

		<category><![CDATA[database]]></category>

		<category><![CDATA[foreign]]></category>

		<category><![CDATA[integrity]]></category>

		<category><![CDATA[key]]></category>

		<category><![CDATA[lamp]]></category>

		<category><![CDATA[mysql]]></category>

		<category><![CDATA[postgresql]]></category>

		<category><![CDATA[primary]]></category>

		<category><![CDATA[referential]]></category>

		<category><![CDATA[wtf]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/03/31/deserving-of-a-serious-lamping/</guid>
		<description><![CDATA[Reinventing primary keys, one horrifying integrity error at a time.]]></description>
			<content:encoded><![CDATA[<p>The LAMP-stack community frequently shows their disdain for foreign and primary keys in databases, and sometimes with reason borne of experience. MySQL historically has been little more than a nice language for comparing a set of unrelated spreadsheets, so referential integrity has had to happen at the application layer or not at all. As such, careful MySQL users put a lot of work into ensuring referential integrity, without the help of the database.</p>
<p>But the eyes of even the most hardened LAMPer would widen, if he were to dip into a conversation to find someone saying the following about something they&#8217;ve built over PostgreSQL:</p>
<blockquote><p>Yeah, I could add the current date/time to the end, so as long as you don&#8217;t add more than one [entry] with the same name within 1 second, it&#8217;ll be fine.</p>
</blockquote>
<p>It might take you a while to work out (a) what that&#8217;s referring to (b) what kind of error in thinking it demonstrates and (c) what it implies about the quality of the underlying code. By that time&#8212;if you&#8217;ve worked at all with that sort of programming&#8212;your head may well be in your hands.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/03/31/deserving-of-a-serious-lamping/feed/</wfw:commentRss>
		</item>
		<item>
		<title>FixMySpine</title>
		<link>http://www.jpstacey.info/blog/2008/01/18/fixmyspine/</link>
		<comments>http://www.jpstacey.info/blog/2008/01/18/fixmyspine/#comments</comments>
		<pubDate>Fri, 18 Jan 2008 20:56:04 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[culture]]></category>

		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[useability]]></category>

		<category><![CDATA[comparison]]></category>

		<category><![CDATA[consultants]]></category>

		<category><![CDATA[facebook]]></category>

		<category><![CDATA[fixmystreet]]></category>

		<category><![CDATA[foss]]></category>

		<category><![CDATA[mysociety]]></category>

		<category><![CDATA[nhs]]></category>

		<category><![CDATA[open]]></category>

		<category><![CDATA[source]]></category>

		<category><![CDATA[spine]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/01/18/fixmyspine/</guid>
		<description><![CDATA[FixMyStreet is getting some great press, this time a Guardian article comparing it favourably to Facebook. We were lucky to have Tom Steinberg at the fourth Oxford Geek Night, and his plucky lieutenant Matthew Somerville (I may get in trouble for that) back at the third OGN. They&#8217;re both fascinating speakers (and I still turn [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://fixmystreet.com/">FixMyStreet</a> is getting some great press, this time <a href="http://www.guardian.co.uk/technology/2008/jan/17/socialnetworking">a Guardian article comparing it favourably to Facebook</a>. We were lucky to have <a href="http://www.mysociety.org/moin.cgi/TomSteinberg">Tom Steinberg</a> at the <a href="http://oxford.geeknights.net/2007/nov-28th/">fourth Oxford Geek Night</a>, and his plucky lieutenant <a href="http://www.dracos.co.uk/">Matthew Somerville</a> (I may get in trouble for that) back at the <a href="http://oxford.geeknights.net/2007/july-25th/">third OGN</a>. They&#8217;re both fascinating speakers (and I still turn red at the way my nerves made me hustle Tom off the stage); but, more than that, through the sites mentioned in the Guardian article above, they and many other unsung heroes have brought about real social change.</p>
<p>The comparison in the Guardian website is with <a href="http://www.facebook.com/">Facebook</a> (which is <a href="http://www.guardian.co.uk/technology/2008/jan/14/facebook">turning rapidly more socially evil</a> by the minute anyway). I think it would be more illuminating to compare mySociety sites with such large, government-commissioned (and consultant-propelled) projects like the <a href="http://www.connectingforhealth.nhs.uk/systemsandservices/spine">NHS Spine</a>. </p>
<p>The Spine is a vast, overarching superproject; it&#8217;s a messy amalgam of large, penny-pinching businesses; separation of responsibilities&#8212;bizarrely&#8212;is in part geographical, so despite purporting to provide a single system there&#8217;s no guarantee (outside of the weird steampunk astrolabe brains of consultants) that Yorkshire and Humber will be able to chat freely with the West Midlands. It&#8217;s been put together without any real thought about whether the problems tackled are the ones that the problem-sufferers (NHS staff and patients) encounter most often. In a nutshell, i&#8217;s overblown, overpriced and over the top. </p>
<p>But if mySociety had been brought in? You would have around a dozen projects, all quite tiny, and all solving fairly simple, easily-scoped problems. Most importantly, they would all stem from consulting the staff: each would have a valid reason for existing before even the planning began. The basic version of each site would be ready within six weeks, and a more polished version in three months. There&#8217;d be ongoing updates and improvements as user requests made them appear worth while ((the Spine, on the other hand, would shudder at the thought that the hoi polloi of front-line employees might dictate project direction, rather than a consultancy firm). And from the point of view of an end result, almost everything would be ready by now, in comparison to a couple of fringe benefits: it would be improving staff and patient experience <em>today</em>, across the country, in those specifically targeted areas, by a hundred times the effect the Spine will have, and for a hundredth of the cost.</p>
<p>mySociety produces perfect examples of the open-source maxim: find an itch, and scratch it. But what distinguishes them from almost every other <abbr title="free and open source">FOSS project</abbr> (apart from perhaps <a href="http://www.ubuntu.com/">Ubuntu</a>) is that they&#8217;re happy to treat <em>other people&#8217;s itches</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/01/18/fixmyspine/feed/</wfw:commentRss>
		</item>
		<item>
		<title>&#8220;You have to have something bad happen to you&#8221;</title>
		<link>http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/</link>
		<comments>http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/#comments</comments>
		<pubDate>Mon, 07 Jan 2008 12:05:11 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[hacking]]></category>

		<category><![CDATA[paradigms]]></category>

		<category><![CDATA[projects]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[bloat]]></category>

		<category><![CDATA[code]]></category>

		<category><![CDATA[copy]]></category>

		<category><![CDATA[debug]]></category>

		<category><![CDATA[ide]]></category>

		<category><![CDATA[paste]]></category>

		<category><![CDATA[rants]]></category>

		<category><![CDATA[reuse]]></category>

		<category><![CDATA[steve]]></category>

		<category><![CDATA[yegge]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/</guid>
		<description><![CDATA[Steve Yegge on code&#8217;s worst enemy:
&#8230; This brings us to the second obviously-bad thing that can go wrong with code bases: copy and paste. It doesn&#8217;t take very long for programmers to learn this lesson the hard way. It&#8217;s not so much a rule you have to memorize as a scar you&#8217;re going to get [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://steve-yegge.blogspot.com/">Steve Yegge</a> on <a href="http://steve-yegge.blogspot.com/2007/12/codes-worst-enemy.html">code&#8217;s worst enemy</a>:</p>
<blockquote><p>&#8230; This brings us to the second obviously-bad thing that can go wrong with code bases: copy and paste. It doesn&#8217;t take very long for programmers to learn this lesson the hard way. It&#8217;s not so much a rule you have to memorize as a scar you&#8217;re going to get whether you like it or not. Computers make copy-and-paste really easy, so every programmer falls into the trap once in a while. The lesson you eventually learn is that code always changes, always always always, and as soon as you have to change the same thing in N places, where N is more than 1, you&#8217;ll have earned your scar&#8230;.</p>
</blockquote>
<p>Code reuse is great, although some languages punish you for it: Coldfusion takes a performance hit on behalf of debug logging whenever it crosses a component boundary, even if debugging is turned off. And a lot of includes scattered across the place can make it difficult to track what&#8217;s going on (unless you use those very IDEs that Steve suggests treat code like heaps of dirt to be rearranged). I suppose ultimately it&#8217;s about developing an instinct for balancing short-term performance, ongoing maintainability and long-term scalability, and you only learn that by dint of many, many scars.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A complex CCK module in Drupal</title>
		<link>http://www.jpstacey.info/blog/2007/09/20/a-complex-cck-module-in-drupal/</link>
		<comments>http://www.jpstacey.info/blog/2007/09/20/a-complex-cck-module-in-drupal/#comments</comments>
		<pubDate>Thu, 20 Sep 2007 19:10:41 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[hacking]]></category>

		<category><![CDATA[projects]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[book]]></category>

		<category><![CDATA[cck]]></category>

		<category><![CDATA[database]]></category>

		<category><![CDATA[drupal]]></category>

		<category><![CDATA[example]]></category>

		<category><![CDATA[field]]></category>

		<category><![CDATA[format]]></category>

		<category><![CDATA[help]]></category>

		<category><![CDATA[module]]></category>

		<category><![CDATA[multiple]]></category>

		<category><![CDATA[submodule]]></category>

		<category><![CDATA[tutorial]]></category>

		<category><![CDATA[widget]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/09/20/a-complex-cck-module-in-drupal/</guid>
		<description><![CDATA[CCK is Drupal&#8217;s way of making rich content. It means that nodes of any content type can have any kind of data attached to them, so you can have e.g. a directory of superstore outlets, where the outlet records have their longitude and latitude (editable by a Google Map widget) whereas the contact records (e.g. [...]]]></description>
			<content:encoded><![CDATA[<p>CCK is Drupal&#8217;s way of making rich content. It means that nodes of any content type can have any kind of data attached to them, so you can have e.g. a directory of superstore outlets, where the outlet records have their longitude and latitude (editable by a Google Map widget) whereas the contact records (e.g. Sales Manager, South-East) can have a portrait photo, selected from an image gallery in a dropdown widget. (A note on terminology: widgets are the structures which are used to edit the CCK data, typically defined in the same CCK submodule as the data types).</p>
<p>There&#8217;s already <a href="http://drupal.org/node/106716">a tutorial with a CCK submodule</a> available. The premise of the sample module is to provide two fairly generic numerical formats. In principle that simplifies the submodule, but in practice it also means it&#8217;s difficult to work out precisely why particular programmatic choices were made and what you can tweak. Also, at work we wanted a much richer content type. Here&#8217;s what we wanted to display:</p>
<ol>
<li>Build an &#8220;Available in&#8221; field for e.g. all the different formats that a book might come in.</li>
<li>Record the dimensions DxWxH</li>
<li>And some dscriptive information</li>
<li>And let the user pick a thumbnail from a dropdown</li>
<li>And let all of this be done multiple times</li>
</ol>
<p>Here&#8217;s a mockup of what we wanted to appear on the admin page (excuse styling&#8212;Wordpress isn&#8217;t the best for this):</p>
<form method="post">
  <fieldset><br />
    <legend>Available in</legend></p>
<div style="3px;">
      <label>Brief description</label><br />
     <label>Width/ins</label><br />
      <label>Height/ins</label><br />
      <label>Depth/ins</label></p>
<p>      <label>Thumbnail</label></p></div>
<div style="3px;">
      <label>Brief description</label><br />
     <label>Width/ins</label><br />
      <label>Height/ins</label><br />
      <label>Depth/ins</label></p>
<p>      <label>Thumbnail</label></p></div>
<div style="3px;">
      <label>Brief description</label><br />
     <label>Width/ins</label><br />
      <label>Height/ins</label><br />
      <label>Depth/ins</label></p>
<p>      <label>Thumbnail</label></p></div>
</p>
<p></fieldset><br />
</form>
<p>And here&#8217;s sort of what we wanted on the front end (again, sorry for the HTML: it&#8217;s table-heavy as it&#8217;s a one off):</p>
<table style="auto" cellpadding="3">
<tr>
<th colspan="9">Available in</th>
</tr>
<tr>
<th colspan="3">Hardback</th>
<th colspan="3">Paperback</th>
<th colspan="3">Trade p/bk</th>
</tr>
<tr>
<th></th>
<td>ins</td>
<td>cm</td>
<th></th>
<td>ins</td>
<td>cm</td>
<th></th>
<td>ins</td>
<td>cm</td>
</tr>
<tr>
<th>W</th>
<td>5.1</td>
<td>13</td>
<th>W</th>
<td>5.1</td>
<td>13</td>
<th>W</th>
<td>5.1</td>
<td>13</td>
</tr>
<tr>
<th>H</th>
<td>7.6</td>
<td>19.2</td>
<th>H</th>
<td>7.6</td>
<td>19.2</td>
<th>H</th>
<td>7.6</td>
<td>19.2</td>
</tr>
<tr>
<th>D</th>
<td>0.79</td>
<td>2.0</td>
<th>D</th>
<td>0.79</td>
<td>2.0</td>
<th>D</th>
<td>0.79</td>
<td>2.0</td>
</tr>
<tr>
<th colspan="3"><img src="http://ec1.images-amazon.com/images/I/01%2BxJfQvi2L.jpg" alt="" width="49" height="75" /></th>
<th colspan="3"><img src="http://ec1.images-amazon.com/images/I/01%2BxJfQvi2L.jpg" alt="" width="49" height="75" /></th>
<th colspan="3"><img src="http://ec1.images-amazon.com/images/I/01%2BxJfQvi2L.jpg" alt="" width="49" height="75" /></th>
</tr>
</table>
<p>It was difficult, from the simplistic submodule available, to work out exactly how you leverage complex editing widgets, and how you get CCK to save all the database information in the five columns we needed: description, thumbnail image reference and three dimensions in inches. What&#8217;s worse is that a CCK submodule with an incomplete set of hook functions seems to do a fandango on certain areas of the database (possibly the cacheing of certain bits of the module&#8217;s behaviour): certainly developing a CCK submodule was quite painful, as the process of trial and error frequently required a database restore so as to try again. That tutorial does warn that &#8220;all hooks are required. CCK expects them to all be present and will not function correctly if some are missing.&#8221; But there&#8217;s a world of developer pain in those brief phrases.</p>
<p>Since <a href="http://lists.drupal.org/archives/support/2007-07/msg00063.html">I originally mentioned the problems we were having</a> on the development mailing lists, a couple of people have asked me how to build a CCK submodule to support rich fields. With this in mind my employers <a href="http://torchbox.com/">Torchbox</a> have very gracefully let me make the module we built public, with some minor edits (the client&#8217;s site isn&#8217;t live yet, so names and details changed to protect the innocent). </p>
<p><a href="/blog/files/drupal/modules/cck_book.module">The module is available here.</a> It consists of 4 1/2 pairs of functions, as follows:</p>
<ol>
<li>
<div>Declare:</div>
<ol type="a">
<li>field types that the module supports</li>
<li>widgets that the module supports, for editing fields on the node-edit page</li>
</ol>
</li>
<li>
<div>Settings for:</div>
<ol type="a">
<li>field (so settings inherent to the way that particular field is stored e.g. decimal accuracy for numeric values)</li>
<li>widgets (so e.g. the image gallery that populates the dropdown for the wireframes)</li>
</ol>
</li>
<li>
<div>Handlers for:</div>
<ol type="a">
<li>field, so what happens to it when a node is loaded</li>
<li>widget, so pre-processing of the field to fit a HTML form, or producing a chunk of Form API, or post-processing the HTML form into a database-saveable format.
  </li>
</ol>
</li>
<li>BONUS UNNECESSARY FUNCTION: cck_book_complex_input just produces the Form API for function 3b. Ignore this one!</li>
<li>
<div>Formatters, which give you output options for fields on the &#8220;Display Fields&#8221; page.</div>
<ol type="a">
<li>Declaring formatters</li>
<li>Formatters</li>
</ol>
</li>
</ol>
<p>A few extra pointers:</p>
<ol>
<li>CCK does most stuff for you, so you don&#8217;t need to actually load/save field contents to the database; declaring the columns for widgets and fields is enough.</li>
<li>If you&#8217;re in the developing phase with your CCK submodule, back up the database first. See above.</li>
<li>We sidestepped formatters altogether as they don&#8217;t cope with e.g. multiple field values that need a header value. Instead, we just overrode <code>theme('field')</code>. One thing, though: you do need some formatters present, or the admin configuration page for &#8220;Display Fields&#8221; defaults every dropdown to &#8220;&lt;Hidden&gt;&#8221;, and you can&#8217;t get anything to appear.</li>
<li>To reiterate, CCK needs all hooks present in its submodules from the start. The further you get from Drupal core, the more bleeding-edge APIs will get.</li>
</ol>
<p>Note that as I say we had to peer into the node (use <code>var_dump($node)</code> and search for the right array) and then override the theme, because we wanted a fancy header to our field. But that was pretty painless&#8212;mostly a matter of knowing one&#8217;s PHP rather than one&#8217;s Drupal&#8212;and it all worked smoothly otherwise. And we ended up with by and large exactly what we wanted. It works and, in retrospect, Drupal has helped us to write readable, maintainable code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/09/20/a-complex-cck-module-in-drupal/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Team Drupal FTW!</title>
		<link>http://www.jpstacey.info/blog/2007/06/26/team-drupal-ftw/</link>
		<comments>http://www.jpstacey.info/blog/2007/06/26/team-drupal-ftw/#comments</comments>
		<pubDate>Tue, 26 Jun 2007 11:39:54 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[discussion]]></category>

		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[projects]]></category>

		<category><![CDATA[cms]]></category>

		<category><![CDATA[drupal]]></category>

		<category><![CDATA[feedback]]></category>

		<category><![CDATA[framework]]></category>

		<category><![CDATA[site]]></category>

		<category><![CDATA[teamsugar]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/06/26/team-drupal-ftw/</guid>
		<description><![CDATA[Coming to the end of the Drupal project on which I&#8217;m currently working, I spotted someone else&#8217;s brand new site on drupal.org: TeamSugar.
The hallmark of a good frameworked site is that it&#8217;s not easy to guess which framework was used, and TeamSugar manages that admirably. While I can&#8217;t really comment on the design&#8212;I find most [...]]]></description>
			<content:encoded><![CDATA[<p>Coming to the end of the <a href="http://drupal.org/">Drupal</a> project on which I&#8217;m currently working, I spotted <a href="http://drupal.org/node/116578" title="TeamSugar, a social networking site for women">someone else&#8217;s brand new site</a> on drupal.org: <a href="http://teamsugar.com/">TeamSugar</a>.</p>
<p>The hallmark of a good frameworked site is that it&#8217;s not easy to guess which framework was used, and TeamSugar manages that admirably. While I can&#8217;t really comment on the design&#8212;I find most networking sites pretty busy, and this is no exception&#8212;it certainly feels like a lot of hard work is distancing the user experience from the limitations of the framework, and that&#8217;s admirable from a usability perspective. The fewer visitors jumping through hoops to indulge the whims of your CMS the better.</p>
<p>There are a couple of interesting observations in that thread, mostly because they&#8217;re guarded criticism coming from an otherwise happy user of the framework:</p>
<blockquote><p>&#8230; We have four app servers now, I believe, and a dedicated database server. We have also extensively edited the code. The architecture of drupal, unfortunately, lends itself to doing things like issuing one query per module per node on a page. For our 8 content sites this isn&#8217;t too bad because they&#8217;re easily cached and don&#8217;t make use of many modules. For TeamSugar it&#8217;s much worse because each feature generally requires at least one module. We cache where we can and refactor code elsewhere&#8230;. [<a href="http://drupal.org/node/116578#comment-197521">link to 1971521</a>]</p>
</blockquote>
<blockquote><p>&#8230; When you&#8217;re creating web applications you&#8217;re typically going for one of three things: speed/scalability, flexibility, or maintainability. Drupal is high on flexibility, average on maintainability, and poor on speed, in my opinion. If your priority is maintainability then I&#8217;d go for one of the RAD environments like Rails or CakePHP. If speed is your priority then I&#8217;d write your own lightweight framework, or whatever, and do it yourself&#8230;. [<a href="http://drupal.org/node/116578#comment-198497">link to 198497</a>]
</p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/06/26/team-drupal-ftw/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Save our servers!</title>
		<link>http://www.jpstacey.info/blog/2007/06/11/save-our-servers/</link>
		<comments>http://www.jpstacey.info/blog/2007/06/11/save-our-servers/#comments</comments>
		<pubDate>Mon, 11 Jun 2007 16:44:13 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[news]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[bandwidth]]></category>

		<category><![CDATA[cache]]></category>

		<category><![CDATA[coldfusion]]></category>

		<category><![CDATA[etag]]></category>

		<category><![CDATA[headers]]></category>

		<category><![CDATA[html]]></category>

		<category><![CDATA[http]]></category>

		<category><![CDATA[http-equiv]]></category>

		<category><![CDATA[if-modified-since]]></category>

		<category><![CDATA[if-none-match]]></category>

		<category><![CDATA[last-modified]]></category>

		<category><![CDATA[meta]]></category>

		<category><![CDATA[php]]></category>

		<category><![CDATA[response]]></category>

		<category><![CDATA[server]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/06/11/save-our-servers/</guid>
		<description><![CDATA[Sick and tired of getting a million hits, all to the same page, which more often than not hasn&#8217;t been updated in the mean time? Want to reduce your bandwidth and server-time loads without necessarily impairing your visitors&#8217; experience of your site?
If you haven&#8217;t ever had cause to use it, there&#8217;s a standard called ETag [...]]]></description>
			<content:encoded><![CDATA[<p>Sick and tired of getting a million hits, all to the same page, which more often than not hasn&#8217;t been updated in the mean time? Want to reduce your bandwidth and server-time loads without necessarily impairing your visitors&#8217; experience of your site?</p>
<p>If you haven&#8217;t ever had cause to use it, there&#8217;s a standard called ETag out there which you can probably implement using existing technology that can boost the efficiency of your content delivery a hundredfold. Along with the longer-standing HTTP header Last-Modified it can be used with compliant browser/aggregator software to drastically lower your overheads, while scarcely impacting on your non-compliant users. And although the two standards see most use in the blogosphere, they can be used for anything else from a company&#8217;s record in a directory to enormous high-resolution image feeds from astronomy laboratories.</p>
<p>The idea is that you embed in every outgoing page request a couple of HTTP header lines. That&#8217;s easier for the total n00b than it sounds: you can do it in one line each with, say, the PHP function <a href="http://uk2.php.net/header"><code>header()</code></a> or the Coldfusion tag <a href="http://mxblogspace.journurl.com/users/admin/index.cfm?mode=article&#38;entry=1853"><code>&lt;cfheader&gt;</code></a>, or even in the HTML if you don&#8217;t have that level of access, using <a href="http://www.i18nguy.com/markup/metatags.html"><code>&lt;meta http-equiv=.../&gt;</code></a>. The point is that you set the following two flags on the &#8220;envelope&#8221; that surrounds the page you send to the browser:</p>
<blockquote class="code"><p>
Last-Modified: Wed, 15 Nov 2006 18:20:54 +0000<br />
ETag: &#8220;78c4d3d8-1834-11dc-8314-0800200c9a66&#8243;
</p>
</blockquote>
<p>Typically for the first field you&#8217;ll want e.g. the latest date from your RSS feed, or the date on which a semi-static page was last edited. The second field is really up to you: if you never go back and edit posts without changing the published date then (a) well done you&#8212;there&#8217;s a space in heaven already reserved&#8212;and (b) you can just calculate ETag from the published date. It can actually <em>be</em> the published date if you&#8217;re a bit slack, although you might want to hash it instead, in the way that you might with passwords, to avoid any sloppy client software depending on ETags being dates.</p>
<p>What happens next? Well, you won&#8217;t see anything at first. But compliant software that&#8217;s visited your site before will start sending <em>you</em> two headers that correspond to your original submissions:</p>
<blockquote class="code"><p>
If-Modified-Since: Wed, 15 Nov 2006 18:20:54 +0000<br />
If-None-Match: &#8220;78c4d3d8-1834-11dc-8314-0800200c9a66&#8243;
</p>
</blockquote>
<p>The idea is that you make sure that you can compare these to the values you&#8217;re about to send out, quite early on in your workflow. That way, if they match, you can immediately terminate all further work and just send a &#8220;304: Not Modified&#8221; HTTP header. The result? Well, with quite complex pages, involving the computation of tag clouds and term hierarchies and archive structures, you can work out quite early on whether it&#8217;s worth bothering, or whether the remote client will know exactly what to do if you just tell it, concisely, that nothing has changed since it last looked.</p>
<p>Word to the wise, though: if you are going to send a 304, you should also send your two headers as you always would. If you don&#8217;t then you only win out every other time, because the remote client will see the absence of ETag and Last-Modified headers and duly forget the ones it had in its cache.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/06/11/save-our-servers/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
