<?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/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jpstacey.info/blog</link>
	<description>Garbage collection, in a very real sense</description>
	<pubDate>Thu, 17 Jul 2008 19:08:52 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<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[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, [...]]]></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>
		<item>
		<title>Now that&#8217;s magic (quotes)</title>
		<link>http://www.jpstacey.info/blog/2006/08/15/now-thats-magic-quotes/</link>
		<comments>http://www.jpstacey.info/blog/2006/08/15/now-thats-magic-quotes/#comments</comments>
		<pubDate>Tue, 15 Aug 2006 20:37:01 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[import/export]]></category>

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2006/08/15/now-thats-magic-quotes/</guid>
		<description><![CDATA[If your web application ensures that all your incoming CGI variables are free of the most common source of malicious site damage, can you stop worrying?
I wondered this as I got far enough into a PHP publishing system that I had to start thinking about adding new content through the system (rather than just jamming [...]]]></description>
			<content:encoded><![CDATA[<p>If your web application ensures that all your incoming CGI variables are free of the most common source of malicious site damage, can you stop worrying?</p>
<p>I wondered this as I got far enough into a PHP publishing system that I had to start thinking about adding new content through the system (rather than just jamming it into the database by hand, which is why the previous incarnation has sadly fallen into disuse). As it&#8217;s typically configured, PHP will add backslashes to anything it doesn&#8217;t trust: hence the comment &#8220;it&#8217;s a great site you&#8217;ve got here&#8221; will, when submitted by a POST request, become &#8220;it&#8217;s a great site you&#8217;ve got here&#8221;. Whether or not your server does this automatically can be checked by calling the function <code>magic_quotes_gpc()</code> (I realised only the other day that &#8220;gpc&#8221; stood for &#8220;GET, POST and cookies:&#8221; I probably have some catching up to do). In performing this blanket adding of slashes, PHP prevents the unwary coder from leaving his site open to both unintentional database hiccups and intentional malevolent attacks, the <a href="http://www.unixwiz.net/techtips/sql-injection.html" title="SQL Injection Attacks by Example">SQL injection attack</a>. </p>
<p>All well and good, but my application is heavily object-oriented. Such objects store whatever content you give them, as well as optionally writing it to the database. If I want these objects to persist (even for the course of a single request) then any access to their internal storage must yield sensible data: <b>those slashes have to disappear</b> before the articles appear in an RSS feed, or on the website itself. So when the CGI environment gives slash-added content to an object, the object needs to know to both add it to the database verbatim and to produce it for viewing with the slashes removed. It can either do this by storing it in a slash-removed state or by placing a filter on its outputs.</p>
<p>There&#8217;s a further complication, in that content can also be written to an object by the PHP application itself: the publishing of all my unpublished articles, for example, would change the status of their accompanying objects without reference to any CGI variable. If I assumed all of this content had had its slashes escaped, then this article, for example, would lose all of its &#8217; text, because the object would assume they&#8217;d been added by PHP&#8217;s internals: in my second paragraph, the &#8220;after&#8221; string would look like the &#8220;before&#8221; string, and the &#8220;before&#8221; string would instead break the database insertion. In addition, what if the server is reconfigured? Can I trust my hosting company to never change the configuration of PHP, even accidentally during an upgrade?</p>
<p>I found myself lost in a maze of adding, removing and then adding slashes, with no clear way of deciding. Suddenly I decided: why not use one of PHP&#8217;s major downsides&#x2014;that it doesn&#8217;t support persistence of objects from one request to the next very well, and hence each action is fighting against the overhead of constantly recreating and recompiling code&#x2014;to ascertain which input/output processes were the most frequent (and most public) and hence needed to be the fastest? I drew <a href="/blog/files/image/magic_sql_slashes.gif" title="GIF image of a typical object's workflow">a flowchart of a typical object&#8217;s behaviour</a> and, by identifying which channels could be safely bottlenecked, arrived at a reasonable solution to the problem.</p>
<p>From my phrasing it&#8217;s clear that it was a foregone conclusion: I wanted, more than anything else, for content to flow straight from the database (through the object if applicable) to the user. This content needed to stay in any object in a simple, de-slashed form, so it could flow and flow as long as the object was in existence. That meant that incoming CGI content could not be stored with its added slashes intact. Counter-intuitively, then, my solution was to <b>undo PHP&#8217;s default safety mechanisms</b>, unescaping the CGI content and storing it raw, and then without fail adding slashes to anything that CGI or my application wanted to add to the database. This would be my bottleneck: everything else would be as fast as it could be.</p>
<p><b>Exit gracefully:</b> ensuring all incoming content can be added to the database safely is not necessarily the most efficient or desirable long-term solution. By examining the likely workflows for content, it&#8217;s possible to make pragmatic decisions on where content should be pre-processed and where it should be left alone. Consider all your overheads, including that of short-term programming and long-term cumulative processing time: this will vary depending on your environment. Also, if you&#8217;re aware of a safety net, over the presence of which you have minimal control, account for the possibility that someone might one day remove it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2006/08/15/now-thats-magic-quotes/feed/</wfw:commentRss>
		</item>
		<item>
		<title>This space intentionally left blank</title>
		<link>http://www.jpstacey.info/blog/2006/07/11/this-space-intentionally-left-blank/</link>
		<comments>http://www.jpstacey.info/blog/2006/07/11/this-space-intentionally-left-blank/#comments</comments>
		<pubDate>Tue, 11 Jul 2006 11:22:23 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[import/export]]></category>

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2006/07/11/this-space-intentionally-left-blank/</guid>
		<description><![CDATA[I&#8217;ve been asked a couple of times recently, as part of separate projects, to split the results of a SQL query on whitespace within. Simply put, how does one go from:
foo
foo bar
quux
blort wuu spong

to the expanded form:
foo
foo
bar
quux
blort
wuu
spong

efficiently and cleanly, only using SQL? (In case anyone&#8217;s worried, I&#8217;ve scrubbed the data sets of any personal details [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been asked a couple of times recently, as part of separate projects, to split the results of a SQL query on whitespace within. Simply put, how does one go from:</p>
<blockquote><p>foo<br />
foo bar<br />
quux<br />
blort wuu spong</p>
</blockquote>
<p>to the expanded form:</p>
<blockquote><p>foo<br />
foo<br />
bar<br />
quux<br />
blort<br />
wuu<br />
spong</p>
</blockquote>
<p>efficiently and cleanly, <em>only using SQL? </em>(In case anyone&#8217;s worried, I&#8217;ve scrubbed the data sets of any personal details they might have previously contained: any resemblance to the real Blort Wuu-Spong is entirely coincidental.)</p>
<p>I finally decided it wasn&#8217;t possible, and although without the pure mathematics to back me up I could have kept huntingâ€”partial solutions involving a self-join for each whitespace splitting kept rearing their headsâ€”what finally convinced me was comparing the behaviour of SQL with that of XSL(T). The two are more alike than you might think; and no, I don&#8217;t mean SQL and XQuery, although that easy comparison provides a clue for the underlying similarity.</p>
<p>In XSL(T), the XML node in your original document(s) is in a sense king: it&#8217;s considered bad form (and is at any rate inefficient) to do data management on some transient data set, created within the template. Loops work best over nodesets rather than with some sort of conditional or from/to structure. This stems from XSL(T)&#8217;s underlying functional paradigm, where each nodeset is created</p>
<p>Of course, it&#8217;s always possible to twist non-functional behaviour out of the stylesheet (and most real-world solutions have to take a pragmatic approach to such programmatic purity) and interpreter-specific kluges exist to node-ize strings based on some non-XML token, but the language works fastest and cleanest when it&#8217;s hanging functions off nodes.</p>
<p>In SQL, the equivalent to the node in an XML document is the row in a query. Rows are passed around, compared with other rows based on the content of some of their cells, tied together and discarded, but very rarely can rows be created out of thin air. The closest one gets is the LEFT/RIGHT OUTER JOIN where the ON-condition is not satisfied: then the left-hand row, rather than being discarded as in the INNER JOIN, is in a sense tied to a row of NULLs. Although that equates to it being tied to no row at all, then when the SQL99 dust settles and post-processing can begin, NULLs can be reinterpreted (Coldfusion does this without being asked, for example).</p>
<p>So to create new rows, one can UNION two rowsets, or entangle the rowsets with some sort of a JOIN, but in simplest, non-iterative SQL, there <em>ought to be </em>no easy way to make one row magically split into two, or maybe three, or maybe four, based on its textual content. It breaks the underlying principle, that rows should flow through the SQL into bit-buckets or the STDOUT tray, but shouldn&#8217;t be tossed into the stream with flamboyant verve like chillis into a stir-fry.</p>
<p><strong>Exit gracefully:</strong> regardless of the data itself, the data <em>model </em>that a given language&#8217;s designers had in mind can have the most effect on what&#8217;s plausible to do in the language. Almost all languages evolve through proprietary extensions until they can do associative arrays, every kind of loop structure and, if left alone for long enough, GOTOs, but being able to complete a task with a given language is not the same as being able to complete it, for a sufficiently large data set, before the death of your server, your development team or the universe.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2006/07/11/this-space-intentionally-left-blank/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
