Just A Summary : http://www.bofh.org.uk/articles.rss en-us 40 Piers Cawley Practices Punditry Work with us <p>If the last post about our Javascript issues didn&#8217;t put you off, then you might be interested to know that we&#8217;re <a href="http://www.amazingtunes.com/jobs">hiring</a>. If you&#8217;re an experienced, test infected Ruby on Rails programmer with some Javascript and a real world consumer website or two under your belt, and you&#8217;re happy to work in Newcastle upon Tyne, then we definitely want to hear from you. I&#8217;d probably be interested in at least hearing from you if you&#8217;re an experienced dynamic language programmer who has only recently made (or is considering making) the switch to Ruby and Rails. It&#8217;s only syntax after all.</p> <p>The money&#8217;s decent, the work is interesting, the people (well, apart from me, obviously) are great, and Newcastle&#8217;s a fantastic city. Drop me a line, ping me on <span class="caps">AIM</span>/gTalk/Twitter or just send your CV to the <a href="mailto:jobs@amazing-media.com">jobs@amazing-media.com</a>.</p> Thu, 03 Jul 2008 06:00:00 -0500 urn:uuid:cbbd49fd-95b1-471f-ac80-477fe3338e4c pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/07/03/work-with-us#comments jobs amazingtunes ruby javascript http://www.bofh.org.uk/articles/2008/07/03/work-with-us Usability testing (throws) rocks <p>Usability testing is wonderful. But wow, its humiliating.</p> <p>I&#8217;ve spent the last few weeks working on the <a href="http://www.amazingtunes.com">Amazingtunes</a> in page player. Amazingtunes is a music site, so we need to play music. However, we don&#8217;t like the way that most music sites work; either the music stops as you go from one page to another, or the player is a huge Flash app running in its own window. There has to be a better way. There needs to be a popup window if you want to eliminate stop/start behaviour, but there&#8217;s surely no reason not to keep the controls on the main page.</p> <p>So, we set about writing somthing that did just that. We settled on using Jeroen Wijering&#8217;s excellent <a href="http://www.jeroenwijering.com/?item=JW_FLV_Player">flvPlayer</a>, which handles the media formats we need and has good Javascript control and communications. This sits in the child window and we use Javascript cross-window communication to have a player controller in the main window that looks something like:</p> <div class="thumbnail"><a href="http://skitch.com/pdcawley/xy5m/piers-cawley-on-amazingtunes.com"><img src="http://img.skitch.com/20080703-58ianuwrptmeysscfkse3bm9i.preview.jpg" alt="Piers Cawley on amazingtunes.com" /></a><br /><span style="font-family: Lucida Grande, Trebuchet, sans-serif, Helvetica, Arial; font-size: 10px; color: #808080">Uploaded with <a href="http://plasq.com/">plasq</a>&#8217;s <a href="http://skitch.com">Skitch</a>!</span></div> <p>This is all done in <span class="caps">HTML</span> and and Javascript, the progress bar does the Safari trick of running behind the tune data links, the buttons do their <span class="caps">AJAX</span> magic and the whole thing is rather slick, though I say so myself.</p> <p>At least, we thought it was slick until we pointed the <a href="http://www.usertesting.com/">usertesting.com</a> legions at it. Without exception, they ignore the in page player, foreground the popup and use the teeny weeny controls on the flash player. Originally, the popup window didn&#8217;t even display any transport controls, it just had a picture of some speakers and some text asking the user not to close it because it was playing the tunes. We added transport controls as a stopgap while we made the in page player work properly.</p> <p>I sound like I&#8217;m whinging don&#8217;t I? It&#8217;s certainly a blow to the ego to see something we spent so much time and attention on being ignored by our sample users. On at least one occasion, while watching the screencasts I found myself boggling at the things the users did, and if I didn&#8217;t shout &#8220;Just play some bloody music!&#8221; at the screen, then I came worryingly close.</p> <p>It would be easy to retreat into a state of denial: &#8220;They&#8217;re not our target users! They&#8217;re stupid! They&#8217;re American! If they would only magically intuit the way we think they should use the site!&#8221;. And maybe it would be comforting to do so, for a while. The right thing to do is to suck it up &#8211; take away from those videos the sure and certain knowledge that bits of the site don&#8217;t work and do something about it.</p> <p>We may dislike the &#8216;popup window for transport controls&#8217; model of controlling music playback, but users are cool with it. And it&#8217;s not as if the work we did on making the in page player work is going to be wasted &#8211; widget is straightforwardly event driven so it&#8217;ll work just as well in the popup window, and the communication protocol will be much simpler. Having the player in its own window means we&#8217;ll be able to extend its interface in ways that would be hard when the player had to share window space with the rest of the page. In the end, it&#8217;s all good.</p> <p>But&#8230; damn that in page player was sweet. I learned Javascript as I wrote it (mostly by pretending it was Perl with odd syntas) and I&#8217;m bloody proud of it. I&#8217;ll happily replace it with the next iteration (which I&#8217;m already working on), but it&#8217;ll be with a pang of remorse all the same.</p> Thu, 03 Jul 2008 04:55:00 -0500 urn:uuid:c3e1ff9d-3a90-4f3d-8cbc-706f8fb61b85 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/07/03/usability-testing-throws-rocks#comments amazingtunes practiceofprogramming usabilitytesting javascript http://www.bofh.org.uk/articles/2008/07/03/usability-testing-throws-rocks Announcing Announcements for Ruby <p>I&#8217;ve just pushed a just about usable (but horribly untested) port of Vassili Bykov&#8217;s very lovely Smalltalk <a href="http://www.cincomsmalltalk.com/userblogs/vbykov/blogView?showComments=true&#38;entry=3310034894">Announcements framework</a> onto github. It&#8217;s a very raw port at the moment (the interface isn&#8217;t what you&#8217;d call idiomatic ruby yet), but I shall be working on that soon. Documentation (beyond a synopsis in the readme file) is nonexistent, but I reckon that there&#8217;s the core of something useful there (I&#8217;ve got plans for using it in Typo as the basis of a Wordpressesque plugin architecture and I need it for my Sooper Sekrit Project too&#8230;).</p> <p>Expect some more details on the whats and whys in this blog soon, but if you want to have a play, you&#8217;ll find it at <a href="http://github.com/pdcawley/announcements">http://github.com/pdcawley/announcements</a>. Enjoy.</p> Sun, 29 Jun 2008 04:46:00 -0500 urn:uuid:1c2bea3b-ea89-4b97-9a24-54b1b98faa2e pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/06/29/announcing-announcements-for-ruby#comments announcementsproject http://www.bofh.org.uk/articles/2008/06/29/announcing-announcements-for-ruby git is the monads <p>When, in the course of learning about Haskell, I reached the point where I thought I understood what Monads were for, I <a href="http://www.bofh.org.uk/articles/2007/08/07/monads">wrote about it</a>. In the comments, <a href="http://dynamic.ropine.com/yesh/">Seth Gordon</a> observed that:</p> <blockquote> <p>There are two kinds of people who try to learn Haskell: the people who give up because they can’t figure out monads, and the people who go on to write tutorials on how to understand monads.</p> </blockquote> <p>I remembered this today as yet another <a href="http://git.or.cz/">git</a> tutorial rolled by in my newsreader. Maybe git is the monads of version control.</p> <p>What other &#8216;monads&#8217; are there out there? RESTful routing in Rails seems an obvious candidate, but I&#8217;m sure there&#8217;s more.</p> Thu, 15 May 2008 01:57:00 -0500 urn:uuid:e7cf06d4-9bc4-4910-b5ae-be658b031e8b pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/05/15/git-is-the-monads#comments http://www.bofh.org.uk/articles/2008/05/15/git-is-the-monads Rails tip: Dealing with out of sync migrations <p>Sometimes, for one embarrassing reason or another (usually involving chaotic branch merges&#8230;) a database migration can get leapfrogged. When this happens, it&#8217;s tempting to renumber the leapfrogged migration, but that breaks any servers where the migration <em>didn&#8217;t</em> get renumbered. Here&#8217;s how I dealt with it recently:</p> <div class="typocode"><pre><code class="typocode_default ">class MaybeOldMigration &lt; ActiveRecord::Migration def self.up unless old_migration_applied? OldMigration.up end end def old_migration_applied? # Checks that the schema looks as it should # if the old migration got applied end end</code></pre></div> <p>Yeah, it&#8217;s a hack, but it&#8217;s a fairly robust hack.</p> Wed, 07 May 2008 10:09:00 -0500 urn:uuid:5b5a3510-11a5-4ec3-993a-3c978fd18aed pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/05/07/rails-tip-dealing-with-out-of-sync-migrations#comments http://www.bofh.org.uk/articles/2008/05/07/rails-tip-dealing-with-out-of-sync-migrations A quick Javascript formatting tip <p>IE&#8217;s a pain. The particular pain I want to write about is its pickiness about Javascript object literals. Consider the following Javascript object:</p> <div class="typocode"><pre><code class="typocode_default ">{ success: function () {...}, failure: function () {...}, }</code></pre></div> <p>If you&#8217;re used to programming in Perl or Ruby, that trailing comma&#8217;s perfectly fine, in fact leaving it there is sometimes considered good practice because it makes it easy to extend the hash, just add a new row and leave another trailing comma.</p> <p>The trouble is, it&#8217;s not strictly legal to do that in Javascript. Pretty much every implementation out there will allow it though.</p> <p>Except IE.</p> <p>So, I&#8217;ve taken a leaf out of Damian Conways <cite>Perl Best Practices</cite> and writing my object literals as:</p> <div class="typocode"><pre><code class="typocode_default ">{ success: function () {...} , failure: function () {...} }</code></pre></div> <p>By sticking the comma at the beginning of the line, I&#8217;m never going to make an object that breaks IE, and adding a new line to the hash is straightforward too. Just stick the cursor in front of the <code>}</code>, type my leading comma, space, attribute name, and hit return when I&#8217;m finished.</p> <p>I&#8217;ve also started using the same practice pretty much everywhere else that I&#8217;ve got a comma separated list of things:</p> <div class="typocode"><pre><code class="typocode_default ">var foo , bar , baz ; $.each( anArray , function () { ... } );</code></pre></div> <p>It looks weird at first, but trust me, it grows on you.</p> <h3>Update</h3> <p>In the comments, I make reference to tweaking Steve Yegge&#8217;s excellent <a href="http://code.google.com/p/js2-mode/">js2-mode</a> to handle leading comma style a little more gracefully. Since then, I&#8217;ve made it work and attached a diff to <a href="http://code.google.com/p/js2-mode/issues/detail?id=64">this issue</a> on the project&#8217;s issue tracker.</p> Wed, 16 Apr 2008 04:01:00 -0500 urn:uuid:43c91868-fede-47d2-8f9b-14fdce6dee88 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/04/16/a-quick-javascript-formatting-tip#comments The Practice of Programming javascript formatting tips http://www.bofh.org.uk/articles/2008/04/16/a-quick-javascript-formatting-tip Ads are gone <p>Back when I was writing the occasional &#8220;How do you find me?&#8221; article, I would get some weird ads showing up. On one occasion, I commented that the searcher had obviously just typed a homework question into google and expected an answer. All the ads on that page ended up being for sites that would write your essays for you.</p> <p>&#8220;Hmm&#8230;&#8221; I thought, &#8220;That&#8217;s not good.&#8221;, and set about adding those advertisers to the block list.</p> <p>Then, in another article, I ranted about those, ah, bastions of democracy (thank you, Tom Lehrer) who indulge in comment spamming and found myself advertising them.</p> <p><a href="http://www.bofh.org.uk/articles/2006/10/16/rolling-back-the-enlightenment">Rolling back the enlightenment</a> which discussed, amongst other things, my Uncles&#8217; marriage after 36 years together (yay!) attracted some pretty dodgy ads too.</p> <p>To my shame, none of these made me rethink the advertising, I just extended the filter and shook my head at the unpleasantness of it all.</p> <p>The straw that broke the camel&#8217;s back was the advertising around <a href="http://www.bofh.org.uk/articles/2008/04/12/fat-is-an-economic-issue">Fat is an economic issue</a> ran utterly counter to the spirit of the of the article, and they were like &#8220;whack a mole&#8221;. Every time I extended the filter, another ad for another bloody health insurance leech or some other snake oil peddler popped up.</p> <p>So, screw that, the Google ads are gone &#8211; it&#8217;s not as if they were making me a huge amount anyway. I&#8217;ll continue with the left margin Amazon links though &#8211; nobody ever buys anything I recommend, but I like the pictures.</p> Tue, 15 Apr 2008 01:33:00 -0500 urn:uuid:2e86a8de-8dd5-4525-889e-6667e3a70f09 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/04/15/ads-are-gone#comments http://www.bofh.org.uk/articles/2008/04/15/ads-are-gone Fat is an economic issue <p>Terry Pratchett once observed that a character of his was anorexic because every time they looked in a mirror, they saw a fat person. By that measure, I&#8217;m anorexic, though I tend to avoid mirrors. By more objective measures, I&#8217;m morbidly obese &#8211; 6&#8217; tall, 346 pounds; the Body Mass Index calculation is never going to give a good number.</p> <p>To listen to some sections of the press, I might as well be public enemy number one. A drain on the public purse, a morally bankrupt insult to the eye of the right thinking, <cite>Daily Mail</cite> reading healthy public. Apparently, I have the self control of an incontinent puppy and spend my time sat on my arse in front of the TV or looking at child porn on the internet, constantly stuffing my face with lard and chocolate.</p> <p>Mmm&#8230; lard and chocolate&#8230;</p> <p>Now, everyone&#8217;s entitled to their opinions of the morality of others. Catch me on another day, and I can rant for ages about the ugliness of the way diet and beauty industries stoke insecurities to sell product. Today I want to talk about the cost issue.</p> <p>Fat people aren&#8217;t cheap to keep &#8211; we tend to die younger, and in the process of our dying we cost a lot of money. But dying can be an expensive business and however we go, we all do sooner or later. Fat people&#8217;s healthcare costs may well be higher than those of healthy people of the same age, but those healthy people could end up waiting &#8216;til they are 80 before dying of something horribly expensive like cancer, or Alzheimer&#8217;s.</p> <p>When you add up the net lifetime healthcare costs of the average healthy person, and those of the average obese person, the healthy person costs more.</p> <p>This is analogous to the &#8220;Long Tail&#8221; idea &#8211; the idea that the long tail of low sales of &#8216;specialist&#8217; books/records/services adds up to being of greater value than the total sales of the top 100 or whatever. Obvious when you think about it, but running counter to traditional thinking in this area.</p> <p>We&#8217;re really good at spotting the big things, but rather less good at spotting the slow accretion of small things. Each drop of water that falls from a stalactite to a stalagmite doesn&#8217;t appear to contribute anything. Nevertheless, the stalactite and stalagmite got there somehow.</p> <p>I find this knowledge rather heartening. Okay, so as a fat git with diabetes, I&#8217;m likely to die young, but that&#8217;s <em>my</em> business. The pernicious idea that the broader population of tax payers is somehow suffering because of me and that because of that I should be denied access to health care isn&#8217;t just morally repugnant, it&#8217;s economically illiterate.</p> <h3>References</h3> <p><a href="http://medicine.plosjournals.org/perlserv/?request=get-document&#38;doi=10.1371%2Fjournal.pmed.0050029">Lifetime Medical Costs of Obesity: Prevention No Cure for Increasing Health Expenditure</a> from PLoS medicine. The paper describes a mathematical model rather than something which does the arithmetic on a real population, so it&#8217;s only as good as the assumptions, but it does seem compelling that the driver for high total healthcare costs over a lifetime is the length of that life. But, as I fat git, I might be expected to say that. Ho hum.</p> Sat, 12 Apr 2008 01:41:00 -0500 urn:uuid:0290c65b-f8ec-4e3b-83d8-117fa42f070e pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/04/12/fat-is-an-economic-issue#comments Musings obesity economics http://www.bofh.org.uk/articles/2008/04/12/fat-is-an-economic-issue Reinventing the wheel for fun and profit <p>When they tell you to stop because you&#8217;re reinventing the wheel, ignore them and carry on building a better mousetrap.</p> Mon, 07 Apr 2008 06:05:00 -0500 urn:uuid:a3f6069b-1d1b-44b5-9ab0-14d2348f74b5 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/04/07/reinventing-the-wheel-for-fun-and-profit#comments http://www.bofh.org.uk/articles/2008/04/07/reinventing-the-wheel-for-fun-and-profit Code is data, and it always has been <p>I&#8217;m just back from the first <a href="http://www.scotlandonrails.com">Scotland on Rails</a> conference, and a jolly fine conference it was too. Much kudos is due to <a href="http://www.alancfrancis.com">Alan</a>, <a href="http://woss.name">Graeme</a>, Abdel and <a href="http://merecomplexities.com/">Paul</a>. It was hard to believe that this was the first conference these guys have run and I think all my fellow delegates hope it won&#8217;t be the last. As I said in the Pub on Saturday night, I&#8217;d had a talk proposal knocked back and, in that situation, it&#8217;s terribly easy to find yourself sitting in a session thinking &#8220;Bloody hell, my talk would have been better than this!&#8221;, but not at this conference.</p> <p>A phrase that cropped up a couple of times was the old saw that &#8220;Data == Code&#8221; &#8211; it&#8217;s very hard to avoid the idea once you start talking about code generation or Domain Specific Pidgins, parsing&#8230; I first came across the idea in <a href="http://www.amazon.co.uk/exec/obidos/ASIN/0262510871/justasummary-21">The Structure And Interpretation of Computer Programs</a> where it&#8217;s elegantly phrased as &#8220;Data is just dumb code, and code is just smart data&#8221;. Traditionally, the idea seems to be attributed to <a href="http://en.wikipedia.org/wiki/John_McCarthy_%28computer_scientist%29">John McCarthy</a>, the inventor of Lisp. But it&#8217;s older than that. Way older than that. The idea is actually older than Computer Science. It lies at the core of <a href="http://en.wikipedia.org/wiki/Alan_Turing">Turing&#8217;s</a> original paper <a href="http://www.thocp.net/biographies/papers/turing_oncomputablenumbers_1936.pdf"><cite>On Computable Numbers, with an Application to the Entscheidungsproblem</cite></a> in which invents computer science on the way to proving that it&#8217;s impossible to decide algorithmically whether a given statement of arithmetic is true or false.</p> <p>In the course of the paper, Turing posits what has become known as the Halting Problem:</p> <blockquote> <p>Given a description of a program and a finite input, decide whether the program finishes running or will run forever, given that input.</p> </blockquote> <p>Turing&#8217;s proof runs something like this:</p> <p>Suppose we have a subroutine <code>halts?(code,data)</code> which solves the halting problem. Let&#8217;s use that to write something like:</p> <div class="typocode"><pre><code class="typocode_default ">def counter_example(code) if halts? code, code for (;;) end else return end end counter_example(File.read(STDIN))</code></pre></div> <p>and ask the question &#8220;What happens when we run <code>counter_example.rb &lt; counter_example.rb</code>&#8221;? If <code>halts?</code> reckons that <code>counter_example</code> would halt, given itself as input, then counter example will enter an infinite loop, but if <code>halts?</code> reckon that it would enter an infinite loop, then it would halt. Which is a contradiction. Which means that there can be no subroutine <code>halts?</code>, which means that maths is hard enough to be interesting and occasionally undecidable.</p> <p>Look at how the proof works &#8211; it&#8217;s built around the idea that code can be treated as data. In fact, you could say that the Turing Machine looks like it does because Turing was working backwards from this core idea to describe a sufficiently powerful machine that could obviously treat it&#8217;s own description as data. Certainly when you compare the clarity of his proof that the halting problem is undecidable (given the idea of the universal Turing machine) with the contortions required to make mathematics swallow its own tail in similar fashion so that Gödel could prove his Incompleteness Theorem.</p> <p>So, if you want to know who the idea that code is data is due to, the answer (as is so often the case in our field) is Turing.</p> <h3>Postscript</h3> <p>Incidentally, Turing is also responsible for the first ever bug &#8211; his original implementation of a Universal Turing Machine has a couple, one of which is probably a dumb typo (which even I could spot when I read the paper). Another is more subtle, but still fixable. Somewhat delightfully, a young grad student, (<a href="http://en.wikipedia.org/wiki/Donald_Davies">Donald W Davies</a>, who invented packet switching) spotted these bugs and told Turing:</p> <blockquote> <p>I &#8230; found a number of quite bad programming errors, in effect, in the specification of the machine that he had written down, and I had worked out how to overcome these. I went along to tell him and I was rather cock-a-hoop &#8230; I thought he would say &#8216;Oh fine, I&#8217;ll send along an addendum. But in fact he was very annoyed, and pointed out furiously that really it didn&#8217;t matter, the thing was right in principle, and altogether I found him extremely touchy on this subject.</p> </blockquote> <p>Nearly fifty years later Davies wrote and published a debugged version of the code, which you can find in <a href="http://www.amazon.co.uk/exec/obidos/ASIN/0198250797/justasummary-21">The Essential Turing</a>. One lesson to draw from the above is that getting annoyed at people pointing out trivial bugs in example code is also at least as old as computer science. Rather splendidly, there&#8217;s also a story of the chap who wrote the first ever assembler getting a serious telling off from Turing because the computer&#8217;s time was too valuable to waste it on converting symbols into machine code when humans were perfectly capable of doing it themselves. Who knows, maybe Turing&#8217;s contention was actually true back in the days of the Manchester Baby&#8230;</p> Mon, 07 Apr 2008 00:12:00 -0500 urn:uuid:1f6a68ac-944e-48e0-8802-6568a221bf71 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/04/07/code-is-data-and-it-always-has-been#comments Musings The Practice of Programming scotlandonrails turing compsci codeisdata http://www.bofh.org.uk/articles/2008/04/07/code-is-data-and-it-always-has-been Tragedy <p>There&#8217;s always a moment, in a perfect tragedy, where you dare to hope that maybe the heroes are going to break the surface tension of the plot and escape. That perfect moment in <cite>Romeo and Juliet</cite> where, no matter how often you&#8217;ve seen it, you hope that <em>this</em> time, Juliet&#8217;s message will reach Romeo. Or, when watching <cite>Cruel Intentions</cite>, you find yourself hoping that the writers have managed to wangle a happy ending.</p> <p>It never happens of course, and we&#8217;d be disappointed if it did. We are taken to the critical point, when everything seems possible, when the characters are pushed to their utmost&#8230; and fail. Give me the life and death struggles of two teenagers for whom love is everything and life isn&#8217;t worth living without it over the pat solutions of the <cite>Dream</cite>, or give me &#8220;Fortinbras, knee deep in Danes&#8221; over the cross dressing, weddings and cruel taunts of <cite>Twelfth Night</cite>. (Not that I don&#8217;t enjoy the comedies).</p> <h3>What brought this one?</h3> <p>Why am I musing on tragedy instead of code?</p> <p>The explanation is simple: I just watched the last ever episode of <cite>The Wire</cite>.</p> <p>If you follow the show yourself, nothing more is needed. If you don&#8217;t, why not? Okay, so if you&#8217;re in the UK you&#8217;re reduced to paying the Murdoch tax, buying the DVDs or watching through Bittorrent (and only Bittorrent is up to date), but you should. All five seasons of <cite>The Wire</cite> add up to being the best thing I&#8217;ve ever seen on television. It&#8217;s impossible to describe how good it is without misrepresenting the whole. It&#8217;s the kind of campaigning documentary fiction which would make Dickens or Mrs Gaskell proud. It&#8217;s a sprawling epic with a huge cast of fascinating and flawed characters. It&#8217;s the story of how a cop destroys his career, a junky kicks his habit, a school system fails its pupils, politicians fail their constituents, a newspaper fails its readers and how a policy of prohibition fails a country.</p> <p>Prohibition and its consequences are shot through the fabric of <cite>The Wire</cite>. It&#8217;s easy to see how drugs destroy addicts. Easy (for liberal old me at least) to see how the money spent in the War on Drugs could be spent more effectively. What&#8217;s not so easy, and what <cite>The Wire</cite> does so well, is to show how &#8220;the game&#8221; destroys generation after generation of the best and brightest of the urban poor too. Why bother working to get to college, or getting a regular job when selling drugs is so easy and so profitable? If you&#8217;re going to jail for selling the stuff in the first place, why scruple to put a bullet in the head of a business rival, witness, or some mope who calls you a coward? How many &#8220;mute, inglorious Miltons&#8221; end up dead and decaying in a walled up vacant, or stuck behind the barbed wire of the state pen serving out their natural lives with no hope of parole?</p> <p>And what does putting them away achieve? For every small victory, we&#8217;re shown a corresponding fall. New characters slot into the rôles they have vacated and the cycle begins again. It&#8217;s a perfect tragedy &#8211; the game is still rigged and only the players change. The gods are unmoved by the struggles of poor mortals, the lawyers get richer, incompetence is rewarded and money is siphoned away from the streets into the pockets of rich white men who already have plenty.</p> <p>Welcome to Baltimore. Have a nice day.</p> Mon, 24 Mar 2008 03:32:00 -0500 urn:uuid:dc1d310e-80a9-44ad-9bbd-8a9f302f2dfa pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/03/24/tragedy#comments Musings thewire review http://www.bofh.org.uk/articles/2008/03/24/tragedy Javascript scoping makes my head hurt <p>Who came up with the javascript scoping rules? What were they smoking. Here&#8217;s some Noddy Perl that demonstrates what I&#8217;m on about:</p> <div class="typocode"><pre><code class="typocode_default ">my @subs; for my $i (0..4) { push @subs, sub { $i } } print $subs[0]-&gt;(); # =&gt; 0;</code></pre></div> <p>Here&#8217;s the equivalent (or what I thought should be the equivalent) in Javscript:</p> <div class="typocode"><pre><code class="typocode_default ">var subs = []; for (var i in [0,1,2,3,4]) { subs[i] = function () { return i; } } alert subs[0]() // =&gt; 4</code></pre></div> <p>What&#8217;s going on? In Perl, <code>$i</code> is scoped to the <code>for</code> block. Essentially, each time through the loop, a new variable is created, so the generated closures all refer to different <code>$i</code>s. In Javascript, <code>i</code> is scoped to the <code>for</code> loop&#8217;s containing function. Each of the generated closures refer to the same <code>i</code>. Which means that, to get the same effect as the perl code, you must write:</p> <div class="typocode"><pre><code class="typocode_default ">var subs = []; for (var shared_i in [0,1,2,3,4]) { (function (i) { subs[i] = function () { return i; }; })(shared_i); } subs[0]() // =&gt; 0</code></pre></div> <h3>Dodgy Ruby scoping</h3> <p>I had initially planned to write the example &#8220;How it should work&#8221; code in Ruby, but it turns out that Ruby&#8217;s <code>for</code> has the same problem:</p> <div class="typocode"><pre><code class="typocode_default ">subs = []; for i in 0..4 subs &lt;&lt; lambda { i } end subs[0].call # =&gt; 4</code></pre></div> <p>Which is one reason why sensible Ruby programmers don&#8217;t use <code>for</code>. If I were writing the snippet in &#8216;real&#8217; Ruby, I&#8217;d write:</p> <div class="typocode"><pre><code class="typocode_default ">subs = (0..4).collect { |i| lambda { i } } subs[0].call # =&gt; 0</code></pre></div> <h3>My conclusion</h3> <p>Javascript is weird. Okay, so you already know this. In so many ways it&#8217;s a lovely language, but it does have some annoyingly odd corners.</p> Thu, 20 Mar 2008 11:41:00 -0500 urn:uuid:ab821d04-fe0e-40c5-a96f-9f879eff05f2 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/03/20/javascript-scoping-makes-my-head-hurt#comments Musings The Practice of Programming javascript http://www.bofh.org.uk/articles/2008/03/20/javascript-scoping-makes-my-head-hurt Baby's first screencast <p>If you follow the Ruby blogs, you will probably have seen a bunch of programmers attempting to do something akin to Haskell&#8217;s <code>maybe</code>, or the ObjectiveC style, message eating null.</p> <p>Generally, by about the 3rd time you&#8217;ve written</p> <div class="typocode"><pre><code class="typocode_default ">if foo.nil? ? nil : foo.bar ... end</code></pre></div> <p>you&#8217;re getting pretty tired of it. Especially when <code>foo</code> is a variable you&#8217;ve had to introduce solely to hold a value while you check that it&#8217;s not nil. The pain really kicks in when you really want to call <code>foo.bar.baz</code>. You can end up writing monstrosities like <code>(tmp = foo.nil? ? nil : foo.bar).nil? ? nil : tmp.baz</code> (actually, if you were to write that in production code, you probably have bigger problems). One option is to just define <code>NilClass#method_missing</code> to behave like its Objective C equivalent, but I&#8217;ve never quite had the nerve to find out how that might work. I wanted to write</p> <div class="typocode"><pre><code class="typocode_default ">if maybe { foo.bar.baz } ... end</code></pre></div> <p>and have nil behave like an Objective C nil for the duration of the block, but no longer. So I wrote it. Then I thought about how to present it. I wrote the thing test first using rspec and the whole thing just flowed, but writing up a test first development process for a blog entry is painful, so I&#8217;ve made a very rough (but blessedly short) screencast of the process instead.</p> <p><a href="http://www.archive.org/download/RubyMaybeRoughcut/Monad2.mov"><img src="http://www.bofh.org.uk/images/monadcast.jpg" alt="" /></a></p> <p>That&#8217;s a slightly reduced thumbnail, the movie is substantially more readable. The bottom pane of the window is the output of autotest rerunning the spec every time either the spec or the implementation changes. The top pane alternates between the specs and the implementation. Generally, every time I edit the specs, a test starts failing and every time I edit the implementation it starts passing again. In the (any) real coding run, there were of course false starts, but generally the specs kept me pretty straight.</p> <p>A word or two of warning: This is a completely unedited, silent, screen cast, there are typos, backtrackings and other embarrassments. I stopped recording once I&#8217;d got 4 tests passing, but this is far from release quality (it&#8217;s perfectly usable if you know its limitations, but it&#8217;s not entirely robust).</p> <p>Please let me know what you think of this. I&#8217;m aiming to make a more polished version, complete with voice over and it would be good to know which bits are confusing and need addressing in more detail in the voice over.</p> Fri, 14 Mar 2008 14:29:00 -0500 urn:uuid:4b5ad7c3-d601-487b-9554-2d140f18b1a8 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/03/14/babys-first-screencast#comments Ruby screencast maybe rspec TDD http://www.bofh.org.uk/articles/2008/03/14/babys-first-screencast I am not a rock star <p>I am not a <a href="http://www.google.com/search?q=ruby+OR+rails+rockstar">rock star</a>. I am a computer programmer. I think I&#8217;m quite a good one.</p> <p>You are not a rock star either.</p> <p>387,000 matches to that query. Can we all just&#8230; I don&#8217;t know&#8230; grow up please?</p> <p>Mutter&#8230; grumble&#8230; chunter&#8230; I&#8217;m 40 you know!</p> <h4>Updates</h4> <p>I have it on reliable authority that James O&#8217;Kelly is a Ruby on Rails Rockstar that would make a great addition to any team!</p> Sat, 23 Feb 2008 00:13:00 -0600 urn:uuid:016d1523-aac0-4783-a87d-06908e0de83e pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/02/23/i-am-not-a-rock-star#comments Musings Ruby oldfart http://www.bofh.org.uk/articles/2008/02/23/i-am-not-a-rock-star Joined up thinking: why your resources want links <p>Remember the good old days? The days before Google? The days before Altavista? The days when a 14k4bps modem was fast? Did I say <em>good</em> old days?</p> <p>In those days, the web had to be discoverable &#8216;cos it sure as hell wasn&#8217;t searchable. The big, big enabling technology of the web was the humble <code>&lt;a href='http://somewhereelse.com'&gt;Go somewhere else&lt;/a&gt;</code>. Placing the links right there in the body of the document turned out to be exactly the right thing to do.</p> <p>And it continues to be the right thing to do. Consider the two pieces of <span class="caps">YAML</span> below the fold.</p> <p>Here&#8217;s something close to what I&#8217;ve been generating at work (We generate <span class="caps">JSON</span>, but <span class="caps">YAML</span>&#8217;s easier to write out by hand):</p> <pre><code> location: http://site/users/pdcawley/tunes/99 name: Bill Norrie creator: name: Piers Cawley location: http://site/users/pdcawley duration: 360 image: http://s3.amazonaws.com/... stream: http://s3.amazonaws.com/... </code></pre> <p>Here&#8217;s that same snippet, recast in the <span class="caps">URL</span> free style that&#8217;s common in &#8216;RESTful&#8217; APIs:</p> <pre><code> id: 99 name: Bill Norrie creator: name: Piers Cawley id: pdcawley duration: 360 image: http://s3.amazonaws.com/... stream: http://s3.amazonaws.com/... </code></pre> <p>Which of those would you rather have served up to your <span class="caps">API</span> client? Obviously, the one with the URLs because then your client has to know so much less. If resources carry links within their body they&#8217;re discoverable, just like anything else on the web. A client only needs to know about a few resource directories and maybe a mechanism for searching, and most of the rest should follow from the RESTful principles<sup><a href="#fn1">1</a></sup>.</p> <p>If you wanted to write a client to make use of resources in the second form, you&#8217;d need to know that a tune&#8217;s <span class="caps">URL</span> is of the form <tt>/users/<var>creator.id</var>/tunes/<var>tune_id</var></tt>, that user urls have the form <tt>/users/<var>creator.id</var></tt> and so on. You&#8217;d curse the <span class="caps">API</span> designer who designed that <span class="caps">URL</span> scheme. You&#8217;d curse again when, having written the Ruby <span class="caps">API</span>, you sat down to write the Javascript version (modern sites need their <span class="caps">AJAX</span>, right?) and had to teach it all about the <span class="caps">URL</span> scheme all over again.</p> <h3>Don&#8217;t Repeat Yourself</h3> <p>If there&#8217;s one thing worse than violating the <span class="caps">DRY</span> principle, it&#8217;s forcing other people to do it. Structuring your APIs representations around IDs rather than URIs is doing just that. The complexity that you dodge by punting <span class="caps">URL</span> generation to the user is multiplied by the number of <span class="caps">API</span> client implementations (and, arguably, the number of client that don&#8217;t get written &#8216;cos your <span class="caps">API</span>&#8217;s a <span class="caps">PITA</span>).</p> <p>It&#8217;s worse than that though. You already <em>have</em> the code for mapping between resources and URLs. If you&#8217;re using Ruby on Rails, your mapper is bidirectional too<sup><a href="#fn2">2</a></sup>. Generating URLs within your representations should be a snap<sup><a href="#fn3">3</a></sup>. So, what are you waiting for? Start writing Joined Up APIs.</p> <p id="fn1"><sup>1</sup> For values of &#8216;the rest&#8217; that are concerned with the how of the <span class="caps">API</span>. You&#8217;re still going to have to document the what and the why. You can get a long way down that road with careful use of <code>&lt;link rel="ServiceDoc" href="/servicedocs/model" /&gt;</code> though.</p> <p id="fn2"><sup>2</sup> Catch me in the right mood and I can rant for ages about the awfulness of RoR&#8217;s routing system, but the bidirectional nature of them trumps almost all my complaints. It&#8217;s like Jamie Zawinski&#8217;s line that <a href="http://www.jwz.org/doc/java.html">Java doesn&#8217;t have <code>free</code></a>. Everything else about the routing system can suck almost as hard as it likes, but two way routing is a win.</p> <p id="fn3"><sup>3</sup> Not quite the snap it could be in Rails because rails is of the opinion that <span class="caps">URL</span> generation is something the controller does. Which is fine as far as it goes until you find yourself writing <code>Tune#to_json</code> without a controller in sight and you can&#8217;t change <code>to_json</code>&#8217;s signature because it&#8217;s a standard method. And you just want to cry. <code>Model.include ActionController::UrlWriter</code> is wrong, but <em>so</em> tempting&#8230; In fact I&#8217;ve succumbed, just to get the test to pass. I&#8217;m in the process of refactoring by introducing a <code>UrlPolicy</code> singleton that will do all that stuff and at least isolate the bits where my models get to play like controllers.</p> Fri, 22 Feb 2008 02:26:00 -0600 urn:uuid:89042495-f6bb-4639-9d93-ab87c0262fd2 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/02/22/joined-up-thinking-why-your-resources-want-links#comments The Practice of Programming rest http://www.bofh.org.uk/articles/2008/02/22/joined-up-thinking-why-your-resources-want-links Patterns and principles <p>Recently I&#8217;ve been thinking about the way that patterns on different scales interact with each other. If you read Christopher Alexander&#8217;s <cite><a href="http://www.amazon.co.uk/exec/obidos/ASIN/0195019199/justasummary-21">A Pattern Language</a></cite>, the first pattern in the book is <cite>Independent Regions</cite>, which are talked about within the context of a World Government, so it seems like a <em>huge</em> pattern. And it is, sort of, but it&#8217;s scale invariant &#8211; it applies at the level of countries, but it also applies to states, cities, neighbourhoods, streets, houses and arguably even rooms within those houses.</p> <p>Or maybe it emerges from the patterns that apply at those scales. As Kipling has it:</p> <blockquote> <p>As the creeper that girdles the tree trunk, the law runneth forward and back;<br/> For the strength of the pack is the wolf, and the strength of the wolf is the pack.</p> </blockquote> <p>Can we see similar scale invariant patterns in our programming practice? Of course we can, but we tend to call them principles. Programmers reading this will, I hope, be familiar with &#8220;The <span class="caps">DRY</span> (Don&#8217;t Repeat Yourself) Principle&#8221;, which I first came across by that name in Hunt and Thomas&#8217;s <cite><a href="http://www.amazon.co.uk/exec/obidos/ASIN/020161622X/justasummary-21">The Pragmatic Programmer</a></cite>. It&#8217;s such a fundamental pattern that, it suffuses every pattern in Beck&#8217;s <cite><a href="http://www.amazon.co.uk/exec/obidos/ASIN/013476904X/justasummary-21">Smalltalk Best Practice Patterns</a></cite>, but isn&#8217;t actually expressed as a pattern there.</p> <p>There are other macro patterns, one that I&#8217;m starting to appreciate more and more is:</p> <h3>Fail Fast</h3> <p><cite>Fail Fast</cite> is the principle that, when something starts going wrong, you shouldn&#8217;t cover it up, but raise the issue as quickly as possible, hopefully to a level where it can be dealt with. As a pattern it informs almost every activity:</p> <ul> <li>I want to go and photograph the Angel of the North. I plan to be at the angel half an hour before sunrise to get that magical pre dawn golden light. But the weather forecast says tomorrow will be entirely overcast, so I scratch that plan and decide to shoot some still life stuff in diffuse window light instead.</li> </ul> <ul> <li>I&#8217;m working on adding something to the work site and I realise that I&#8217;m not going to get it done in time, so I take it to the boss immediately. We work out how to reduce the scope of the change so that we&#8217;ll still have something useful, but which can/should be extended in a future iteration.</li> </ul> <ul> <li>A low level method gets some data it didn&#8217;t expect and doesn&#8217;t know how to deal with, so it throws an exception and attaches what it knows about the problem &#8211; hopefully something up the caller chain will have enough information to deal with the problem.</li> </ul> <ul> <li>I&#8217;m looking for a new house. I check the details to see make sure there is room for our (huge) dining table, which means the room needs to be at least 18 feet long. If the dining room isn&#8217;t big enough, I&#8217;m probably not going to like the rest of the house either, so I can reject houses quickly as I&#8217;m looking at details.</li> </ul> <p>All reasonably obvious applications of the pattern, I hope you&#8217;ll agree.</p> <p>It gets fun is when <cite>Fail Fast</cite> affects other patterns. For instance, there&#8217;s a pattern for choosing the name of the <code>each</code> block parameters. It says that you should always use the same name, usually <code>each</code> or <code>ea</code>. Many people rebel against the idea: surely it&#8217;s better to reflect the parameter&#8217;s type or ro&#770;le, or something. And they&#8217;re right, sort of. However, those are rules for naming method parameters (type suggesting) and temporary variables (ro&#770;le suggesting or &#8216;explaining&#8217;). If an each block gets long enough that you want to give the parameter a &#8216;better&#8217; name, then it&#8217;s time give the block a name too. Pull the body of the block out into a method, ideally on the parameter&#8217;s class (which spares you the headache of naming the parameter &#8211; it&#8217;s called <code>self</code> &#8211; and, if you&#8217;re using ActiveSupport or something like it, you can replace the block with <code>&#38;:method_name</code>.</p> <p>By naming your block parameters this way, you&#8217;re applying the <cite>Fail Fast</cite> pattern. Your block becomes obviously ugly far sooner than it would if you gave it a more suggestive name, and getting ugly fast is often a good strategy. Similarly, if you&#8217;re stuck with an old fashioned <code>for</code> loop, call your iterator <code>i</code> and when the body of the loop gets unwieldy, replace it with a method or function call that takes the counter and (probably) a <a href="http://c2.com/cgi/wiki?CollectingParameter">Collecting Parameter</a> as arguments.</p> <p><cite>Fail Fast</cite> is why I&#8217;m using <a href="http://haml.hamptoncatlin.com/">Haml</a> more and more in personal work. Haml recasts <span class="caps">HTML</span> in a <span class="caps">YAML</span> like structure, doing away with all the line noise involved in closing tags and letting me concentrate on the structure and content of the page. In an <span class="caps">ERB</span> template, it&#8217;s all too easy to fall into the trap of writing complex logic in view code where it doesn&#8217;t belong. In Haml, that gets ugly quickly, which makes me factor the logic into helpers. Then, because generating markup in a helper is a pain in the arse, it&#8217;s easier to set things up so that the conditional logic simply selects which candidate partial to render. At the end of the process, the template, helpers and partials are working together, but each element is doing one thing and one thing only, and that makes for more comprehensible code. At least, it makes it more comprehensible to me.</p> <p>Smalltalk people have been doing this sort of thing forever. A common complaint from new Smalltalkers is that the code editor isn&#8217;t very capable compared to, say emacs, or vi, or whichever <span class="caps">IDE</span> the newbie is used to. Seasoned Smalltalkers will reply that, if you&#8217;ve reached the point where you wish you had a more capable editor, the method you&#8217;re working on is probably too big. Limited text editing capability is just another way of failing faster, getting to the point where the code is telling you, loudly, that it needs to be better factored.</p> <h3>When getting to ugly hurts</h3> <p>When a pattern or programming language starts to get ugly fast if you start down a dodgy road, the programmer wins. But sometimes the wrong sort of code gets ugly. When I&#8217;m asked why I don&#8217;t code in Perl 5 any more (<a href="http://www.bofh.org.uk/articles/2006/08/03/ruby-til-6">Ruby &#8216;til 6</a> is still my motto) I usually reply that &#8220;I got fed up of unrolling <code>@_</code>.&#8221;)</p> <p>For those unfortunates who are unfamiliar with Perl 5, Perl subroutines are odd in that they don&#8217;t have named parameters. Almost every method ends up beginning like:</p> <div class="typocode"><pre><code class="typocode_default ">sub some_method { my $self = shift; my($other, $thing) = @_; ... }</code></pre></div> <p>There are arguments about whether or not to use <code>shift</code> to pull <code>$self</code> off the front of the parameter array, some folk argue for <code>my($self, $other, $thing) = @_;</code> as the One True Way, but <strike>they are heathens and should be shunned</strike> it really comes down to taste and local coding standards.</p> <p>The problem with this style of argument passing is that you have to do it for every bloody method. One or two lines of precious vertical space are always lost to unrolling the argument list. Vertical space is precious. Losing one or two lines of space for every method is fine when your methods are long, but well factored methods are anything but long. When your method bodies are usually 3 or 4 lines long, that repeated chunk of code is adding 25-30% to your line count, and those added lines are almost pure repetition. The temptation was always to let that method get a little bit longer, swallowing the extra complexity rather than waste another few precious lines on doing the same damned thing again. Perl 6&#8217;s implicit <code>self</code> and named arguments are, on the face of it at least, only minor improvements, but they&#8217;re the sort of improvements that make all the difference.</p> <h3>What did I miss?</h3> <p>I&#8217;m sure you&#8217;ve got pet examples of this pattern, things that I&#8217;ve overlooked or never thought of. Tell us about it &#8211; comment here or blog it. Let&#8217;s all start failing earlier and winning bigger.</p> Sat, 16 Feb 2008 09:57:00 -0600 urn:uuid:7a31a637-e4ad-407c-afaf-ccc20139bba4 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/02/16/patterns-and-principles#comments http://www.bofh.org.uk/trackbacks?article_id=patterns-and-principles&day=16&month=02&year=2008 http://www.bofh.org.uk/articles/2008/02/16/patterns-and-principles The authentication tarpit <p>At work, we&#8217;re looking at adding the Atom Publishing Protocol in a few places where it makes sense. <span class="caps">APP</span>&#8217;s got a lot going for it &#8211; the spec is a great example of how to design a Resourceful <span class="caps">API</span> and is worth reading even if it&#8217;s not an immediately good fit for your application.</p> <h3>But&#8230;</h3> <p>It&#8217;s one of the givens of good application security that you don&#8217;t store passwords in clear text and you do your level best not to send them over the wire in cleartext. That way, if someone pinches your user database, they should have their work cut out for them if they want to find out what your password is (because, unless you&#8217;re very good or are using something like <a href="http://1passwd.com/">1password</a>, you probably use the same password for lots of different websites).</p> <p>A decent authentication protocol should ensure that the clear text of the password is never sent over the wire and doesn&#8217;t need to be stored in the clear on the server. Also, it shouldn&#8217;t be subject to reply attacks. One way to do this is to use <span class="caps">SSL</span> for authenticated sessions and rely on that protocol&#8217;s encryption to solve the problem of the password going over the wire in the clear. Or you could use the standard HTDigest authentication method. The basic trick with systems that don&#8217;t send the plain password over the wire works a little like this:</p> <p>Alice and Bob have agreed a secret password and a hashing algorithm.</p> <p>Alice wants to prove to Bob that a particular request comes from her, so she comes up with a unique &#8216;nonce&#8217; string. She then concatenates this string with the agreed secret, and generates a digest string using the agreed hashing algorithm. She attaches the nonce string and the resulting digest to her request. When Bob receives the request, he concatenates the nonce string with the agreed secret, runs it through the hashing algorithm and, if he gets the same digest value as the one attached to the request, then it&#8217;s very probable that Alice is the real requester.</p> <p>There are variations with different protocols, of course, but the general rule is to send a set of inputs and a result that can only derived from the results by someone who knows the agreed secret. It&#8217;s the sort of thing your bank does when you phone them: &#8220;Can I have you postcode? Surname and initial? What&#8217;s the first letter of your password? And the last letter? Your memorable address?&#8221; The theory is that only you know how to answer those last 3 questions, but at no point are you required to say &#8220;My password is &#8216;flapdoodle&#8217;&#8221; loudly and clearly in a crowded restaurant. Also, it ensures that the bank employee doesn&#8217;t get to see your whole password either. Where the banks fall down is when they phone you and immediately try to take you through the security questions without doing anything to prove that they are who they claim to be.</p> <p>The HTDigest protocol has a neat little wrinkle in its hashing algorithm. Instead of generating the digest directly from a combination of the user identifier<sup><a href="#fn1">1</a></sup>, password and nonce string, it generates an intermediate digest from the user identifier and password, and then uses the same hashing algorithm to calculate a digest from this intermediate result and the nonce string. This means that the server can store the intermediate result instead of the plaintext password.</p> <p>The problem with implementing the Atom Publishing Protocol is that one of the client apps that we want to support, Nokia&#8217;s LifeBlog mobile app, <em>only</em> supports the adaptation of the <span class="caps">WSSE</span> UserToken authentication protocol <a href="http://www.xml.com/pub/a/2003/12/17/dive.html">recommended</a> by Marc Pilgrim. There&#8217;s lots to like about this protocol, especially the way it allows <span class="caps">CGI</span> based servers to take control of authentication without needing access to Apache&#8217;s <code>.htaccess</code> or requiring <code>mod_digest</code> to be installed. However, the design of the protocol is such that there&#8217;s no way to avoid storing the user&#8217;s password in plain text on the server. Which we really, really, really don&#8217;t want to have to do.</p> <p>Mutter. Grumble. Chunter. Bloody WS-* &#8211; biting the big one again.</p> <p id="fn1"><sup>1</sup> The user identifier is a combination of a username and a &#8216;realm&#8217;, a little like the way that email addresses often take the form <code>username@domain</code></p> Tue, 29 Jan 2008 05:19:00 -0600 urn:uuid:c901f3b1-51bb-4087-ac9a-5f387d56ea27 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/01/29/the-authentication-tarpit#comments http://www.bofh.org.uk/articles/2008/01/29/the-authentication-tarpit Martin Fowler's big mouthful <p>Martin Fowler is writing a book about <a href="http://martinfowler.com/dslwip/">Domain Specific Languages</a> and, because you could never accuse Martin of a lack of ambition, he&#8217;s trying to write it in a reasonably (implementation) language agnostic fashion.</p> <p>It&#8217;s fairly easy to write an implementation language agnostic book about old school DSLs, what used to be called little languages &#8211; there&#8217;s a fairly well established literature and theory to do with lexing, parsing and interpreting. These are all about algorithms, and algorithms are implementation language neutral by their very nature.</p> <p>Where Martin has his work cut out for him is trying to talk about what he calls &#8216;internal DSLs&#8217; and what I&#8217;ve been calling &#8216;pidgins&#8217;. These are the sorts of languages where you don&#8217;t write a lexer or parser but instead build a family of objects, methods, functions or whatever other bits and pieces your host language provides in order to create a part of your program that, while it is directly interpreted by the host language, feels like it&#8217;s written in some new dialect.</p> <p>The Lisp family of languages can be said to be all about this. A good &#8216;bottom up&#8217; lisp programmer will shape a language to fit the problem space, essentially building a new lisp which makes it easy to solve the problem at hand. Lisp&#8217;s minimal syntax, powerful macros and the way it blurs the boundary between code and data really support this style.</p> <p>Once you move from Lisp to more &#8216;syntaxy&#8217; languages, things get hairier. As Martin himself <a href="http://martinfowler.com/bliki/BookCode.html">says</a></p> <blockquote> <p>Another issue with book code is to beware of using obscure features of the language, where obscure means for my general reader rather than even someone fluent in the language I&#8217;m using. [...] this is much harder for a <span class="caps">DSL</span> book. Internal DSLs tend to rely on abusing the native syntax in order to get readability. Much of this abuse involves quirky corners of the language. Again I have to balance showing readable <span class="caps">DSL</span> code against wallowing in quirk.</p> </blockquote> <p>He&#8217;s dead right. When I&#8217;m thinking about writing a pidgin in Ruby for instance, my first thought is usually to start with some kind of tabula rasa object which I can use to <code>instance_eval</code> a block. That lets me start to shape my language by lexically scoping the change:</p> <pre><code> in_pidgin do ... end </code></pre> <p>But, though it&#8217;s easy to illustrate what I&#8217;d <em>do</em> with my tabula rasa, the implementation is somewhat tricky, and the tricks needed are unique to Ruby.</p> <p>That sort of construct&#8217;s not really available to someone trying to write a pidgin in Java or Perl. In Perl, there are other odd corners of the language that can be abused to good effect. Dynamic scoping can let you &#8216;inject&#8217; methods into a block even though there&#8217;s no Perl equivalent to <code>instance_eval</code>, or you can do some quite staggering things with the otherwise really annoying Perl function prototypes. For instance, here&#8217;s part of a <a href="http://jifty.org/">Jifty</a> definition of a persistent object:</p> <pre><code> column title =&gt; type is 'text', label is 'Title', default is 'Untitled post'; column body =&gt; type is 'text', label is 'Content', render_as 'Textarea'; </code></pre> <p>Doesn&#8217;t look much like Perl does it? But it&#8217;s parsed and executed by perl with no source filters or <code>eval STRING</code> in sight. And there&#8217;s no unsightly <code>:symbols</code> scattered about the place either come to that.</p> <p>These things all work by making the language do something unexpected, and generally, the way to do that is by knowing your host language inside out and playing with it. One of Damian Conway&#8217;s more inspired moments in recent years was <a href="http://search.cpan.org/~dconway/List-Maker-v0.0.3/lib/List/Maker.pm">List::Maker</a>, in which the good doctor managed to find a corner of Perl where he could wedge a proper old school, complete with full on parser to build the <span class="caps">AST</span>, Little Language right in the heart of Perl without it <em>looking</em> like he was taking a plain old string and interpreting it. So, having found this odd little corner, he proceeded to implement a remarkably neat tool for building complex lists that are beyond the capabilities of Perl&#8217;s <code>..</code> operator.</p> <pre><code> @odds = &lt;1..100 : N % 2 != 0 &gt;; @primes = &lt;3,5..99&gt; : is_prime(N) &gt;; @available = &lt;1..$max : !allocated{N} &gt; </code></pre> <p>You may not think that&#8217;s all that sexy, but, and trust me on this, it&#8217;s just <em>gorgeous</em>. Yet more proof that Damian Conway is an (evil) genius.</p> <p>Frankly, once you&#8217;ve seen the best of the pidgins available in Perl, some of highly praised &#8216;DSLs&#8217; in Ruby start to look a bit ordinary. Ruby makes a great deal of stuff that a pidgin breeder needs to do really easy. In Perl it&#8217;s often rather hard with a huge amount of hoopage to deal with. But some of the things that are hard in Perl are impossible in Ruby.</p> <p>Anyhoo&#8230; coming back to my point. I do find myself wondering if Martin&#8217;s bitten off more than he can chew in attempting to write a book that covers implementing pidgins without getting bogged down in the nitty gritty of individual languages. The problem he&#8217;s facing is that different languages don&#8217;t just have different quirks, they have different idioms too. What reads naturally in the context of a Ruby program will read very weirdly in, say Java or a lisp. Any patterns of implementation beyond broad (but important) strokes like &#8220;Play to your host language&#8217;s strengths&#8221; will surely end up as language specific patterns. Designing and implementing a good pidgin is <em>hard</em>. Doing it effectively means getting down and dirty with your host language and its runtime structures. And that&#8217;s not the sort of thing you can cover effectively in a language agnostic book.</p> <p>Martin, if you&#8217;re reading this, good luck. I think you&#8217;re going to need it. I look forward to being proved wrong.</p> Fri, 18 Jan 2008 17:19:00 -0600 urn:uuid:85fbce77-14bf-44e5-ac34-b61f925d54b0 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/01/18/martin-fowlers-big-mouthful#comments Musings The Practice of Programming pidgin http://www.bofh.org.uk/articles/2008/01/18/martin-fowlers-big-mouthful Getting to grips with Javascript <p>I&#8217;ve been busily adding <span class="caps">AJAX</span> features to the work website, and I got bored of writing Form handlers. I got especially bored of attaching similar form handlers to lots of different forms on a page, so I came up with something I could attach to <code>document.body</code> and then plug in handlers for different form types as I wrote them.</p> <p>So, I wrote <code>FormSender</code> and set up my event handler like so:</p> <div class="typocode"><pre><code class="typocode_default ">FormSender.onSubmit = function (e) { if (canDispatch(e)) { YAHOO.util.Event.stopEvent(e); YAHOO.util.Connect.setForm(e.target); YAHOO.util.initHeader('Accept', 'application/javascript, application/xml'); YAHOO.util.Connect(e.target.method.toUpperCase(), e.target.action, callbackFor(e)); } }; jQuery(document.body).each(function () { YAHOO.util.Event.addListener(this, &quot;submit&quot;, FormSender.onSubmit); });</code></pre></div> I decided to mark any Ajax dispatchable forms using a class of &#8216;ajax&#8217;, the idea being that it would be a simple thing to check <code>jQuery(e.target).hasClass('ajax')</code>, but there was a snag. We had two sorts of forms on our pages, forms built using <code>form_for(..., :class =&gt; 'ajax')</code> and forms built using <code>button_to(..., :class =&gt; 'ajax')</code>, and they attached their classes in different places. In the <code>form_for</code> case, the class was on the form tag, but in the <code>button_to</code> case, it was on the generated form&#8217;s submit field. One option would be to monkey patch <code>button_to</code>, or roll my own <code>ajax_button_to</code>, but I ended up writing <code>canDispatch</code> like so: <div class="typocode"><pre><code class="typocode_default ">function canDispatch(e) { jQuery(e.target).find(':submit').andSelf().hasClass('ajax'); }</code></pre></div> <p>This uses jQuery to build a list of the form, and its submit button, and then checks to see if any member of that list has the class &#8216;ajax&#8217;.</p> <p>So, we can now tell if the source of a <code>submit</code> event is a form we should be doing <span class="caps">AJAX</span> dispatch with. The next trick is to work out what needs to be done with the results of sending the form. One option is the Prototype trick of simply evaluating the returned javascript, but it often makes sense to keep the behaviour clientside and just have the server return a datastructure. I decided that the way to do this would be by adding a second class to a form which used a none default handler, and then keep a hash of callback constructors keyed by class. This made <code>callbackFor</code> look like:</p> <div class="typocode"><pre><code class="typocode_default ">function callbackFor(e) { var candidates = candidateClasses(e.target); for (var i = 0; i &lt; candidates.length; i++) { if (FormSender.callbacks[candidates[i]]) { return new FormSender.callbacks[candidates[i]](e); } } return new FormSender.callbacks.ajax(e); }</code></pre></div> <p><code>candidateClasses</code> is, again, a little more complex than I&#8217;d like, by virtue of the differences between <code>button_to</code> and <code>form_for</code> differences, but still reasonably straightforward, thanks to jQuery:</p> <div class="typocode"><pre><code class="typocode_default ">function candidateClasses(element) { return jQuery(element).find(':submit').andSelf() .filter('.ajax').attr('className') .replace(/ajax/, '').trim().split(/ +/); }</code></pre></div> <p>JQuery gets the form and its submit button, then selects the tag that has the &#8216;ajax&#8217; class and pulls out the full <code>className</code> string. The <code>replace</code> gets rid of &#8216;ajax&#8217;, <code>trim</code> chops any useless whitespace off either end, and <code>split(/ +/)</code> turns it into an array of classnames. The <code>replace -&gt; trim -&gt; split</code> pipeline has the feel of something that must already exist in some <span class="caps">DOM</span> interface somewhere, but I&#8217;m not sure where, so I rolled my own.</p> <p>Once we have a list of classes it&#8217;s easy to just cycle through the candidates until we find one that matches a callback constructor, falling back to the default where nothing matches.</p> <p>For completeness, I&#8217;ll show you my current default handler, which I expect to be extending to deal with a couple more media types and, in the case of the failure handler, more failure statuses.</p> <div class="typocode"><pre><code class="typocode_default ">FormSender.callbacks.ajax = function (e) { var form = e.target; this.scope = form; }; FormSender.callbacks.ajax.prototype.success = function (o) { switch (o.getResponseHeader['Content-Type'].replace(/;.*/, '')) { case 'application/javascript': case 'application/x-javascript': case 'text/javascript': eval(o.responseText); break; default: YAHOO.log(&quot;Can't handle AJAX response of type &quot; + o.getResponseHeader['Content-Type']); } }; FormSender.callbacks.ajax.prototype.failure = function (o) { switch (o.status) { case 401: Authenticator.loginThenSubmit(this); break; default: switch (o.getResponseHeader['Content-Type'].replace(/;.*/, '')) { case 'application/javascript': case 'application/x-javascript': case 'text/javascript': eval(o.responseText); break; default: YAHOO.log(&quot;Can't handle AJAX failure response of type &quot; + o.getResponseHeader['Content-Type']); } } };</code></pre></div> <p>You&#8217;ll notice a reference to <code>Authenticator.loginThenSubmit</code> in the 401 handler, but that&#8217;s something I&#8217;ll save for another day.</p> <h3>A note on namespacing</h3> <p>Although I&#8217;ve been showing the various FormSender helper functions as if they were in the global namespace, in the real code they&#8217;re wrapped in a function call:</p> <div class="typocode"><pre><code class="typocode_default ">var FormSender = (function () { var candidateClasses = function (element) {...}; var callbackFor = function (e) {...}; ... var onSubmit = function (e) {...}; return {onSubmit: onSubmit, callbacks: {}}; })();</code></pre></div> <p>I love the <code>(function () {...})()</code> pattern &#8211; it&#8217;s a great way of keeping your paws out of the global namespace until you really, really need to.</p> <h3>FormSender Benefits</h3> <p>Aside from the obvious benefit of drastically reducing the number of <code>onSubmit</code> event handlers registered with the browser, I found that using <code>FormSender</code> has simplified some of my response handlers. For instance, one form would get a chunk of html back from the server and would use that to replace the div that contained the form. But the new div <em>also</em> contained a form that needed to have Ajax behaviour, so a chunk of the handler code was concerned with reregistering onSubmit handlers for the new form (or forms). No fun. By switching to a single, body level, form handler, that problem simply disappears &#8211; so long as the new forms have the right class, they automatically get the appropriate behaviour. Result.</p> <p>Obviously, FormSender is unobtrusive javascript, which is nice, and its pluggable nature means it&#8217;s easy to extend just by writing new response handlers and registering them with the FormSender object.</p> <h3>Future Directions</h3> <p>One obvious extension to FormSender is to pull out the meat of the <code>onSubmit</code> method into the callback object to allow for forms that don&#8217;t simply send themselves to the server. Another is to wrap my head around the workings of Javascript&#8217;s object model to make it easy to build handlers that don&#8217;t duplicate the behaviour of the default handler through the medium of copy and pasting code&#8230;</p> <h3>Your comments please?</h3> <p>I&#8217;m still very new to Javascript as a programming language and I&#8217;m sure I&#8217;m doing plenty of boneheaded things here. Please let me know if there&#8217;s things I can do to improve this, or point me at any libraries that already cover this ground.</p> Fri, 18 Jan 2008 02:30:00 -0600 urn:uuid:881e1181-5ea9-4ffb-af25-f468276dbaec pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/01/18/getting-to-grips-with-javascript#comments The Practice of Programming javascript http://www.bofh.org.uk/articles/2008/01/18/getting-to-grips-with-javascript The secret of comedy is... <p>... timing. You either have it or you don&#8217;t.</p> <p>Does this count as good timing?</p> <ol> <li>Finish up some improvements to the way Typo sweeps cached pages</li> <li>Announce Typo 5.0</li> <li>Go down with a horrible cough and cold that leaves you exhausted and incapable of hacking</li> <li>Discover that the &#8216;improvements&#8217; in Typo&#8217;s cache sweeping can, occasionally, cause it to wipe the entire Typo installation directory</li> <li>Stagger out of bed. Attempt to fix problem</li> <li>Release Typo 5.0.1</li> <li>Discover that the fix doesn&#8217;t work</li> <li>Bleargh!</li> <li>Let your co-maintainer deal with the fall out before releasing Typo 5.0.2 which <em>does</em> fix the cache sweeper</li> <li>We hope</li> <li>Recover enough to write a blog entry</li> </ol> <p>Okay folks, Typo 5.0.2 is out and it appears to be working. I&#8217;m running it here, and I&#8217;ve had no problems so far. I&#8217;ve <em>still</em> got the cold, but it&#8217;s nowhere near as horrible as it was (went to bed at 5pm on New Year&#8217;s Eve, woke up at 11am on New Years Day &#8211; first time I&#8217;ve missed the turning of the year in ages).</p> Tue, 08 Jan 2008 11:46:00 -0600 urn:uuid:66d6a51f-36f1-421f-9285-e0095cbe3fc0 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/01/08/the-secret-of-comedy-is#comments Typo http://www.bofh.org.uk/articles/2008/01/08/the-secret-of-comedy-is Typo 5 is out - and more on the future <p>Right, we&#8217;ve cut a Typo 5 gem and it&#8217;s on rubyforge and heading to various mirrors I hope. Frédéric&#8217;s writing the release notification which will be appearing on <a href="http://blog.typosphere.org/">Typosphere</a> Real Soon Now.</p> <p>It&#8217;s been a surprisingly tricky process &#8211; we&#8217;re now requiring Rails 2.0.2 because the workings of <code>view_paths</code> have changed in a way which means we can&#8217;t quite make themes with Rails 2.0 <em>and</em> 2.0.2 and working with the edge seems like the more sensible proposition. If you&#8217;re on the bleeding edge, you should find that you get the right Rails via svn:externals anyway.</p> <h3>Typo futures</h3> <p>Meanwhile, I&#8217;ve been playing with stet and I&#8217;ve come to the conclusion that, although there&#8217;s mileage to be had in a radically slimmed down approach to the way Typo works, I&#8217;m better off simply removing the misfeatures from Typo and building from there &#8211; there&#8217;s a surprising amount of <em>stuff</em> that needs to be done in a competent blogging engine that Typo gets right &#8211; starting again would be throwing the baby out with the bathwater I think.</p> <p>However, this does mean that if you&#8217;re following the Typo <span class="caps">SVN</span> trunk, you&#8217;ll be seeing a reduction in features in the short term. We&#8217;ll be copying the current trunk to a <code>5-0-stable</code> branch before we start with the featurectomies though, so if you&#8217;re just after bugfixes, you&#8217;ll be better off there.</p> <h4>Multiblogging</h4> <p>We&#8217;re aiming to have multiblogging in the next release, but we&#8217;re rethinking the <em>how</em> of it. Right now, the &#8216;Blog&#8217; object adds a bunch of complexity to code that would be much happier simply assuming that it has the database to itself. So we&#8217;re going to look at switching to a database per blog approach, that way our core code can pretty much forget about the complexities of multiblogging, and (at least initially) anyone who wants multiblogging can get there by monkeying with configuration files &#8211; of course, we intend to add a web based admin interface once things settle down and we know how things are going to work.</p> <h4>Caching</h4> <p>Caching is always a bugbear in any typo installation. Because we want to be installable on the widest possible range of hosts, we can&#8217;t rely on the presence of handy tools like &#8216;memcached&#8217;. Also, some of our users are operating under some fairly severe memory and process constraints, so it makes sense to have the webserve serve static files as much as possible. Meanwhile, tools like Evan Weaver&#8217;s <a href="http://blog.evanweaver.com/articles/2007/12/13/better-rails-caching/">Interlock</a> are pointing the way towards seriously effective fragment caching. I shall be looking into implementing something that conforms to the interlock interface, but which can use an arbitrary cache backing store for fragments <em>and</em> maintain a full page cache. It&#8217;ll be interesting to find out if this is doable&#8230;</p> <h4>Atom Publishing Protocol</h4> <p>ActionWebService is going to go away &#8211; it&#8217;s already in the <code>ousted</code> branch of the rails <span class="caps">SVN</span> repository, and including it in Typo to support the various different admin APIs is getting painful. So, we&#8217;re going to preempt it. We won&#8217;t be getting rid of the various <span class="caps">XMLRPC</span> APIs until the pain becomes too great, but we are going to be concentrating on implementing, and strongly favouring, the Atom Publishing Protocol.</p> <h4>Feeds for everything</h4> <p>In particular, we&#8217;ll be adding atom feeds for all sorts of administrative data as a means of enabling people to write external tools for, say, spam protection, comment moderation and notification tasks. Right now, there&#8217;s a great deal of computation happening on the server side every time someone, say, comments on a post &#8211; in the kind of resource limited environments some people are running Typo in, that&#8217;s too much work. Switching to a feed + <span class="caps">APP</span> approach should help enormously with resource utilization.</p> <h4>Speaking of resources&#8230;</h4> <p>Using the server to render article previews is&#8230; suboptimal. Expect to see a javascript based preview system akin to the one I use for comments here.</p> Sun, 30 Dec 2007 09:10:18 -0600 urn:uuid:72e74aa1-6450-438c-9757-81f8621b342c pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2007/12/30/typo-5-is-out-and-more-on-the-future#comments Ruby Typo http://www.bofh.org.uk/articles/2007/12/30/typo-5-is-out-and-more-on-the-future Rails 2.0 and the Future of Typo <p>So, if you&#8217;ve been watching the Typo tree, you&#8217;ll see there&#8217;s been a fair amount of activity on it since Rails 2.0 got released. There&#8217;s a new default theme replacing the rather creaky &#8216;azure&#8217;, and a fair amount of work on getting our code compatible with the current state of Rails. As we work on this, it becomes apparent that Typo&#8217;s code is getting horribly brittle. I have said before that there&#8217;s been several places where we&#8217;ve zigged before Rails zagged, and we&#8217;re paying the price for that. It doesn&#8217;t help that our test coverage is distinctly ropy either &#8211; and I&#8217;m probably guiltier than most for letting things get into that state.</p> <p>So, our goal is to get what we have cleaned up and working with Rails 2 before releasing Typo 5.0. Once that&#8217;s done, that line of code will go into maintenance mode &#8211; there are still plenty of bugs to fix and documentation to write, but I&#8217;m afraid that extending that base is becoming too much of a chore.</p> <p>Which is why I have a new path in my local svk repository, //stet. I&#8217;m using this for experimental development of a new, slimmed down blogging engine that will be, first and foremost, a capable Atom Publishing Protocol host. Things like spam processing will be removed from the core of the application, but we&#8217;ll provide a suite of webservice clients that will consume the &#8216;unmoderated feedback&#8217; webfeed and use <span class="caps">APP</span> to either approve or delete the feedback as appropriate.</p> <p>Theming (at least initially) will probably be confined to Javascript and <span class="caps">CSS</span> changes, and I&#8217;m even thinking of exposing the sidebars as Atom collections &#8211; certainly I expect that, in the first cut, sidebars will be static &#8211; if you want content that <em>looks</em> dynamic you&#8217;ll have to do it via javascript.</p> <p>My initial goal is to slim things down as far as I possibly can &#8211; I want to build a blogging engine that can cope with the tight memory constraints of shared hosting by off loading much of the heavy lifting to client boxes. After all, I have far more processing capability available to me on the laptop I&#8217;m typing this on than the slice of Site5&#8217;s hosting infrastructure that&#8217;s actually running the blog. By making things small and static, I also hope to wring good performance numbers out of the tool as well &#8211; expect aggressive page caching at the very least.</p> <p>Another important goal is easy migration of Typo databases. I expect to be writing models and controllers from the ground up, but converting the database should just be a matter of running a migration.</p> <h3>Experimental</h3> <p>Of course, stet&#8217;s currently <em>very</em> experimental &#8211; about the only thing that&#8217;s actually <em>written</em> so far are a couple of routing plugins which should help radically simplify our routes.rb (expect an article&#8217;s url to change from /articles/2007/12/16/rails-20-and-the-future-of-type to /article/2007/12/16/rails-20-and-the-future-of-typo, but with a redirect in place to cater for the old style urls). I may have grandish plans for the thing, but I could equally discover that I&#8217;m off up a blind alley, in which case you can expect me to return to the current typo codebase with a few more lessons learned.</p> <h4>ActiveResource?</h4> <p>I remain unconvinced by ActiveResource as a technology. I agree with the authors of <a href="http://www.amazon.co.uk/exec/obidos/ASIN/0596529260/justasummary-21">RESTful Webservices</a> &#8211; good webservices are joined up. They take full advantage of what could be described as the defining technology of the world wide web, the <span class="caps">URL</span> based hyperlink to knit resources together in a discoverable fashion. An ActiveResource based webservice may well be a good <span class="caps">HTTP</span> citizen, but it&#8217;s still not really &#8216;webby&#8217; enough for my taste. Which means the Atom Publishing Protocol will remain my friend for most of the things I hope to do with stet. It may be harder to write a good <span class="caps">APP</span> server, but I&#8217;m convinced that it&#8217;s a much better interface for clients, and you should always favour ease of use over ease of implementation. If nothing else, we&#8217;re aiming to have more users than developers. Many more.</p> Sun, 16 Dec 2007 10:35:00 -0600 urn:uuid:e685075e-992e-4813-b17d-3392fb9c1e91 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2007/12/16/rails-2-0-and-the-future-of-typo#comments Ruby Typo stet http://www.bofh.org.uk/articles/2007/12/16/rails-2-0-and-the-future-of-typo Comprehensible sorting in Ruby <p>Here&#8217;s a problem I first came across when I was about 13 and helping do the stock check at the family firm. The parts department kept all their various spare parts racks of parts bins. Each bin was &#8216;numbered&#8217; with an alphanumeric id. We had printouts of all the bin numbers along with their expected contents and we&#8217;d go along the racks counting the bins&#8217; contents and checking them off against the print out. What confused me at the time was the way the printouts were organized. Instead of the obvious ordering, &#8220;A1, A2, A3, ..., <span class="caps">A99</span>&#8221;, the lists were ordered like &#8220;A1, <span class="caps">A10</span>, A11, ..., A2, <span class="caps">A20</span>, A21, ...&#8221;. After a bit of thought I realised that the computer was sorting the numeric bits of the bin numbers as if they were just sequences of strange letters. A bit more thought made me realise why, post computerisation, people were starting to use bin numbers like &#8220;A01, <span class="caps">A02</span>, ...&#8221;. Computers were more important than people so, in order to make sorting things easier, just add spurious leading 0s to make the number field a fixed width and Robert&#8217;s your parent&#8217;s brother.</p> <p>27 years later and computers are still crap at sorting things in a sensible fashion. Back before Moore&#8217;s Law was really kicking in, I suppose it was excusable, but surely we&#8217;ve moved past that now.</p> <p>Over on the <a href="http://blog.labnotes.org/2007/12/13/rounded-corners-173-beautiful-code/">labnotes</a> blog, there&#8217;s an example of some ruby code that attempts to do &#8216;human&#8217; sorting:</p> <div class="typocode"><pre><code class="typocode_default ">module Enumerable def sensible_sort sort_by { |key| key.split(/(\d+)/).map { |v| v =~ /\d/ ? v.to_i : v } } end end</code></pre></div> <p>It&#8217;s okay, as far as it goes. It certainly solves the parts bin problem I outlined above, but it&#8217;s not ideal. For example, you might expect <code>['-1', '1', '1.02', '1.1'].sensible_sort</code> to leave the order unchanged, but what you actually get is &#8216;1, 1.02, 1.1, -1&#8217;. Not ideal. Let&#8217;s rewrite sensible sort as</p> <div class="typocode"><pre><code class="typocode_default ">module Enumerable def sensible_sort sort_by {|k| k.split(/([-+]?\d+(?:\.\d+)?(?:[-+]?[eE]\d+)?)/).map {|v| Float(v) rescue v}} end end</code></pre></div> <p>That ugly regular expression should match a far wider selection of string representations of numbers. Certainly our &#8216;bad&#8217; list is now sorted correctly.</p> <p>But what about &#8220;a-1&#8221;, &#8220;a-2&#8221;. Using the implementation above, they&#8217;d get sorted as &#8220;a-2, a-1&#8221;, which can&#8217;t be right, can it? Let&#8217;s extend it a bit more and make sure we only worry about the &#8217;+&#8217; and &#8217;-&#8217; if they&#8217;re at the beginning of a line or preceded by whitespace.</p> <div class="typocode"><pre><code class="typocode_default ">module Enumerable def sensible_sort sort_by {|k| k.to_s.split(/((?:(?:^|\s)[-+])?\d+(?:\.\d+)?(?:[eE]\d+)?)/ms).map {|v| Float(v) rescue v}} end end</code></pre></div> <p>And that works fine, until you find that &#8220;B&#8221; sorts before &#8220;a&#8221;. Let&#8217;s catch that as well:</p> <div class="typocode"><pre><code class="typocode_default ">module Enumerable def sensible_sort sort_by {|k| k.to_s.split(/((?:(?:^|\s)[-+])?\d+(?:\.\d+)?(?:[eE]\d+)?)/ms).map {|v| Float(v) rescue v.downcase}} end end</code></pre></div> <p>Yay!</p> <p>Oh, wait a minute, what about version numbers? How should we sort, say &#8220;perl 5.8.0&#8221; and &#8220;perl 5.10.0&#8221;? The 5.8.0 form should definitely come first&#8230; Hmm&#8230;</p> <p>How about</p> <div class="typocode"><pre><code class="typocode_default ">module Enumerable def sensible_sort sort_by {|k| k.to_s.split(/((?:(?:^|\s)[-+])?\d+(?:\.\d+?(?:[eE]\d+)?(?:$|(?![eE\.])))?)/ms).map {|v| Float(v) rescue v.downcase}} end end</code></pre></div> <h3>How far down does this thing go?</h3> <p>I just noticed that &#8221;.1&#8221; sorts after &#8220;1&#8221;. Time for another tweak&#8230;</p> <div class="typocode"><pre><code class="typocode_default ">module Enumerable def sensible_sort sort_by {|k| k.to_s.split(/((?:(?:^|\s)[-+])?(?:\.\d+|\d+(?:\.\d+?(?:[eE]\d+)?(?:$|(?![eE\.])))?))/ms).map {|v| Float(v) rescue v.downcase}} end end</code></pre></div> <p>but that doesn&#8217;t work with version numbers like &#8221;.8.2&#8221;, &#8221;.10.2&#8221;...</p> <h4>Time passes&#8230; Thorin sits down and sings about gold</h4> <p>I was planning on giving an extension of the regex that caught this issue as well, but I&#8217;m afraid I&#8217;ve stumped myself &#8211; I can&#8217;t do it with a single regular expression unless I can use a fixed width lookbehind assertion, but they&#8217;re only available in Perl. Of course, it&#8217;s still possible to fix it, but doing so will take more thought than I have available to me at this time on a Sunday morning. And all this is before we get onto making sure that &#8220;1/2&#8221; sorts between &#8220;0&#8221; and &#8220;1&#8221;. And phone numbers. After all, &#8220;01915551238&#8221; is &#8216;obviously&#8217; the same as &#8220;0191 555 1238&#8221; and &#8220;0191 555-1238&#8221;, so they should end up next to each other in the sorted list.</p> <p>It looks like this is a &#8216;three pipe problem&#8217; after all. I shall probably return to this&#8230;</p> Sun, 16 Dec 2007 03:00:51 -0600 urn:uuid:a309756d-03d1-403e-99f6-c183d4509932 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2007/12/16/comprehensible-sorting-in-ruby#comments The Practice of Programming Ruby http://www.bofh.org.uk/articles/2007/12/16/comprehensible-sorting-in-ruby Can I get a witness? <blockquote> <p>Worrying about test coverage when you&#8217;re doing Test- or Behaviour-driven development is like worrying about the price of fish in Zimbabwe when you&#8217;re flying a kite.</p> </blockquote> <p>Your tests are there to help you discover your interface and to provide you with an ongoing stream of small bugs to fix. If you write them cleanly, and keep them well factored (you are refactoring your tests, aren&#8217;t you?) they will help to document your intent too. Ensuring that every code path is exercised might be intellectually satisfying but that satisfaction costs time, and time is money. And that&#8217;s before you start worrying about your code&#8217;s malleability. Cover the happy path and the edge cases you <em>know</em> how to deal with and move on. If you&#8217;ve screwed something up, it will get found during acceptance testing (or out in the wild) and you can write a few more tests to isolate the problem, fix it, and move on.</p> <p>If you deliberately add a test that passes without requiring you to write another line of code, ask yourself why you bothered with it. The test isn&#8217;t isolating a bug or specifying new behaviour. If you&#8217;re lucky, it merely confirms something you already know, and if you&#8217;re unlucky, you just introduced a bug in your test suite. Better to move on and either pull a new bug off the queue, or turn a feature request into a new bug &#8211; &#8220;Feature X doesn&#8217;t work!&#8221; &#8211; fix it, refactor and move on to the next. Further down the road, you may discover that the feature you were about to exhaustively test doesn&#8217;t even need to be there, or maybe it works differently than you expected. Aren&#8217;t you glad you didn&#8217;t worry about 100% coverage then? Maybe you will need to revisit the tests and cover more cases in the future. But future you knows more about the problem domain and can do a better job of working out what the behaviour needs to be. And if future you is likely to do a worse job than you right now, you may have bigger problems than the code to worry about.</p> Mon, 19 Nov 2007 13:17:21 -0600 urn:uuid:751d1619-fd46-4407-953d-fe794c06bf6d pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2007/11/19/can-i-get-a-witness#comments The Practice of Programming http://www.bofh.org.uk/articles/2007/11/19/can-i-get-a-witness So... I was wondering <p>Has anyone written an Atompub client in JavaScript yet?</p> Sat, 17 Nov 2007 12:54:23 -0600 urn:uuid:fa7400ee-cf26-4bad-b862-7acda211dfe2 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2007/11/17/so-i-was-wondering#comments lazyweb javascript atompub http://www.bofh.org.uk/articles/2007/11/17/so-i-was-wondering