<?xml version='1.0' encoding='UTF-8'?>
<!--  If you are running a bot please visit this policy page outlining rules you must respect. https://www.livejournal.com/bots/  -->
<rss xmlns:media='http://search.yahoo.com/mrss/' version='2.0' xmlns:lj='http://www.livejournal.org/rss/lj/1.0/' xmlns:atom10='http://www.w3.org/2005/Atom' xmlns:atom='http://www.w3.org/2005/Atom'>
<channel>
  <atom:link href='http://pubsubhubbub.appspot.com' rel='hub'/>
    <atom:link href='http://anthonybailey.net/blog/feed' rel='self'/>
    <title>Anthony Bailey&apos;s blog</title>
  <link>http://anthonybailey.net/blog</link>
  <description>Anthony Bailey&apos;s blog - LiveJournal.com</description>
  <lastBuildDate>Fri, 06 Jan 2017 20:51:56 GMT</lastBuildDate>
  <generator>LiveJournal / LiveJournal.com</generator>
  <lj:journal>anthonybailey</lj:journal>
  <lj:journalid>927339</lj:journalid>
  <lj:journaltype>personal</lj:journaltype>
  <image>
    <url>https://l-userpic.livejournal.com/4100127/927339</url>
    <title>Anthony Bailey&apos;s blog</title>
    <link>http://anthonybailey.net/blog</link>
    <width>100</width>
    <height>100</height>
  </image>

<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/38275.html</guid>
  <pubDate>Fri, 06 Jan 2017 20:51:56 GMT</pubDate>
  <title>Ask Alexa Dot &quot;Try Amazon Music Unlimited&quot;, get &quot;Sorry, I&apos;m having trouble&quot; response? Workaround.</title>
  <link>http://anthonybailey.net/blog/2017/01/06/ask-alexa-dot-try-amazon-music-unlimited-etc</link>
  <description>(Context/disclaimer: I do work for Amazon, but not with the Alexa folk: this is me reporting an issue and workaround as a customer rather than as an employee.)&lt;br /&gt;&lt;br /&gt;I&amp;#39;m a UK Amazon customer who bought an &lt;a href=&quot;https://www.amazon.co.uk/dp/B01DFKBL68&quot; rel=&quot;nofollow&quot;&gt;Echo Dot&lt;/a&gt; a few months ago. The deal of &amp;pound;3.99 per month for &lt;a href=&quot;https://www.amazon.co.uk/gp/dmusic/promotions/AmazonMusicUnlimited&quot; rel=&quot;nofollow&quot;&gt;Amazon Music Unlimited&lt;/a&gt; on just that device is a plausible fit for my needs, and a friend had asked me to help sort out some themed music for a New Year&amp;#39;s Eve party. I knew lending the Dot to another household was plausible because I&amp;#39;d just taken it on a Christmas visit elsewhere. On that occasion I&amp;#39;d even got my host to log in with their own Amazon Prime account to access their music library.&lt;br /&gt;&lt;br /&gt;So on the afternoon of 31st December I logged said previous host out of the Alexa app, signed in myself, then asked Alexa to &lt;i&gt;&amp;quot;try Amazon Music Unlimited&amp;quot;&lt;/i&gt;. (Henceforth I&amp;#39;ll just write that I asked to try AMU.) It reported my free trial had started. A few quick test requests worked really well.&lt;br /&gt;&lt;br /&gt;So I took the Dot to the party, told it about Wifi and bluetooth speakers. No luck accessing the 40 million songs there though, and asking again to try AMU got me &lt;i&gt;&amp;quot;Sorry, I&amp;#39;m having trouble.&amp;quot;&lt;/i&gt; Ah well. Odd spot for the Dot I guessed.&lt;br /&gt;&lt;br /&gt;On return home, though, same situation. No access to the music, no evidence of a subscription having started. Asking to try AMU, same report. In the history, I see &lt;i&gt;&amp;quot;SystemFaultMusic.MembershipIntentM...&amp;quot;&lt;/i&gt; in the response too. Lastly: not even a record of my brief interaction where I successfully tried AMU and played some songs. Hmmm.&lt;br /&gt;&lt;br /&gt;I&amp;#39;m on holiday from work, but I&amp;#39;m still a customer, so I &lt;a href=&quot;https://www.amazon.co.uk/gp/help/contact-us/call-me.html&quot; rel=&quot;nofollow&quot;&gt;contacted customer services&lt;/a&gt;. The Alexa specialist support told me that the subscription process on the device uses Voice Purchasing, and that this simply doesn&amp;#39;t work for non-Prime members.&lt;br /&gt;&lt;br /&gt;(It remains enabled and selected in my Alexa app, though. And of course I really did successfully subscribe when sure I was signed in as my non-Prime account. As you may have guessed the free trial had been started instead on the previously logged Prime account - my host wisely cancelled it when they got an unexpected welcome email. I will be adding correspondence to a trouble ticket when I return to work I think. But let&amp;#39;s just get to the workaround.)&lt;br /&gt;&lt;br /&gt;This is the workaround customer service advised: &lt;b&gt;non-Prime amazon.co.uk customers who want to try Amazon Music Unlimited at &amp;pound;3.99 on their Alexa device should instead start a trial of the full service from the website. Once the trial expires you can ask Alexa to downgrade to the &amp;pound;3.99 level.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;This may hold for non-UK Amazon too: I don&amp;#39;t know. And a proper fix (rather than weird error and support workaround) is in progress, of course.</description>
  <comments>https://anthonybailey.livejournal.com/38275.html#comments</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>1</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/37900.html</guid>
  <pubDate>Sat, 19 Feb 2011 18:09:18 GMT</pubDate>
  <title>GoogleCL authentication with accounts that use non-Google email addresses</title>
  <link>http://anthonybailey.net/blog/2011/02/19/googlecl-authentication-with-accounts-that-use-etc</link>
  <description>&lt;p&gt;
&lt;img src=&quot;https://imgprx.livejournal.net/c9bf1773891a0ee6dcc00455dca0eeb3b1d027c3/c--7zuSnWW-f_ZThK3_X-zmpGg4SJVv-Z721cfxoLmCKN-7h6ccTofLVEoR1D31YIi5TUuwrMbgnT_tMhwfcYT3BB8GahtddiWqXKG_MT6k&quot; style=&quot;padding: 1em&quot; align=&quot;left&quot; alt=&quot;logo&quot; /&gt;&lt;a href=&quot;http://code.google.com/p/googlecl/&quot; rel=&quot;nofollow&quot;&gt;GoogleCL&lt;/a&gt; is a command line tool that uses the Google Data APIs, so that you can interact with your personal wisp of the Google cloud from your shell. I approve: many thanks to the Google devs who run this project in their spare time.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;However, there&apos;s an authentication issue for Google accounts registered under non-Google email addresses. This blog post describes a workaround&lt;/strong&gt; that solved the problem for my &lt;code&gt;anthonybailey.net&lt;/code&gt; account - but &lt;strong&gt;I&apos;ll use &lt;code&gt;example.com&lt;/code&gt; as the domain name throughout&lt;/strong&gt; to avoid personalizing the report.
&lt;span title=&quot;Thanks and all credit to sjoub... - I&amp;amp;apos;m just trying to provide a more visible step-by-step recipe&quot;&gt;
(I was clued in to this workaround through &lt;a href=&quot;http://code.google.com/p/googlecl/issues/detail?id=213#c4&quot; rel=&quot;nofollow&quot;&gt;a forum comment&lt;/a&gt; by someone I can only credit as &quot;sjoub...&quot;..)&lt;/span&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;
So: you have a Google account under an email address in a domain that you own: &lt;code&gt;mail@example.com&lt;/code&gt;. You have &lt;a href=&quot;https://www.google.com/a/cpanel/domain/new&quot; title=&quot;If I remember right, this makes example.com an &amp;amp;apos;Other username&amp;amp;apos; on your original Google Account automatically - if not, do that too!&quot; rel=&quot;nofollow&quot;&gt;signed your &lt;code&gt;example.com&lt;/code&gt; account up for Google Apps&lt;/a&gt;, and installed GoogleCL. When you run it, you&apos;ll have to grant it access permissions. This is what you do:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a title=&quot;You might be able to do this halfway through the process - but let&amp;amp;apos;s not complicate things any further!&quot;&gt;First, sign in&lt;/a&gt; to your &lt;code&gt;mail@example.com&lt;/code&gt; Google account in your browser.&lt;/li&gt;
&lt;li&gt;Run your GoogleCL command, specifying this account, and telling it to ignore any previous failed attempts to authenticate:&lt;pre&gt;% google calendar list --user mail@example.com --force-auth&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;GoogleCL will say: Please log in and/or grant access via your browser at &lt;code&gt;https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=10n9_r4nd0m_Ex4mp13_70k3n_5tr1n9&amp;hd=example.com&lt;/code&gt; then hit enter.&lt;/li&gt;
&lt;li&gt;(Your browser will probably open up that URL, follow some 302 redirects to a &lt;code&gt;https://www.google.com/a/example.com/ServiceLogin2&lt;/code&gt; page, and report &quot;Sorry, you&apos;ve reached a login page for a domain that isn&apos;t using Google Apps&quot;.)&lt;/li&gt;
&lt;li&gt;Visit &lt;a title=&quot;e.g. https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=10n9_r4nd0m_Ex4mp13_70k3n_5tr1n9&quot;&gt;the URL that GoogleCL suggested, &lt;strong&gt;but with the &quot;&lt;code&gt;&amp;hd=example.com&lt;/code&gt;&quot; part at the end chopped off.&lt;/strong&gt;&lt;/a&gt; This makes Google correctly use &lt;a title=&quot;you could specify &amp;amp;hd=default rather than chopping the URL, if you wanted&quot;&gt;the default &lt;code&gt;example.com&lt;/code&gt; hosted domain&lt;/a&gt; for the logged-in account. You&apos;ll get to a &lt;code&gt;https://www.google.com/accounts/b/0/OAuthAuthorizeToken&lt;/code&gt; page where you &quot;Grant Access&quot; to the GoogleCL application.&lt;/li&gt;
&lt;li&gt;Press enter back in the GoogleCL shell and see the successful results of your command.&lt;/li&gt;
&lt;li&gt;Check that GoogleCl is permanently permitted (and has remembered you as the default user) by running again and getting the same results without any need to do special arguments or the browser / cut-and-paste dance:&lt;pre&gt;% google calendar list&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
(You&apos;ll have to do this for each Google service you access: each one needs to give GoogleCL access permissions. For some services you have to copy a token back from the authentication page to the shell.)
&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&quot;But&quot;, you exclaim, &quot;wasn&apos;t this you being dumb? You shouldn&apos;t have given &lt;code&gt;mail@example.com&lt;/code&gt; as the username - you just needed to give &lt;code&gt;example.com&lt;/code&gt;, the domain that Google Apps knows about!&quot;&lt;/p&gt;

&lt;p&gt;
Alas, no. This doesn&apos;t work:&lt;pre&gt;% google calendar list --user example.com&lt;/pre&gt;You do indeed get to grant access without any cut-and-paste dance. But Google Apps ends up granting access to the primary name for the account, &lt;code&gt;mail@example.com&lt;/code&gt;. And GoogleCL quite reasonably but &lt;a title=&quot;pointless because even if you log in *calling* yourself example.com, you&amp;amp;apos;ll still be logged in as mail@example.com, so that&amp;amp;apos;s who gets access&quot;&gt;pointlessly&lt;/a&gt; reports:&lt;blockquote&gt;You specified account &lt;code&gt;example.com&lt;/code&gt; but granted access for &lt;code&gt;mail@example.com&lt;/code&gt;. Please log out of &lt;code&gt;mail@example.com&lt;/code&gt; and grant access with &lt;code&gt;example.com&lt;/code&gt;.&lt;/blockquote&gt;
&lt;/p&gt;

&lt;p&gt;
I may have missed a trick, but I didn&apos;t find any sequence of attempts that worked without the URL-hacking.
&lt;/p&gt;

&lt;p&gt;
&quot;Why didn&apos;t you just sign up with a Gmail address in the first place? The system broke because you did something complicated.&quot;
&lt;/p&gt;

&lt;p&gt;
Maybe so. But although I love Google services, I like to use my own domain for my identity and my email address. I had the email address before Gmail came along, and I want to be able to carry on using it without having to ask everyone to update their address books, even if I switch away from the Google service. 
&lt;/p&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/37900.html#comments</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>1</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/37810.html</guid>
  <pubDate>Tue, 01 Feb 2011 00:16:52 GMT</pubDate>
  <title>Review: Homestuck</title>
  <link>http://anthonybailey.net/blog/2011/02/01/homestuck</link>
  <description>
&lt;div class=&quot;&quot; style=&quot;width:90%&quot;&gt;
&lt;ul style=&quot;display:none&quot;&gt;
&lt;li&gt;(&lt;a href=&quot;http://microformats.org/wiki/hreview&quot; rel=&quot;nofollow&quot;&gt;hreview&lt;/a&gt; version &lt;span class=&quot;&quot;&gt;0.2&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;(Reviewed on &lt;abbr class=&quot;&quot; title=&quot;2011-01-31T19:00:00Z&quot;&gt;31 January 2011&lt;/abbr&gt;
by &lt;a class=&quot;&quot; href=&quot;http://anthonybailey.net/&quot; rel=&quot;nofollow&quot;&gt; &lt;span class=&quot;&quot;&gt;Anthony Bailey&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;&quot; style=&quot;display:none&quot;&gt;website&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;a href=&quot;http://mspaintadventures.com/?s=6&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;Homestuck logo&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/9327f64ba86c31723da1a419e37d8b3083b8a75b/c--7zuSnWW-f_ZThK3_X-7xDnKfn-X4HSWE6XNbwgbY-7N86piqCIoWbssnaCVVqBBSvFa2q415aSJ7hAsjvUJUXNvLlOAl0Tq9i8xRL5O4&quot; /&gt;&lt;/a&gt;&lt;h2&gt;&lt;a class=&quot;&quot; href=&quot;http://mspaintadventures.com/?s=6&quot; rel=&quot;nofollow&quot;&gt;
    &lt;cite&gt;Homestuck&lt;/cite&gt;
&lt;/a&gt;&lt;/h2&gt;by Andrew &quot;&lt;a href=&quot;http://mspaintadventures.com&quot; rel=&quot;nofollow&quot;&gt;MSPaint Adventures&lt;/a&gt;&quot; Hussie
&lt;blockquote class=&quot;&quot;&gt;&lt;p&gt;
This &lt;a href=&quot;http://mspaintadventures.com/?s=6&quot; title=&quot;started 2009.04.13, currently around 3,500 pages and 250,000 words, probably about two-thirds through&quot; rel=&quot;nofollow&quot;&gt;epic ongoing webcomic&lt;/a&gt; is my favorite new artistic work of the last year.
&lt;/p&gt;&lt;p&gt;
&lt;img alt=&quot;a favorite panel&quot; style=&quot;align: center; max-width: 80%&quot; src=&quot;https://imgprx.livejournal.net/cd78da278c921a456d96a6be73da691b9ffc5411/c--7zuSnWW-f_ZThK3_X-7xDnKfn-X4HSWE6XNbwgbY-7N86piqCIoWbssnaCVVqnBZrefh-_5bywp-dqEd1GmrTBxt9W0Irequ671iptQY&quot; /&gt;
&lt;/p&gt;&lt;p&gt;
The &lt;a title=&quot;the first of my many necessary over-simplifications in describing this sprawling work&quot;&gt;core of the story concerns&lt;/a&gt; a bunch of children on interwoven hero&apos;s quests, exploring &lt;a title=&quot;&amp;amp;quot;The Medium&amp;amp;quot;&quot;&gt;something like a video game&lt;/a&gt;. It has a few elements in common with &lt;a href=&quot;http://www.scottpilgrim.com/&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Scott Pilgrim&lt;/cite&gt;&lt;/a&gt; but is massively more ambitious and inventive, and &lt;a title=&quot;and pleasingly obsessively intricate&quot;&gt;the mythos is more fully realized&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;
The plot mechanics are highly intricate: in particular the time-lines of characters and objects form a spirograph-worthy pattern that makes &lt;a href=&quot;http://upload.wikimedia.org/wikipedia/en/0/03/PrimerTimeline.gif&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Primer&lt;/cite&gt;&lt;/a&gt; look like an &lt;a title=&quot;please substitute Homestuck in this punchline&quot; href=&quot;http://xkcd.com/657/&quot; rel=&quot;nofollow&quot;&gt;idle doodle&lt;/a&gt;. One character accurately describes the thing as &quot;&lt;span style=&quot;background: #eeeeee; color: #626262; font-weight: strong; font-family: Courier,monospace&quot;&gt;4 B1G S3LF FULLF1LL1NG CLUST3RFUCK, A HUG3 ORG14ST1C MOB1US DOUBL3 R34CH4ROUND&lt;/span&gt;&quot; - and yet it fits together as well as any time-travel story I&apos;ve seen.
&lt;/p&gt;&lt;p&gt;
Creator Andrew Hussie tells his tale in a highly singular voice and using a &lt;a href=&quot;http://mspaintadventures.com/?viewpage=new&quot; rel=&quot;nofollow&quot;&gt;boundary-stretching style&lt;/a&gt;. The &lt;a title=&quot;lower-case &amp;amp;apos;m&amp;amp;apos; this time&quot;&gt;medium&lt;/a&gt; is an unusual evolving experiment: all the &lt;a href=&quot;http://mspaintadventures.com/?viewpage=archive&quot; rel=&quot;nofollow&quot;&gt;MSPaint Adventures&lt;/a&gt; are presented in the form of an interactive adventure where readers suggest what the characters should do next. This has become more of a stylistic motif than a core principle as Hussie tells longer stories, and &lt;cite&gt;Homestuck&lt;/cite&gt; ups the ante on this with some of the story&apos;s own characters giving instructions in the same manner, and watching each other through the same screens the readership does. The &lt;a title=&quot;fourth walls, self-reference, and mercifully non-intrusive/annoying author-insertion&quot;&gt;usual meta-fictional elements&lt;/a&gt; abound.
&lt;/p&gt;&lt;p&gt;
Typically &lt;a title=&quot;it averages a bit more than five&quot;&gt;several&lt;/a&gt; pages of the comic are published every day. Most contain &lt;a title=&quot;Example - spoiler-free, it&amp;amp;apos;s the first page of the story&quot; href=&quot;http://www.mspaintadventures.com/?s=6&amp;amp;p=001901&quot; rel=&quot;nofollow&quot;&gt;a single GIF image, frequently animated&lt;/a&gt;. Often these are accompanied by a short descriptive text, or by character dialog which is always presented in the form of &lt;a title=&quot;Example - non-spoiler, very early in the story&quot; href=&quot;http://www.mspaintadventures.com/?s=6&amp;amp;p=001926&quot; rel=&quot;nofollow&quot;&gt;a chat log&lt;/a&gt;. Some pages feature Flash content: these range from simple &lt;a title=&quot;Example - non-spoiler, title sequence early in the story&quot; href=&quot;http://www.mspaintadventures.com/?s=6&amp;amp;p=001982&quot; rel=&quot;nofollow&quot;&gt;transitions&lt;/a&gt; with a little atmospheric audio, through &lt;a title=&quot;Example - non-spoiler, very early in the story&quot; href=&quot;http://mspaintadventures.com/?s=6&amp;amp;p=001931&quot; rel=&quot;nofollow&quot;&gt;interactive stuff&lt;/a&gt; to explore, &lt;a title=&quot;Strife! A bit anime in style; my reference point would be Cave Story, but I&amp;amp;apos;m ignorant of the true prior art&quot;&gt;parodies&lt;/a&gt; of &lt;a title=&quot;Example - only spoils the stylistic surprise, is very early in the story&quot; href=&quot;http://mspaintadventures.com/?s=6&amp;amp;p=001990&quot; rel=&quot;nofollow&quot;&gt;boss battles&lt;/a&gt; all the way to complete 8-bit style &lt;a title=&quot;Example - WARNING fine if you just observe the style, but spoilers from later in the story if you start wandering and playing&quot; href=&quot;http://www.mspaintadventures.com/?s=6&amp;amp;p=004979&quot; rel=&quot;nofollow&quot;&gt;embedded games&lt;/a&gt; and full-on soundtracked fast-cut &lt;a title=&quot;Example - WARNING considerable spoilers - but, *probably* so incomprehensible out of context that it won&amp;amp;apos;t wreck anything for you&quot; href=&quot;http://www.mspaintadventures.com/?s=6&amp;amp;p=003701&quot; rel=&quot;nofollow&quot;&gt;cinematic animations&lt;/a&gt; lasting several minutes for some pivotal sections of the story.
&lt;/p&gt;&lt;p&gt;
OK, powerful &lt;a title=&quot;It has ALL THE LEVELS. All of them.&quot;&gt;many-layered&lt;/a&gt; story-telling with cutting avant-garde edges. But the key quality that got me reading this comic, pulled me through the archives over Christmas and now has me impatient for updates every day is that &lt;strong&gt;the jokes are consistently great&lt;/strong&gt;. The humor is quite universal, somewhat geeky, and occasionally nerdy (I confess it was the slapstick sequences based on data structures that hooked me forever.) And the character dialog sparkles: if you pulled the Scooby Gang fifteen years into the future and onto IRC then you might end up with these chats and their hilarious embrace and extend of &lt;a title=&quot;I think. I mean, I&amp;amp;apos;m old. My mash/manips are made of mud, and my lulz are more bash.org than 4chan.&quot;&gt;contemporary kids Net idiom and culture&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;
Highly recommended, if you can cope.
&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/37810.html#comments</comments>
  <category>hreview</category>
  <lj:security>public</lj:security>
  <lj:reply-count>2</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/37422.html</guid>
  <pubDate>Sun, 29 Aug 2010 20:44:32 GMT</pubDate>
  <title>Review: Red Mars, Green Mars, Blue Mars</title>
  <link>http://anthonybailey.net/blog/2010/08/29/red-mars-green-mars-blue-mars</link>
  <description>
&lt;div class=&quot;&quot; style=&quot;width:90%&quot;&gt;
&lt;ul style=&quot;display:none&quot;&gt;
&lt;li&gt;(&lt;a href=&quot;http://microformats.org/wiki/hreview&quot; rel=&quot;nofollow&quot;&gt;hreview&lt;/a&gt; version &lt;span class=&quot;&quot;&gt;0.2&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;(Reviewed on &lt;abbr class=&quot;&quot; title=&quot;2010-08-29T20:20:00+0100&quot;&gt;29 August 2010&lt;/abbr&gt;
by &lt;a class=&quot;&quot; href=&quot;http://anthonybailey.net/&quot; rel=&quot;nofollow&quot;&gt; &lt;span class=&quot;&quot;&gt;Anthony Bailey&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;&quot; style=&quot;display:none&quot;&gt;product&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;a class=&quot;&quot; href=&quot;http://en.wikipedia.org/wiki/Mars_trilogy&quot; rel=&quot;nofollow&quot;&gt;
    &lt;cite&gt;The Mars Trilogy&lt;/cite&gt;
    (&lt;cite&gt;Red Mars&lt;/cite&gt;, &lt;cite&gt;Blue Mars&lt;/cite&gt;, &lt;cite&gt;Green Mars&lt;/cite&gt;)
    by Kim Stanley Robinson
&lt;/a&gt;
&lt;blockquote class=&quot;&quot;&gt;&lt;p&gt;&lt;img style=&quot;width:15%; margin-left: 1em&quot; alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/6b9b0739cbe3b36eec6fee4013eeda0db07a3574/c--7zuSnWW-f_ZThK3_X-_siEevxpEd22OYrkOq1Exrl3-ifwz1mb25UICCHACV1YjPrNWHnNhqvbDiDa1hAlHUcJ741ImCPHaZEym11gcU&quot; /&gt;I read &lt;a href=&quot;http://en.wikipedia.org/wiki/Mars_trilogy&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;The Mars Trilogy&lt;/cite&gt;&lt;/a&gt; since it loiters near the top of most of the lists of great sci-fi novels I&apos;ve encountered. This is mostly a &quot;me too, +1&quot; review.
&lt;/p&gt;&lt;p&gt;&lt;img style=&quot;width:15%; margin-left: 1em&quot; alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/50a3a7897f506c47501cc15ba22c3b849b93d4a2/c--7zuSnWW-f_ZThK3_X-_siEevxpEd22OYrkOq1Exrl3-ifwz1mb25UICCHACV1sm112K1xWSbIO0hJwFo0XWyG7z3EuoSJc_xDB9KeRf4&quot; /&gt;
&lt;a href=&quot;http://www.amazon.com/dp/0553560735&quot; title=&quot;Red Mars (592pp)&quot; rel=&quot;nofollow&quot;&gt;The&lt;/a&gt; &lt;a href=&quot;http://www.amazon.com/dp/0553572393&quot; title=&quot;Green Mars (640pp)&quot; rel=&quot;nofollow&quot;&gt;three&lt;/a&gt; &lt;a href=&quot;http://www.amazon.com/dp/0553573357&quot; title=&quot;Blue Mars (784pp)&quot; rel=&quot;nofollow&quot;&gt;books&lt;/a&gt; follow the fortunes of the &quot;First Hundred&quot; Mars colonists. There is plenty of &lt;a href=&quot;http://en.wikipedia.org/wiki/Hard_science_fiction&quot; title=&quot;I presume: I&amp;amp;apos;m not an planetary engineer&quot; rel=&quot;nofollow&quot;&gt;hard&lt;/a&gt; structural and terraforming science, and much exploration of the social and political fall-out of founding a separated human world, but it shines as a story about fascinating people and their lengthened lives.
&lt;/p&gt;&lt;p&gt;&lt;img style=&quot;width:15%; margin-left:1em&quot; alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/3441411b55c66f399e4d3c9852e9c0e06b0075ac/c--7zuSnWW-f_ZThK3_X-_siEevxpEd22OYrkOq1Exrl3-ifwz1mb25UICCHACV1XeROL0e7V7j1pJJukO9-dLzqY4s18GJJLq0opgyDzmY&quot; /&gt;
As I read, my simplifying pattern-matching machinery decided &quot;this is &lt;cite&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Deadwood_(TV_series)&quot; title=&quot;especially if the fourth season hadn&amp;amp;apos;t been cancelled&quot; rel=&quot;nofollow&quot;&gt;Deadwood&lt;/a&gt;&lt;/cite&gt; in space&quot;, and it is a strong enough analogy I think that, with enough love and skill, a TV adaptation could work - despite &lt;a href=&quot;http://www.denofgeek.com/television/200007/why_red_mars_may_prove_unfilmable.html&quot; title=&quot;(spoilers in linked article, btw!) sure, the odds of any adaptation working well are low - but I refute the prettiness argument&quot; rel=&quot;nofollow&quot;&gt;understandable concerns to the contrary&lt;/a&gt;.
&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/37422.html#comments</comments>
  <category>hreview</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/37210.html</guid>
  <pubDate>Sat, 17 Apr 2010 16:49:22 GMT</pubDate>
  <title>Review: For The Win</title>
  <link>http://anthonybailey.net/blog/2010/04/17/for-the-win</link>
  <description>
&lt;div class=&quot;&quot; style=&quot;width:90%&quot;&gt;
&lt;ul style=&quot;display:none&quot;&gt;
&lt;li&gt;(&lt;a href=&quot;http://microformats.org/wiki/hreview&quot; rel=&quot;nofollow&quot;&gt;hreview&lt;/a&gt; version &lt;span class=&quot;&quot;&gt;0.2&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;(Reviewed on &lt;abbr class=&quot;&quot; title=&quot;2010-04-10T18:10:00+0000&quot;&gt;10 April 2010&lt;/abbr&gt;
by &lt;a class=&quot;&quot; href=&quot;http://anthonybailey.net/&quot; rel=&quot;nofollow&quot;&gt; &lt;span class=&quot;&quot;&gt;Anthony Bailey&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Review is in the &lt;a href=&quot;http://creativecommons.org/licenses/publicdomain/&quot; rel=&quot;license&quot;&gt;public domain&lt;/a&gt;&lt;/li&gt; 
&lt;li&gt;&lt;span class=&quot;&quot; style=&quot;display:none&quot;&gt;product&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;a class=&quot;&quot; href=&quot;http://amazon.co.uk/Win-Cory-Doctorow/dp/0007352018&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; style=&quot;padding-left: 1em&quot; src=&quot;https://imgprx.livejournal.net/d4bdc3a1588f2eddd783db8a853a8ad1a4b8f880/c--7zuSnWW-f_ZThK3_X-x3mAVa959tFnSCh41wh0DGb8s-ieaNhX0HhWFWrGCWZBghF4mwVAG6NFDLu7i8BLdcfPAag8sW_vL4taE5P0b2Yd-nsI5MRtYr0gZz_cEid&quot; /&gt;&lt;cite&gt;For The Win&lt;/cite&gt; by &lt;author&gt;Cory Doctorow&lt;/author&gt;
&lt;/a&gt;
&lt;blockquote class=&quot;&quot;&gt;&lt;p&gt;
Doctorow weaves a highly original story setting from three observations.
&lt;ul&gt;
&lt;li&gt;Currency and assets in virtual worlds have significant real world value and large economies within which some people work for a living.&lt;/li&gt;
&lt;li&gt;The distributed and global nature of the Net is a good fit for mobilizing employees of contemporary corporations.&lt;/li&gt;
&lt;li&gt;The nature of wealth in a speculative information-driven economy is open to disruption&amp;mdash;to gaming, if you will.&lt;/li&gt;
&lt;/ul&gt;
Within this context he presents a fable for young people on the historic and future importance of worker unionization.
&lt;/p&gt;&lt;p&gt;
No, seriously.
&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.amazon.co.uk/Freedom-Daniel-Suarez/dp/1849161763&quot; rel=&quot;nofollow&quot;&gt;&lt;img style=&quot;padding-left: 1em&quot; alt=&quot;Freedom book cover&quot; align=&quot;right&quot; src=&quot;https://imgprx.livejournal.net/89eaa435c6f1c6afa0573dd56e4939c3a97edc30/c--7zuSnWW-f_ZThK3_X-x3mAVa959tFnSCh41wh0DGb8s-ieaNhX0HhWFWrGCWZkew-FZ6iWZeChWtbkNtFoBGjIIJy7RwsZrZqONMPESEht98Mnt9HIvlGIqrNgGdf&quot; /&gt;&lt;/a&gt; Actually. it works really well: the adventure story and the message play very nicely together. I rate this as a better combination of techno-thriller and political writing than another recent read (&lt;a href=&quot;http://www.amazon.co.uk/Freedom-Daniel-Suarez/dp/1849161763&quot; title=&quot;It&amp;amp;apos;s OK, but I could smell it was a bulked-up rework of the Daemon&amp;amp;apos;s intended ending, before it grew too long and had to be cut&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Freedom&lt;sup&gt;TM&lt;/sup&gt;&lt;/cite&gt;&lt;/a&gt;, Daniel Suarez&apos; sequel to &lt;a href=&quot;http://www.amazon.co.uk/Daemon-Daniel-Suarez/dp/1847249612&quot; title=&quot;This debut novel is almost as good as everyone claims&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Daemon&lt;/cite&gt;&lt;/a&gt;), along both axes: &lt;a href=&quot;http://amazon.co.uk/Win-Cory-Doctorow/dp/0007352018&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;For The Win&lt;/cite&gt;&lt;/a&gt; is more fun despite being better grounded and relevant, and more sophisticated despite being targeted at teenagers.
&lt;/p&gt;&lt;p&gt;
The ideas are the core but the central characters are more three-dimensional than average in this kind of contemporary fantasy/sci-fi. Even though they are larger than real-life, and sometimes unreasonably heroic / physically capable / aspirational symbols, I cared about them.
&lt;/p&gt;&lt;p&gt;
&lt;a href=&quot;http://anthonybailey.net/blog/2008/10/01/little-brother&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Little Brother&lt;/cite&gt;&lt;/a&gt; has grown up good. Recommended.
&lt;/p&gt;
&lt;/blockquote&gt;&lt;/div&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/37210.html#comments</comments>
  <category>hreview</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/37066.html</guid>
  <pubDate>Thu, 01 Apr 2010 22:16:28 GMT</pubDate>
  <title>The hopeful tale of an unspoiled Twilight</title>
  <link>http://anthonybailey.net/blog/2010/04/01/the-hopeful-tale-of-an-unspoiled-twilight</link>
  <description>Viewers of television shows with long narrative arcs know the Net can be a double-edged sword. It can provide many pleasant words shared with other engaged fans. It can also deliver much pain in just a few unwanted words of spoiler. The key to avoiding the latter, I think, is community and convention. &lt;br /&gt;&lt;br /&gt;For many years as a UK viewer, I found myself jealously observing the growth of lively Net discussion of the unfolding stories on US TV. The time difference between when countries aired of the shows meant I couldn&apos;t actively participate in those discussions, only read them many months after the fact. Meanwhile even a casual browsing of fan sites for the shows ran quite a risk of being spoiled.&lt;br /&gt;&lt;br /&gt;More lately this has been less of a problem for me, since I can download episodes of the few shows I do watch week-by-week shortly after they air in the US. Instead I observe others experiencing an analogous problem at a smaller timescale as they attempt to combine a DVR-based viewing schedule with their eager tracking of the real-time web. &quot;OMG I can&apos;t believe X just Y&quot; tweets from those watching live make the trade-off between involved and unspoilt viewing as difficult and as dangerous as ever.&lt;br /&gt;&lt;br /&gt;Discussion of the spoilage process itself is even more fraught with difficulty - there&apos;s precious little you can assume everyone knows or that no-one will mind hearing.&lt;br /&gt;&lt;br /&gt;Given this context, &lt;strong&gt;I&apos;m pleased to present a recent personal story of spoilage avoidance.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Although the TV show is over, the official Buffy canon continues in the form of a &quot;Season Eight&quot; series of monthly comics, involving a masked Big Bad known as Twilight. Lately there was a horrendous mess up when the uncensored version of a cover of an upcoming issue which literally unmasked Twilight was unintentionally included in teaser marketing materials, revealing the identity of this villain months ahead of schedule. A significant proportion of the keener fans were spoiled, and there were dozens of discussions and press stories on how this all came about.&lt;br /&gt;&lt;br /&gt;Now, I follow Joss Whedon stuff relatively close up on the excellent &lt;a href=&quot;http://whedonesque.com/&quot; rel=&quot;nofollow&quot;&gt;Whedonesque&lt;/a&gt; hub. But this site has a gated and relatively caring community, and a strong convention of omitting spoilers from summaries and clearly marking when they may be present in linked articles, or the site&apos;s own discussion boards. I read Whedonesque for many months before the comic in question was finally published, and despite the huge amount of attention &quot;Twilightgate&quot; received I easily remained unspoiled until I reached the intended page. So I want to offer warm fuzzy thanks in the general direction of all those who helped that happen.&lt;br /&gt;&lt;br /&gt;(I&apos;ll reserve judgement on the overall plot and twist in question until the season is done, mind.)&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <category>metaspoilt</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/36697.html</guid>
  <pubDate>Sat, 26 Dec 2009 01:38:08 GMT</pubDate>
  <title>Review: Sweet Dreams (Pride, and Prejudice, and Zombies)</title>
  <link>http://anthonybailey.net/blog/2009/12/26/sweet-dreams-pride-and-prejudice-and-zombies</link>
  <description>
&lt;div class=&quot;&quot; style=&quot;width:90%&quot;&gt;
&lt;ul style=&quot;display:none&quot;&gt;
&lt;li&gt;(&lt;a href=&quot;http://microformats.org/wiki/hreview&quot; rel=&quot;nofollow&quot;&gt;hreview&lt;/a&gt; version &lt;span class=&quot;&quot;&gt;0.2&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;(Reviewed on &lt;abbr class=&quot;&quot; title=&quot;2000-12-26T00:31:42+0000&quot;&gt;26 December 2009&lt;/abbr&gt;
by &lt;a class=&quot;&quot; href=&quot;http://anthonybailey.net/&quot; rel=&quot;nofollow&quot;&gt; &lt;span class=&quot;&quot;&gt;Anthony Bailey&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Review is in the &lt;a href=&quot;http://creativecommons.org/licenses/publicdomain/&quot; rel=&quot;license&quot;&gt;public domain&lt;/a&gt;&lt;/li&gt; 
&lt;li&gt;&lt;span class=&quot;&quot; style=&quot;display:none&quot;&gt;product&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;a class=&quot;&quot; href=&quot;http://www.amazon.com/Sweet-Dreams/dp/0262541912&quot; rel=&quot;nofollow&quot;&gt;&lt;img alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/bee3859e122b12aaf109fa984fa1e08fe6531f26/c--7zuSnWW-f_ZThK3_X-x3mAVa959tFnSCh41wh0DGb8s-ieaNhX0HhWFWrGCWZNOspvLFwtznWZsyhczmzOYpX-eryfIXYmbWWlV-1t_-WGBC71d3hJxNf1Ijq3jvK&quot; /&gt;&lt;cite&gt;Sweet Dreams (Philosophical Obstacles to a Science of Consciousness)&lt;/cite&gt; by &lt;author&gt;Daniel Dennett&lt;/author&gt;
&lt;/a&gt;
&lt;blockquote class=&quot;&quot;&gt;&lt;p&gt;&lt;a href=&quot;http://www.amazon.com/Consciousness-Explained/dp/0140128670&quot; rel=&quot;nofollow&quot;&gt;&lt;img style=&quot;padding-right: 1em&quot; alt=&quot;Consciousness Explained book cover&quot; align=&quot;left&quot; src=&quot;https://imgprx.livejournal.net/f17e8905d05e79bf9b3be0ad61b4dfb0ec4c1df6/c--7zuSnWW-f_ZThK3_X-x3mAVa959tFnSCh41wh0DGb8s-ieaNhX0HhWFWrGCWZi7hLk5T0Tbw_TMTOgn0KCmm5Yn_nP55qCZunSCd-9EldTRuoOePUkVH-iTZGZrdd&quot; /&gt;&lt;/a&gt; When I read the provocatively entitled &lt;a href=&quot;http://www.amazon.com/Consciousness-Explained/dp/0140128670&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Consciousness Explained&lt;cite&gt;&lt;/a&gt; fifteen years ago, I was very impressed by Dennett&apos;s &quot;intentional stance&quot; and advocacy of &lt;a href=&quot;http://en.wikipedia.org/wiki/Heterophenomenology&quot; title=&quot;ironically, Dennett claims to dislike obscure terminology&quot; rel=&quot;nofollow&quot;&gt;heterophenomenology&lt;/a&gt; - applying the standard scientific method to understanding the nature of the consciousness of some third-party, using the subject&apos;s own reports about their internal experience together with other evidence. The particular &quot;multiple drafts&quot; model of consciousness he proposed alongside was plausible but very sketchy.
&lt;/p&gt;&lt;p&gt;&lt;a title=&quot;This pun was not the only reason I wrote this review... but, almost&quot; href=&quot;http://en.wikipedia.org/wiki/Pride_and_Prejudice_and_Zombies&quot; rel=&quot;nofollow&quot;&gt;&lt;img style=&quot;padding-right: 1em&quot; alt=&quot;Pride and Prejudice and Zombies book cover&quot; align=&quot;left&quot; src=&quot;https://imgprx.livejournal.net/f9da87a96f62ee3a6a91adead1b29c32e6f581a3/c--7zuSnWW-f_ZThK3_X-x3mAVa959tFnSCh41wh0DGb8s-ieaNhX0HhWFWrGCWZ-yszzzQXWuO8NYfCNA59m2Ipi3rWLIHzcbj4clSMndbFQ-cdtfuHLIBKxcdF7Aw2&quot; /&gt;&lt;/a&gt;
Dennett returns to the topic in &lt;a href=&quot;http://www.amazon.com/Sweet-Dreams/dp/0262541912&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Sweet Dreams&lt;/cite&gt;&lt;/a&gt;, and again does a great job clearing the junk from this philosophical space. By his account, one has to fight surprisingly hard for common sense in the study of consciousness - &lt;a title=&quot;Pun concordance: Pride!&quot;&gt;people seem threatened by any model that doesn&apos;t make them sufficiently special&lt;/a&gt;, and &lt;a title=&quot;Pun concordance: Prejudice!&quot;&gt;unusually willing to rely on their default intuitions&lt;/a&gt;, even if this means entertaining &lt;a title=&quot;Pun concordance: *uncomprehending zombie growl*&quot; href=&quot;http://en.wikipedia.org/wiki/Philosophical_zombie&quot; rel=&quot;nofollow&quot;&gt;zombies&lt;/a&gt; and moving into &lt;a title=&quot;not even going to try summarizing this one&quot; href=&quot;http://en.wikipedia.org/wiki/Qualia&quot; rel=&quot;nofollow&quot;&gt;qualia&lt;/a&gt; street. 
&lt;/p&gt;&lt;p&gt;
So, &lt;a title=&quot;Capsule review&quot;&gt;&lt;strong&gt;most of the book is a careful and polished philosophical argument that seeks to remove the obstacles that stop us making progress with the &quot;problem&quot; of consciousness. It&apos;s Dennett&apos;s best presentation yet - but for me, what he builds on the claimed ground remains frustratingly fuzzy.&lt;/strong&gt;&lt;/a&gt; He fits &lt;a title=&quot;fame in the brain, fantasy echo&quot;&gt;a few new metaphors&lt;/a&gt; onto his still plausible model, but I&apos;m still left waiting for others to go and &lt;a title=&quot;Look at him still talking, when there&amp;amp;apos;s science to do!&quot; href=&quot;http://anthonybailey.net/tumblelog/2008/01/02/look-at-me-still-talking-when-theres-science-etc&quot; rel=&quot;nofollow&quot;&gt;Do Science&lt;/a&gt; with the tools and justifications that he has prepared.
&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;&lt;/cite&gt;&lt;/cite&gt;</description>
  <comments>https://anthonybailey.livejournal.com/36697.html#comments</comments>
  <category>hreview</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/36497.html</guid>
  <pubDate>Mon, 30 Nov 2009 04:52:48 GMT</pubDate>
  <title>Testing with less manual calculation</title>
  <link>http://anthonybailey.net/blog/2009/11/30/testing-with-less-manual-calculation</link>
  <description>&lt;p&gt;

After seeing some solutions to &lt;a href=&quot;http://rubyquiz.com/quiz14.html&quot; rel=&quot;nofollow&quot;&gt;this Ruby coding kata on generating ASCII representations of LCD calculator numbers&lt;/a&gt; I thought writing the test cases could be more pleasant. Because the whole idea is to have the machine deal with the tedious task of generating the fiddly and sizeable output, &lt;strong&gt;I really don&apos;t like the straightforward approach that means I have to supply lots of example outputs myself, by hand.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
I thought either of two alternative testing approaches might help: &lt;strong&gt;checking universal properties&lt;/strong&gt;, or &lt;strong&gt;content regression&lt;/strong&gt;.
&lt;/p&gt;

&lt;h2&gt;Universal coverage&lt;/h2&gt;

&lt;p&gt;
The first approach is that rather than give many specific examples of output, we &lt;strong&gt;find some generic conditions that all outputs should satisfy and then check these for many cases&lt;/strong&gt;. For this to work well the inputs need to be simpler than the outputs, or easy to generate automatically.
&lt;/p&gt;

&lt;p&gt;
A good example from a previous job involved 3D vector geometry. We had code for distances and angles, and for various transformations. An intrinsic feature of this domain is that the distance between any pair of points should be unchanged under translations, rotations and reflections, and multiplied by an appropriate factor under a scaling. Similarly the angle subtended by any three points should be unchanged under any of those four tranformations.
&lt;/p&gt;

&lt;p&gt;
It was easy to check these identities for many combinations of input points and transformations, including both pseudorandom inputs and some specially chosen to provoke edge conditions e.g. zero and near-zero distances, and co-linear, perpendicular and anti-parallel vectors. Much more pleasant than manually calculating the answers for a smaller number of examples &amp;mdash; and it gave better coverage too.
&lt;/p&gt;

&lt;h2&gt;Lowest common denominators of LCD&lt;/h2&gt;

&lt;p&gt;
You can find some pretty good constraints that every LCD output should satisfy; certain horizontals and verticals should contain only spaces and hyphens, others only spaces and pipes; it should have certain dimensions; and certain relationships should hold between the outputs for different sizes of the same input, and between outputs for single digits and their combinations.
&lt;/p&gt;

&lt;p&gt;
Actually... once you have pinned down the basic form of each of the digits, it isn&apos;t difficult to write a complete specification of the content of each character position in the output expected for a given set of inputs. Now said spec is pretty easy to make executable: just loop over the positions and render the character that should be there. In fact it turns out to be most natural to express this procedurally without explicitly tracking the positions in the final output.
&lt;/p&gt;

&lt;p&gt;
So thinking about this kind of testing informed my choice of implementation instead! An unusual variation on test-driven design.
&lt;/p&gt;


&lt;h2&gt;Implementation rendered obvious&lt;/h2&gt;

&lt;p&gt;
Here is &lt;a href=&quot;http://pastie.org/719708&quot; rel=&quot;nofollow&quot;&gt;the production code I ended up with&lt;/a&gt;.
&lt;/p&gt;
&lt;hr /&gt;&lt;b&gt;
&lt;div class=&quot;&quot;&gt;
  &lt;div class=&quot;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color:#B06;font-weight:bold&quot;&gt;Lcd&lt;/span&gt;

  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;initialize&lt;/span&gt;
    &lt;span style=&quot;color:#33B&quot;&gt;@cells&lt;/span&gt; = &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;lt;&amp;lt;CELLS&lt;/span&gt;&lt;/span&gt;.split( &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; )&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span&gt;
 -       -   -       -   -   -   -   - 
| |   |   |   | | | |   |     | | | | |
         -   -   -   -   -       -   - 
| |   | |     |   |   | | |   | | |   |
 -       -   -       -   -       -   - &lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;
CELLS&lt;/span&gt;&lt;/span&gt;
  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;

  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;render&lt;/span&gt;( digits, size = &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;2&lt;/span&gt; )
    rows = [ &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;0&lt;/span&gt;, [&lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;1&lt;/span&gt;] * size, &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;2&lt;/span&gt;, [&lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;3&lt;/span&gt;] * size, &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;4&lt;/span&gt; ].flatten
    rows.map { | row | render_row( row, digits, size ) }.join
  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;

  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;render_row&lt;/span&gt;( row, digits, size )
    cols = [ &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;0&lt;/span&gt;, [&lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;1&lt;/span&gt;] * size, &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;2&lt;/span&gt; ].flatten
    digits.split( &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; ).map &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;do&lt;/span&gt; | digit |
      cols.map { | col | &lt;span style=&quot;color:#33B&quot;&gt;@cells&lt;/span&gt;[ row * &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;40&lt;/span&gt; + digit.to_i * &lt;span style=&quot;color:#00D;font-weight:bold&quot;&gt;4&lt;/span&gt; + col ] }.join
    &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;.join(&lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;) + &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;\n&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;

&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/b&gt;&lt;hr /&gt;

&lt;p&gt;&lt;small&gt;
(I omitted the command-line option handling specified in the original kata &amp;mdash; it&apos;s two uninteresting lines using the &lt;a title=&quot;my favorite Ruby option parsing friend&quot; href=&quot;http://trollop.rubyforge.org/&quot; rel=&quot;nofollow&quot;&gt;trollop gem&lt;/a&gt;.)
&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;
I really like the succinctness of this solution, and that the basic digit forms are directly readable in the code. It does have a bit of a &lt;a title=&quot;The code smell of using primitive types directly rather than abstracting them for readability&quot; href=&quot;http://blogs.agilefaqs.com/2009/10/20/primitive-obsession&quot; rel=&quot;nofollow&quot;&gt;primitive obsession&lt;/a&gt;, with the source rows and columns and the input digits all represented by plain integers, and the compositions performed by anonymous application of list operators such as &lt;code&gt;join&lt;/code&gt;. But in this case I found the indirections and conversions that were introduced if I abstracted these away undermined the readable simplicity of the core ASCII renderer.
&lt;/p&gt;

&lt;p&gt;
(I guess that nostalgia for the idioms of low-level rendering is probably why I kept the &quot;magic numbers&quot; expression that calculates the index to look up in &lt;code&gt;@cells&lt;/code&gt; verbatim in the inner loop. Look, just be happy I didn&apos;t inline &lt;code&gt;render_row&lt;/code&gt; too, OK?)
&lt;/p&gt;


&lt;h2&gt;Contentful, again&lt;/h2&gt;

&lt;p&gt;
Since universal properties drove the production code rather more directly than normal, although I did write some tests of that form, the main approach I used to avoid writing tedious example output myself was to instead &lt;strong&gt;capture what production code does, and regress against that once it looks good&lt;/strong&gt;.
&lt;/p&gt;

&lt;p&gt;
I&apos;ve &lt;a href=&quot;http://anthonybailey.net/blog/2007/07/19/regression-therapy-contentful-testing&quot; rel=&quot;nofollow&quot;&gt;blogged&lt;/a&gt; and &lt;a href=&quot;http://anthonybailey.net/tumblelog/2008/04/08/contentful-slides-from-my-talk-at-scotland-on-etc&quot; rel=&quot;nofollow&quot;&gt;talked&lt;/a&gt; about this kind of content testing before, and implemented &lt;a title=&quot;must... move to... github...&quot; href=&quot;http://contentful.rubyforge.org/&quot; rel=&quot;nofollow&quot;&gt;a Rails plug-in&lt;/a&gt; for view content testing. In this case distilled the approach to its unpolished &lt;a href=&quot;http://pastie.org/719846&quot; rel=&quot;nofollow&quot;&gt;essence&lt;/a&gt;.
&lt;/p&gt;
&lt;hr /&gt;&lt;b&gt;
&lt;div class=&quot;&quot;&gt;
  &lt;div class=&quot;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;regress_render&lt;/span&gt;( digits, size )
  regress( &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;background:#eee;color:black&quot;&gt;&lt;span style=&quot;font-weight:bold;color:#777&quot;&gt;#{&lt;/span&gt;size&lt;span style=&quot;font-weight:bold;color:#777&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span style=&quot;background:#eee;color:black&quot;&gt;&lt;span style=&quot;font-weight:bold;color:#777&quot;&gt;#{&lt;/span&gt;digits&lt;span style=&quot;font-weight:bold;color:#777&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;.content&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span style=&quot;color:#33B&quot;&gt;@lcd&lt;/span&gt;.render( digits, size ) )
&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;

&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B;font-weight:bold&quot;&gt;regress&lt;/span&gt;( name, content )
  expected_content = &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;File&lt;/span&gt;.open( name + &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;span&gt;.expected&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; ).read &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;rescue&lt;/span&gt; &lt;span style=&quot;color:#d70;font-weight:bold&quot;&gt;$!&lt;/span&gt;.message
  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;if&lt;/span&gt; ( expected_content != content )
    &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;File&lt;/span&gt;.open( name, &lt;span style=&quot;background-color:#fff0f0;color:#D20&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;span&gt;w&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; ).write( content )
    assert_equal( expected_content, content )
  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;elsif&lt;/span&gt; &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;File&lt;/span&gt;.exists?( name )
    &lt;span style=&quot;color:#036;font-weight:bold&quot;&gt;File&lt;/span&gt;.delete( name )
  &lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color:#080;font-weight:bold&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/b&gt;&lt;hr /&gt;

&lt;p&gt;
So when I first put e.g. &lt;code&gt;regress_render( &apos;88&apos;, 3 )&lt;/code&gt; in a test, then my current content was written to &lt;code&gt;3-88.content&lt;/code&gt; and I was told it didn&apos;t match &quot;&lt;code&gt;No such file or directory - 3-88.content.expected&lt;/code&gt;&quot;. Once I&apos;d written enough code that the output was rendered correctly, I captured it (e.g. &lt;code&gt;mv 3-88.content 3-88.content.expected&lt;/code&gt;.) This let me build up a solid set of regression tests without ever having to construct their content by hand &amp;mdash; I just had to observe results and move them to being expectations once I saw they were valid.
&lt;/p&gt;

&lt;br /&gt;
&lt;br /&gt;

&lt;p&gt;
If you found either of my new variations on this old kata diverting, please do comment with your thoughts.
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;
&lt;/p&gt;</description>
  <comments>https://anthonybailey.livejournal.com/36497.html#comments</comments>
  <category>software_development</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/36131.html</guid>
  <pubDate>Wed, 29 Apr 2009 23:14:48 GMT</pubDate>
  <title>Review: Anathem</title>
  <link>http://anthonybailey.net/blog/2009/04/29/anathem</link>
  <description>
&lt;div class=&quot;&quot; style=&quot;width:90%&quot;&gt;
&lt;ul style=&quot;display:none&quot;&gt;
&lt;li&gt;(&lt;a href=&quot;http://microformats.org/wiki/hreview&quot; rel=&quot;nofollow&quot;&gt;hreview&lt;/a&gt; version &lt;span class=&quot;&quot;&gt;0.2&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;(Reviewed on &lt;abbr class=&quot;&quot; title=&quot;2009-04-29T23:39:32+01:00&quot;&gt;29 April 2009&lt;/abbr&gt;
by &lt;a class=&quot;&quot; href=&quot;http://anthonybailey.net/&quot; rel=&quot;nofollow&quot;&gt; &lt;span class=&quot;&quot;&gt;Anthony Bailey&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Review is in the &lt;a href=&quot;http://creativecommons.org/licenses/publicdomain/&quot; rel=&quot;license&quot;&gt;public domain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;&quot; style=&quot;display:none&quot;&gt;product&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/89ee3a2245bff7a42aa7724b140c225ef62a72f1/c--7zuSnWW-f_ZThK3_X-x3mAVa959tFnSCh41wh0DGb8s-ieaNhX0HhWFWrGCWZJHvzb3kpb_ltOXS_y8n9D1NGhOTdwzahUBm26yNWvR8&quot; /&gt;&lt;a class=&quot;&quot; href=&quot;http://www.amazon.co.uk/gp/product/1843549166&quot; rel=&quot;nofollow&quot;&gt;
    &lt;cite&gt;Anathem&lt;/cite&gt;
    by &lt;author&gt;Neal Stephenson&lt;/author&gt;
&lt;/a&gt;
&lt;blockquote class=&quot;&quot;&gt;&lt;p&gt;
After the more historic &lt;a href=&quot;http://anthonybailey.net/blog/2009/02/21/the-baroque-cycle&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Baroque Cycle&lt;/cite&gt;&lt;/a&gt;, Stephenson returns to speculative sci-fi a la &lt;a href=&quot;http://www.amazon.com/Diamond-Age-Neal-Stephenson/dp/0553573314&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Diamond Age&lt;/cite&gt;&lt;/a&gt;, playing with the parallel evolution of language, culture, and quantum narratives.
&lt;/p&gt;&lt;p&gt;
I enjoyed this a lot. It oddly reminded me of the &lt;a href=&quot;http://en.wikipedia.org/wiki/Riverworld&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Riverworld&lt;/cite&gt; saga&lt;/a&gt;, but with philosophical ideas rather than characters from history making their cameos against a densely detailed unfolding backdrop and story.
&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/36131.html#comments</comments>
  <category>hreview</category>
  <lj:security>public</lj:security>
  <lj:reply-count>1</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/35888.html</guid>
  <pubDate>Sat, 21 Feb 2009 20:42:36 GMT</pubDate>
  <title>Review: The Baroque Cycle</title>
  <link>http://anthonybailey.net/blog/2009/02/21/the-baroque-cycle</link>
  <description>
&lt;div class=&quot;&quot; style=&quot;width:90%&quot;&gt;
&lt;ul style=&quot;display:none&quot;&gt;
&lt;li&gt;(&lt;a href=&quot;http://microformats.org/wiki/hreview&quot; rel=&quot;nofollow&quot;&gt;hreview&lt;/a&gt; version &lt;span class=&quot;&quot;&gt;0.2&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;(Reviewed on &lt;abbr class=&quot;&quot; title=&quot;2009-02-21T20:12:49+00:00&quot;&gt;21 February 2009&lt;/abbr&gt;
by &lt;a class=&quot;&quot; href=&quot;http://anthonybailey.net/&quot; rel=&quot;nofollow&quot;&gt; &lt;span class=&quot;&quot;&gt;Anthony Bailey&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;&quot; style=&quot;display:none&quot;&gt;product&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;a class=&quot;&quot; href=&quot;http://www.amazon.com/gp/series/88340&quot; rel=&quot;nofollow&quot;&gt;
    &lt;cite&gt;The Baroque Cycle&lt;/cite&gt;
    by &lt;author&gt;Neal Stephenson&lt;/author&gt;
&lt;/a&gt;
&lt;blockquote class=&quot;&quot;&gt;
&lt;div&gt;&lt;a href=&quot;http://amazon.com/gp/product/0099410680&quot; rel=&quot;nofollow&quot;&gt;
&lt;img style=&quot;margin-left: 2em&quot; alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/c20e6a7e47851e30f87413e9eccde9c3c49c2634/nH31Fc7lEJLodsQSjwa9axrr9JMu5dmlCPWrSD-J8Wsvbmsx2adMgFbtXxJnaKzjdoLjHsFa8mANOugS3qIMMZAWXToUwVBC4DdaCP652qk&quot; /&gt;&lt;/a&gt;
&lt;p&gt;Size matters, here. &lt;cite&gt;The Baroque Cycle&lt;/cite&gt; is something of an epic, at around one million words long. (Workings: &lt;a href=&quot;http://amazon.com/gp/product/0099410680&quot; title=&quot;Quicksilver&quot; rel=&quot;nofollow&quot;&gt;its&lt;/a&gt; &lt;a href=&quot;http://amazon.com/dp/0099410699&quot; title=&quot;The Confusion&quot; rel=&quot;nofollow&quot;&gt;three&lt;/a&gt; &lt;a href=&quot;http://amazon.com/dp/0099463369&quot; title=&quot;The System of the World&quot; rel=&quot;nofollow&quot;&gt;books&lt;/a&gt; end on page numbers 916 + 815 + 886 = 2617 pages * 45 lines/page * 10 words/line = 1.12Mwords, then round down some whitespace.) 
&lt;/p&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;http://amazon.com/dp/0099410699&quot; rel=&quot;nofollow&quot;&gt;
&lt;img style=&quot;margin-right: 2em&quot; alt=&quot;book cover&quot; align=&quot;left&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/a3eb7368eb045f68ab37870dcc36b38fdf7a4f1a/nH31Fc7lEJLodsQSjwa9axrr9JMu5dmlCPWrSD-J8Wsvbmsx2adMgFbtXxJnaKzjeuZD64o6aJ8CySflcBDV871M7tn5BosJwqLtl1anQrs&quot; /&gt;&lt;/a&gt;
&lt;p&gt;The trilogy is a &quot;behind the scenes&quot; saga spanning fifty years of scientific and economic alchemy, featuring characters from the pages of history but centered on three of their peers whose tales escaped the official record.
&lt;/p&gt;&lt;/div&gt;
&lt;div&gt;&lt;a href=&quot;http://amazon.com/dp/0099463369&quot; rel=&quot;nofollow&quot;&gt;
&lt;img style=&quot;margin-left: 2em&quot; alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/2f204d62f33ff2cc3c66600633761b0e1106bbf9/nH31Fc7lEJLodsQSjwa9axrr9JMu5dmlCPWrSD-J8Wsvbmsx2adMgFbtXxJnaKzjfHdRUn5sTPa2gdhoAc26jkEu7itbF829RFH5nKt23jE&quot; /&gt;&lt;/a&gt;
&lt;p&gt;In many ways this is the 17th/18th century version of the same author&apos;s more contemporary &lt;a href=&quot;http://amazon.com/dp/0060512806&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Cryptonomicon&lt;/cite&gt;&lt;/a&gt;, with which it shares the above approach, plenty of adventures colored by cryptography and computation, and &lt;a title=&quot;Insert spoiler here...&quot;&gt;more&lt;/a&gt;. However, I found its sprawling scope resulted in less value per page: its three books contain only a little more gold in total than &lt;cite&gt;Cryptonomicon&lt;/cite&gt;&apos;s one. 
&lt;/p&gt;&lt;/div&gt;
&lt;/blockquote&gt;&lt;/div&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/35888.html#comments</comments>
  <category>hreview</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/35797.html</guid>
  <pubDate>Mon, 15 Dec 2008 23:38:46 GMT</pubDate>
  <title>Contacts: Let&apos;s keep all this between ourselves</title>
  <link>http://anthonybailey.net/blog/2008/12/15/lets-keep-all-this-between-ourselves</link>
  <description>&lt;p&gt;
I want to describe how I like contact(s) information on the Net to work.
&lt;/p&gt;

&lt;p&gt;
I say &quot;contact(s)&quot; because I have complementary ideas regarding both the contact details for a person, and the details of who their contacts are - you can say &quot;friends&quot; or &quot;social graph&quot; for the latter if you like. To oversimplify: I want the information sources to be distributed, and to delegate to individuals as authorities for their own details. I find that most current technologies don&apos;t share this ideology; however, I can still use them to act in tune with it.
&lt;/p&gt;

&lt;p&gt;
An introductory note: I&apos;m going to talk about people &quot;owning&quot; a web page. What I mean is that they have significant control over the main content of the page, which is published under as permanent an URL as possible. They definitely don&apos;t have to serve the page from their own machine, or from a host that they rent - a page on a social network or in an ISP&apos;s basic web hosting area is fine. The URL can be under someone else&apos;s domain, so long as they have confidence it will last a while. (&lt;a href=&quot;#own_the_domain&quot; rel=&quot;nofollow&quot;&gt;IMHO aside: own the domain.&lt;/a&gt;)
&lt;/p&gt;

&lt;p&gt;
My suggestion about contacts assumes some kind of a homepage/identity baseline: that people own some page that is about them - such as a blog, or a presence on a social network. Their homepage URL is then a decent identifier for their identity online. For bonus points, they can prove that they are the person who owns that page through OpenID, or Facebook Connect, or similar.  All this is standard for many people online already, and it can easily enough be true for anyone else who cares to make it so. 
&lt;/p&gt;

&lt;p&gt;
My stance is that &lt;strong&gt;I want to own my &lt;em&gt;contact&lt;/em&gt; information&lt;/strong&gt; - because I believe I&apos;m best placed to be the central authority it. I want to publish it as a resource located on or somewhere that is discoverable from my homepage, in a standard format. (Until the world stabilizes a bit, probably in multiple formats, all views of the same underlying data.) I&apos;d like others to do the same. It&apos;s up to them exactly which details they publish. If they care to, they can even restrict access to some information, making it &quot;friends only&quot;. (&lt;a href=&quot;#most_privacy_is_squeamish&quot; rel=&quot;nofollow&quot;&gt;IMHO aside: most privacy is squeamish.&lt;/a&gt;)
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;I also want to own my &lt;em&gt;contacts&lt;/em&gt; information&lt;/strong&gt; - the list of other people that I know. For each of them I want to store and publish a homepage URL, and also a name - given how neither or those identifiers is completely permanent. I also own how I personally would describe my relationship with these people. This perspective need not be reciprocated.
&lt;/p&gt;

&lt;p&gt;
But, &lt;strong&gt;I don&apos;t want to own my &lt;em&gt;contacts&apos;&lt;/em&gt; information&lt;/strong&gt;. I want to delegate that to them! In as much as my contacts list is an address book, it should be so only through indirection: to find out about a contact, go to the homepage I have linked for them, and discover the contact information that they themselves have published there.
&lt;/p&gt;

&lt;p&gt;
Most current systems do not assume such delegation: I am expected to own other people&apos;s contact information, as well as mine. I presume this is a deliberate compromise in order to gain critical mass (of contact details published online in general and on the vendors network in particular.) My own disdain for such practicality comes partly from not finding much need for an address book per se - perhaps if my network(ing) were better this would be otherwise. But, even allowing for that, I don&apos;t see the delegation I desire called out as an ideal or an aspiration anywhere in the design or implementation of current systems. Evangelizing this, and exploring how to get there from here, is the motivation for this and my next blog entry.
&lt;/p&gt;

&lt;p&gt;
There are a two main reasons I want things to work this way. 
&lt;ul&gt;
&lt;li style=&quot;padding-bottom: 1em&quot;&gt;
Firstly, there is the golden rule: if I want to own my contact details, I should should grant other people the right to own theirs.
&lt;/li&gt;
&lt;li&gt;
Secondly, I&apos;d rather not have the hassle of complicating my own records with other people&apos;s details. Let the person who knows best update their information in a single place, and I&apos;ll get their latest details by going there. This also avoids my having to take responsibility for choosing which of their details to publish. Given current preciousness about privacy, this side-steps a potential minefield.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;
There is a yet more open approach that I have refrained from advocating. In a truly distributed wiki-wiki-world, one could argue that an individual&apos;s opinions on information about themself should not be sacrosanct - that we should seek a consensus of everyone&apos;s opinions. On most truths, I&apos;m all for this kind of emergence. But when it comes to how to contact an individual I think having them be the single authority is too useful a shortcut, and it may have psychologically benefit, too! Letting the rest of the world speak for those as yet offline, though, could be a decent strategy to cover the gaps between where we are and where I want us to be.
&lt;/p&gt;

&lt;p&gt;
Talking of such strategies: next time I&apos;ll write about my current implementation of the plan I advocate using existing contacts technologies - hCard, XFN, FoaF, PoCo, et al.
&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;
I have some further opinions that are related to the discussion above but would have distracted from its core, so I&apos;ve moved them down here.
&lt;/p&gt;

&lt;p&gt;
&lt;a name=&quot;own_the_domain&quot;&gt;Own the domain&lt;/a&gt;: If you&apos;re going to own a page of significance to you, I would advocate controlling the domain name of the URL you publish it under. By all means have another party host the content, just point your own URL at where the page currently is. That way you can change the service/hosting provider without losing the URL by which people find the page.
&lt;/p&gt;

&lt;p&gt;
&lt;a name=&quot;most_privacy_is_squeamish&quot;&gt;Most privacy is squeamish&lt;/a&gt;: Although many are nervous about publishing it, I think much contact and other &quot;personal&quot; information is most naturally public: going ex-directory is weird. The impact of problems that might arise from publishing e-mail, mailing address or biography is overestimated. You&apos;re getting spam anyway. Stalkers are rare. The existence of the concept of &quot;identity theft&quot; occuring through knowledge of simple everyday facts - like a birthday, a hometown, a mother&apos;s maiden name - is a symptom of immature authentication procedures, a laughable security through not-even-obscurity. Lastly, contact details are useless without at least some users - and &lt;a href=&quot;http://anthonybailey.net/tumblelog/2007/09/30/digital-privacy-management-is-ineffable&quot; rel=&quot;nofollow&quot;&gt;trying to control how others use and copy bits is a mug&apos;s game&lt;/a&gt;.
&lt;/p&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/35797.html#comments</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>2</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/35337.html</guid>
  <pubDate>Wed, 22 Oct 2008 19:50:10 GMT</pubDate>
  <title>Review: Implementation Patterns</title>
  <link>http://anthonybailey.net/blog/2008/10/22/implementation-patterns</link>
  <description>
&lt;div class=&quot;&quot; style=&quot;width:90%&quot;&gt;
&lt;ul style=&quot;display:none&quot;&gt;
&lt;li&gt;(&lt;a href=&quot;http://microformats.org/wiki/hreview&quot; rel=&quot;nofollow&quot;&gt;hreview&lt;/a&gt; version &lt;span class=&quot;&quot;&gt;0.2&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;(Reviewed on &lt;abbr class=&quot;&quot; title=&quot;2008-10-22T20:21:25+0100&quot;&gt;22 October 2008&lt;/abbr&gt;
by &lt;a class=&quot;&quot; href=&quot;http://anthonybailey.net/&quot; rel=&quot;nofollow&quot;&gt; &lt;span class=&quot;&quot;&gt;Anthony Bailey&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;&quot; style=&quot;display:none&quot;&gt;product&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/52df652d3e781db913540ccdc5bc5e8c879c4c87/nH31Fc7lEJLodsQSjwa9a8CQdOTCDW-cPAFt-t34uhLIl0qcp0qEDxDcrQ5-By-f6MR1M0rcmuujsk8ZLTZuriz01LanDxsuR01aMm4Xo4Ji3Asc6mAcSqsGJRKTPTeS&quot; /&gt;&lt;a class=&quot;&quot; href=&quot;http://www.amazon.com/gp/product/0321413091&quot; rel=&quot;nofollow&quot;&gt;
    &lt;cite&gt;Implementation Patterns (Addison-Wesley Signature Series)&lt;/cite&gt;
    by &lt;author&gt;Kent Beck&lt;/author&gt;
&lt;/a&gt;
&lt;blockquote class=&quot;&quot;&gt;&lt;p&gt;
This book concerns the detailed choices we make minute-to-minute when implementing programs.
&lt;/p&gt;&lt;p&gt;
The first twenty pages express Beck&apos;s context and motivation in his usual fashion: some personal history and philosophy, some thoughts on cost, and a prioritized set of values (communication, simplicity and flexibility) and some principles (DRYness, symmetry, preferring declarative to procedural expression, plus three ways to group things that change together) that help in translating those values into specific practices or patterns.
&lt;/p&gt;&lt;p&gt;
The next hundred pages is a catalog of seventy-seven such patterns.
&lt;/p&gt;&lt;p&gt;
Two closing chapters offer an overview of collections, and sketch some ideas of how things change if you&apos;re coding a framework rather than a specific application.
&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;
I think those first twenty pages are excellent. Two of my previous favorite books by Beck outlined a core precept, asked &quot;what if we run with it?&quot;, then detailed how to extract far more value than you might initially expect. (To over-simplify: &lt;a href=&quot;http://www.amazon.com/Extreme-Programming-Explained-Embrace-Change/dp/0321278658&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;XP Explained&lt;/cite&gt;&lt;/a&gt; follows from keeping the cost-of-change curve as flat as possible, &lt;a href=&quot;http://www.amazon.com/Test-Driven-Development-Addison-Wesley-Signature/dp/0321146530&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Test-Driven Development&lt;/cite&gt;&lt;/a&gt; follows from a belief that making code testable improves its design.)
&lt;/p&gt;&lt;p&gt;
The main idea in &lt;cite&gt;Implementation Patterns&lt;/cite&gt; is that making code readable is key in good implementation, and that turning those dials to eleven will provide similar unexpected insight. (For example: given that a good name for a variable describes its role in context, then if all good names seem long, you&apos;re probably missing an abstraction of context - i.e. there&apos;s a class waiting to be extracted.) Not quite as big an idea as in the other two books, but very plausible, and my appetite was whetted for the patterns where I hoped this idea, and all the values and principles, would be explored and discussed in context.
&lt;/p&gt;&lt;p&gt;
Alas, no. I was very disappointed. (The above was about the only example I could find.) There was very little exploration and discussion, and the patterns did not often refer back to the values and principles, even implicitly.
&lt;/p&gt;&lt;p&gt;
OK, since it doesn&apos;t build sufficiently on the introduction&apos;s abstractions, the meat of the book had better work well as a stand-alone catalog of patterns. 
&lt;/p&gt;&lt;p&gt;
Alas, a second no. One of the useful things explicit lists of patterns do is to give a name to a concept so we can communicate about it. Beck&apos;s list does do this useful thing. But, that is about the only useful thing it does. Once named, there is rarely additional insight in the pattern descriptions: they mostly do exactly what they say on the tin. You can read the &lt;a href=&quot;http://safari.oreilly.com/9780321413093?tocview=true&quot; rel=&quot;nofollow&quot;&gt;table of contents&lt;/a&gt; to see how simple the concepts under discussion are.
&lt;/p&gt;&lt;p&gt;
The last two chapters are fine, but unremarkable.
&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;
My recommendation: borrow the book to read the material preceding the catalog. Then buy and read &lt;a href=&quot;http://anthonybailey.net/blog/2008/09/03/clean-code&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Clean Code&lt;/cite&gt;&lt;/a&gt;.
&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/35337.html#comments</comments>
  <category>software_development</category>
  <category>hreview</category>
  <lj:mood>disappointed</lj:mood>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/35207.html</guid>
  <pubDate>Sun, 19 Oct 2008 21:04:04 GMT</pubDate>
  <title>Minimal OpenID glue for Rails authentication</title>
  <link>http://anthonybailey.net/blog/2008/10/19/minimal-openid-glue-for-rails-authentication</link>
  <description>&lt;p&gt;
The Rails framework and culture offer a well-developed set of plug-ins and patterns for the authentication of users and the authorization of their actions. These are great for more sophisticated enterprise and social applications - but as a hobbyist, my own apps don&apos;t tend to need a database full of users and roles. Typically &lt;strong&gt;the only user I care about authenticating is me&lt;/strong&gt;, for write access to content that everyone else should view read-only without any hassle. I want something very &lt;strong&gt;lightweight&lt;/strong&gt;.
&lt;/p&gt;

&lt;p&gt;

The app behind &lt;a href=&quot;http://anthonybailey.net&quot; rel=&quot;nofollow&quot;&gt;my ego site&lt;/a&gt; is a good example. It presents pages based on a few sets of resources - contacts, and various flavors of &lt;a href=&quot;http://anthonybailey.net/tumblelog/2007/10/27/permanent-obsession&quot; rel=&quot;nofollow&quot;&gt;permalinks for blog entries which are hosted elsewhere&lt;/a&gt;. Everybody should be able to access those pages. Behind the scenes there is some simple scaffolding for managing the resources. Only I should be accessing those.
&lt;/p&gt;

&lt;p&gt;
The simplest solution is security through obscurity - to keep quiet about the management URLs. It&apos;s not &lt;em&gt;that&lt;/em&gt; bad an approach for a low-stakes app, and I did rely on it for a while. Felt wrong, though.
&lt;/p&gt;

&lt;p&gt;
Having decided to do better, I still wanted to keep things as lightweight as I could. My first preference is to &lt;strong&gt;minimize the use of the Rails session&lt;/strong&gt;: I don&apos;t want people who visit my public pages to get lumbered with a pointless cookie, so I switch sessions off by default.
&lt;/p&gt;

&lt;p&gt;
One way to keep authenticated session management out of the way of users and apps is to &lt;strong&gt;place it in the HTTP layer&lt;/strong&gt;. I am a big fan of the &lt;a href=&quot;http://dev.rubyonrails.org/browser/plugins/http_authentication&quot; rel=&quot;nofollow&quot;&gt;http_authentication&lt;/a&gt; Rails plug-in. The browser on the client side takes care of the session sign-on UI and state, getting users to log in once on first access to protected pages. In your app, you can use a before_filter with implementation as simple as: 
&lt;hr /&gt;&lt;b&gt;
&lt;pre&gt;authenticate_or_request_with_http_basic &lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;do&lt;/span&gt; |ignore_user, password|
  password == &lt;span style=&quot;background-color:#fff0f0&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#D20&quot;&gt;your secret&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/b&gt;&lt;hr /&gt;
&lt;/p&gt;

&lt;p&gt;
But, I have a second preference. &lt;strong&gt;I don&apos;t want arbitrary secrets in my apps, or in my brain.&lt;/strong&gt; I want single sign-on, please, and my web app just needs to know that I am who I say I am - let someone else do the verification of that identity. And I am already &lt;a href=&quot;http://anthonybailey.net/tumblelog/2007/12/09/open-id&quot; rel=&quot;nofollow&quot;&gt;enthusiastic about a technology for authenticating identity&lt;/a&gt; in this way - it&apos;s &lt;strong&gt;&lt;a href=&quot;http://openid.net&quot; rel=&quot;nofollow&quot;&gt;OpenID&lt;/a&gt;&lt;/strong&gt;.
&lt;/p&gt;

&lt;p&gt;
Following a &quot;gem install &lt;a href=&quot;http://openidenabled.com/ruby-openid&quot; rel=&quot;nofollow&quot;&gt;ruby-openid&lt;/a&gt;&quot;, I still wanted as little Rails glue as possible. The &lt;a href=&quot;http://agilewebdevelopment.com/plugins/openidauthentication&quot; rel=&quot;nofollow&quot;&gt;open_id_authentication&lt;/a&gt; plug-in is pretty compact given its power, but it does tend to assume that users will live in the database, and it provides all kinds of store machinery that I don&apos;t need.
&lt;/p&gt;

&lt;p&gt;
So I cut non-essentials away from the plug-in source and ended up with this &lt;strong&gt;minimal parent for my resource controllers&lt;/strong&gt;.
&lt;/p&gt;

&lt;hr /&gt;&lt;b&gt;
&lt;pre&gt;require &lt;span style=&quot;background-color:#fff0f0&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#D20&quot;&gt;openid/consumer&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;

&lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color:#B06; font-weight:bold&quot;&gt;ResourceProtectingController&lt;/span&gt; &amp;lt; &lt;span style=&quot;color:#036; font-weight:bold&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span style=&quot;color:#369&quot;&gt;@@PROTECTED_ACTIONS&lt;/span&gt; = &lt;span style=&quot;background-color:#fff0f0&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;%w(&lt;/span&gt;&lt;span style=&quot;color:#D20&quot;&gt;new create edit update destroy&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
  session &lt;span style=&quot;color:#A60&quot;&gt;:disabled&lt;/span&gt; =&amp;gt; &lt;span style=&quot;color:#038; font-weight:bold&quot;&gt;false&lt;/span&gt;, &lt;span style=&quot;color:#A60&quot;&gt;:only&lt;/span&gt; =&amp;gt; &lt;span style=&quot;color:#369&quot;&gt;@@PROTECTED_ACTIONS&lt;/span&gt;
  before_filter &lt;span style=&quot;color:#A60&quot;&gt;:protect&lt;/span&gt;, &lt;span style=&quot;color:#A60&quot;&gt;:only&lt;/span&gt; =&amp;gt; &lt;span style=&quot;color:#369&quot;&gt;@@PROTECTED_ACTIONS&lt;/span&gt;

  protected
  &lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color:#06B; font-weight:bold&quot;&gt;protect&lt;/span&gt;
    &lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;if&lt;/span&gt; session[&lt;span style=&quot;color:#A60&quot;&gt;:authenticated&lt;/span&gt;]
    realm = &lt;span style=&quot;background-color:#fff0f0&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;background: #eee&quot;&gt;&lt;span style=&quot;font-weight: bold; color: #888&quot;&gt;#{&lt;/span&gt;request.protocol + request.host_with_port&lt;span style=&quot;font-weight: bold; color: #888&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    requested_url = &lt;span style=&quot;background-color:#fff0f0&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;background: #eee&quot;&gt;&lt;span style=&quot;font-weight: bold; color: #888&quot;&gt;#{&lt;/span&gt;realm + request.relative_url_root + request.path&lt;span style=&quot;font-weight: bold; color: #888&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    identity_url = &lt;span style=&quot;background-color:#fff0f0&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#D20&quot;&gt;http://anthonybailey.net&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    consumer = &lt;span style=&quot;color:#036; font-weight:bold&quot;&gt;OpenID&lt;/span&gt;::&lt;span style=&quot;color:#036; font-weight:bold&quot;&gt;Consumer&lt;/span&gt;.new(session, &lt;span style=&quot;color:#038; font-weight:bold&quot;&gt;nil&lt;/span&gt;)
    &lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;if&lt;/span&gt; params[&lt;span style=&quot;color:#A60&quot;&gt;:open_id_complete&lt;/span&gt;].nil?
      open_id_request = consumer.begin(identity_url)
      open_id_request.return_to_args[&lt;span style=&quot;background-color:#fff0f0&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#D20&quot;&gt;open_id_complete&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;] = &lt;span style=&quot;background-color:#fff0f0&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#D20&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;
      redirect_to(open_id_request.redirect_url(realm, requested_url))
    &lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;else&lt;/span&gt;
      returned_params = params.reject {|k, v| request.path_parameters[k] }
      returned_params.delete(&lt;span style=&quot;color:#A60&quot;&gt;:format&lt;/span&gt;)
      open_id_response = consumer.complete(returned_params, requested_url)
      &lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;if&lt;/span&gt; open_id_response.status != &lt;span style=&quot;color:#036; font-weight:bold&quot;&gt;OpenID&lt;/span&gt;::&lt;span style=&quot;color:#036; font-weight:bold&quot;&gt;Consumer&lt;/span&gt;::&lt;span style=&quot;color:#036; font-weight:bold&quot;&gt;SUCCESS&lt;/span&gt;
        render &lt;span style=&quot;color:#A60&quot;&gt;:text&lt;/span&gt; =&amp;gt; &lt;span style=&quot;background-color:#fff0f0&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#D20&quot;&gt;Forbidden: got &lt;/span&gt;&lt;span style=&quot;background: #eee&quot;&gt;&lt;span style=&quot;font-weight: bold; color: #888&quot;&gt;#{&lt;/span&gt;open_id_response.class&lt;span style=&quot;font-weight: bold; color: #888&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#D20&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +
                        &lt;span style=&quot;background-color:#fff0f0&quot;&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color:#D20&quot;&gt;on claiming &lt;/span&gt;&lt;span style=&quot;background: #eee&quot;&gt;&lt;span style=&quot;font-weight: bold; color: #888&quot;&gt;#{&lt;/span&gt;identity_url&lt;span style=&quot;font-weight: bold; color: #888&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#710&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span style=&quot;color:#A60&quot;&gt;:status&lt;/span&gt; =&amp;gt; &lt;span style=&quot;color:#00D; font-weight:bold&quot;&gt;401&lt;/span&gt;
      &lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;else&lt;/span&gt;
        session[&lt;span style=&quot;color:#A60&quot;&gt;:authenticated&lt;/span&gt;] = &lt;span style=&quot;color:#038; font-weight:bold&quot;&gt;true&lt;/span&gt;
      &lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;end&lt;/span&gt;
    &lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color:#080; font-weight:bold&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/b&gt;&lt;hr /&gt;

&lt;p&gt;
Some notes on the implementation:
&lt;ul&gt;
&lt;li&gt;Because OpenID involves a stateful request dance between the relying party and the identity provider, I had to reintroduce the Rails session. However, I can still keep cookies away from the public by only enabling it for the actions needing protection.&lt;/li&gt;
&lt;li&gt;Now I have a session, I ensure that only one dance is required, by stashing the authenticated status. This also works around the fact that OpenID can only return using the GET method: in regular use the client will GET a prelude page before it needs to POST, etc. a real change, at which point we&apos;ve finished dancing with the provider.&lt;/li&gt;
&lt;li&gt;Mostly as a conceptual indulgence, I left the read-only actions &lt;em&gt;unprotected&lt;/em&gt;. (To keep things GET-first, I moved scaffolding UI to delete resources off index pages and onto edit pages - but I kind of feel that&apos;s where it should be anyway.)
&lt;li&gt;Since if you&apos;re not me, you&apos;re not supposed to be here, I didn&apos;t friendly-up the content when access fails.&lt;/li&gt;
&lt;li&gt;Finally, as an aside, it amuses me that my identity URL actually &lt;em&gt;is&lt;/em&gt; the domain of the URLs I&apos;m protecting. (I don&apos;t run my own identity server, mind - I delegate.)
&lt;/ul&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;
&lt;/p&gt;</description>
  <comments>https://anthonybailey.livejournal.com/35207.html#comments</comments>
  <category>software_development</category>
  <category>rails</category>
  <lj:security>public</lj:security>
  <lj:reply-count>11</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/35069.html</guid>
  <pubDate>Wed, 01 Oct 2008 23:07:23 GMT</pubDate>
  <title>Review: Little Brother</title>
  <link>http://anthonybailey.net/blog/2008/10/01/little-brother</link>
  <description>
&lt;div class=&quot;&quot; style=&quot;width:90%&quot;&gt;
&lt;ul style=&quot;display:none&quot;&gt;
&lt;li&gt;(&lt;a href=&quot;http://microformats.org/wiki/hreview&quot; rel=&quot;nofollow&quot;&gt;hreview&lt;/a&gt; version &lt;span class=&quot;&quot;&gt;0.2&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;(Reviewed on &lt;abbr class=&quot;&quot; title=&quot;2008-10-02T00:00:01+0100&quot;&gt;02 October 2008&lt;/abbr&gt;
by &lt;a class=&quot;&quot; href=&quot;http://anthonybailey.net/&quot; rel=&quot;nofollow&quot;&gt; &lt;span class=&quot;&quot;&gt;Anthony Bailey&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;&quot; style=&quot;display:none&quot;&gt;product&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/4ba6b90c221b46180f583ca7e1a2e5fadbc70872/nH31Fc7lEJLodsQSjwa9a8CQdOTCDW-cPAFt-t34uhLIl0qcp0qEDxDcrQ5-By-fMSzwN4vON7fKvYQrs5VToFQsg2BHyMtXXKgDprtVsSZ-dv5n049J9CThG3s6i5WQ&quot; /&gt;&lt;a class=&quot;&quot; href=&quot;http://craphound.com/littlebrother&quot; rel=&quot;nofollow&quot;&gt;
    &lt;cite&gt;Little Brother&lt;/cite&gt;
    by &lt;author&gt;Cory Doctorow&lt;/author&gt;
&lt;/a&gt;
&lt;blockquote class=&quot;&quot;&gt;&lt;p&gt;
This is a fun coming-of-age adventure telling a very contemporary tale of tech-savvy teenage righteous rebellion against a police state.
&lt;/p&gt;&lt;p&gt;
The plot is straightforward in the large, but the formula is well-executed, is written in a convincing voice, and features wonderful details. Doctorow regularly writes apparently futuristic science-fiction simply by basing his fiction on today&apos;s cutting edge, and the edge cuts keenly in this book - the politics and technologies are all here today or grown tomorrow.
&lt;/p&gt;&lt;p&gt;
I read the &lt;a href=&quot;http://craphound.com/littlebrother/download/&quot; rel=&quot;nofollow&quot;&gt;free CC-licensed download&lt;/a&gt;, as I did with one of his previous &lt;cite&gt;Eastern Standard Tribe&lt;/cite&gt; - and the business model of this publishing approach (of which Doctorow is one of the earliest adopters and most passionate proponents) proves itself again: I&apos;ve just ordered &lt;a href=&quot;http://www.amazon.co.uk/Little-Brother-Cory-Doctorow/dp/0007288425&quot; rel=&quot;nofollow&quot;&gt;a copy of the just released UK paperback&lt;/a&gt; to send as geek propaganda to my own &lt;a href=&quot;http://www.facebook.com/profile.php?id=774550437&quot; rel=&quot;nofollow&quot;&gt;younger sibling&lt;/a&gt;.
&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/35069.html#comments</comments>
  <category>hreview</category>
  <lj:mood>rejuvenated</lj:mood>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/34636.html</guid>
  <pubDate>Wed, 03 Sep 2008 19:43:22 GMT</pubDate>
  <title>Review: Clean Code</title>
  <link>http://anthonybailey.net/blog/2008/09/03/clean-code</link>
  <description>
&lt;div class=&quot;&quot; style=&quot;width:90%&quot;&gt;
&lt;ul style=&quot;display:none&quot;&gt;
&lt;li&gt;(&lt;a href=&quot;http://microformats.org/wiki/hreview&quot; rel=&quot;nofollow&quot;&gt;hreview&lt;/a&gt; version &lt;span class=&quot;&quot;&gt;0.2&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;(Reviewed on &lt;abbr class=&quot;&quot; title=&quot;2008-09-01T18:37:18+0100&quot;&gt;01 September 2008&lt;/abbr&gt;
by &lt;a class=&quot;&quot; href=&quot;http://anthonybailey.net/&quot; rel=&quot;nofollow&quot;&gt; &lt;span class=&quot;&quot;&gt;Anthony Bailey&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;&quot; style=&quot;display:none&quot;&gt;product&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/1f0dbfe25868e4ec1a42bbb58cd7eef7a13fd8d9/nH31Fc7lEJLodsQSjwa9axrr9JMu5dmlCPWrSD-J8Wsvbmsx2adMgFbtXxJnaKzjIytDWxB2y_dhekfPFfgyQmDPXOhPoXPoNiRZXlj_n00&quot; /&gt;&lt;a class=&quot;&quot; href=&quot;http://www.amazon.com/gp/product/0132350882&quot; rel=&quot;nofollow&quot;&gt;
    &lt;cite&gt;Clean Code: A Handbook of Agile Software Craftsmanship&lt;/cite&gt;
    by &lt;author&gt;Robert C. Martin&lt;/author&gt;
&lt;/a&gt;
&lt;blockquote class=&quot;&quot;&gt;&lt;p&gt;
I wouldn&apos;t usually have cared to read yet another book on the generics of good programming practice. But this one was by Bob Martin, &quot;Uncle&quot; of the first family of thoughtful contemporary coding, and whose &lt;a href=&quot;http://blog.objectmentor.com/articles/category/uncle-bobs-blatherings&quot; rel=&quot;nofollow&quot;&gt;blog&lt;/a&gt; is high on my roll.
&lt;/p&gt;&lt;p&gt;
The book claims to be unusually hard work due to the substantial amount of code it contains. I disagree - you certainly want to dive deep into the examples, but I&apos;ve read plenty of texts containing more code and less value. (Although, for a book that encourages reading code, and that argues for the retirement of outdated formatting conventions, I am frankly mystified by the &lt;a href=&quot;http://anthonybailey.net/blog/2005/11/15/monospace-culture&quot; rel=&quot;nofollow&quot;&gt;fixed-width&lt;/a&gt;, unhighlighted, vanishingly thin font used to present the examples: there might as well be tractor holes down both sides of the print-out.)
&lt;/p&gt;&lt;p&gt;
Martin makes the pragmatic simplifying choice of presenting everything in Java. That&apos;s fine; apart from some concurrency specifics, most of what is promoted will slip easily back and forth to e.g. C++ and Ruby - and if you can make Java pleasant to read, you&apos;ve earned my respect.
&lt;/p&gt;&lt;p&gt;
After an introduction featuring great abstract definitions of cleanliness from the near-godly, we get twelve solid chapters of concrete advice. An account of best practice should not be surprising to a decent practitioner - and I found much of &lt;cite&gt;Clean Code&lt;/cite&gt; to be a reassuring mix of the obvious (&quot;oh, I already know &lt;strong&gt;that&lt;/strong&gt;&quot;) and the nicely crystallized (&quot;oh, &lt;strong&gt;that&lt;/strong&gt;&apos;s what I already know&quot;.) &lt;abbr title=&quot;Test-Driven Development&quot;&gt;TDD&lt;/abbr&gt;, culling comments, careful naming, ultra-&lt;abbr title=&quot;Don&amp;amp;apos;t Repeat Yourself&quot;&gt;DRY&lt;/abbr&gt;, breaking dependencies, small methods, yada yada yada.
&lt;/p&gt;&lt;p&gt;
There&apos;s also sufficient challenge (&quot;oh, you&apos;re going to push it that far?&quot;) and controversy (&quot;er, wtf? maybe...&quot;) to keep it interesting. Uncle Bob is illuminatingly obsessive about the law of Demeter and the single responsibility and open/closed principles. He particularly surprised me with his enthusiasm for keeping plain old data structures around within the object-oriented world. 
&lt;/p&gt;&lt;p&gt;
But the three large case studies that close the book are the real gold here - the summary list of smells drawn from them is no substitute for their glorious, odorous detail. They are very engaging: despite their final shininess, I bet you too will want to polish them a little further.
&lt;/p&gt;&lt;p&gt;
Recommended.
&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/34636.html#comments</comments>
  <category>software_development</category>
  <category>hreview</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/34471.html</guid>
  <pubDate>Sun, 20 Jul 2008 16:08:40 GMT</pubDate>
  <title>Review: Bulletproof Web Design</title>
  <link>http://anthonybailey.net/blog/2008/07/20/bulletproof-web-design</link>
  <description>
&lt;div class=&quot;&quot; style=&quot;width:90%&quot;&gt;

&lt;ul style=&quot;display:none&quot;&gt;

&lt;li&gt;(&lt;a href=&quot;http://microformats.org/wiki/hreview&quot; rel=&quot;nofollow&quot;&gt;hreview&lt;/a&gt; version &lt;span class=&quot;&quot;&gt;0.2&lt;/span&gt;)&lt;/li&gt;

&lt;li&gt;(Reviewed on &lt;abbr class=&quot;&quot; title=&quot;2008-07-20T16:39:55+0100&quot;&gt;20 July 2008&lt;/abbr&gt;

by &lt;a class=&quot;&quot; href=&quot;http://anthonybailey.net/&quot; rel=&quot;nofollow&quot;&gt; &lt;span class=&quot;&quot;&gt;Anthony Bailey&lt;/span&gt;&lt;/a&gt;)&lt;/li&gt;

&lt;li&gt;&lt;span class=&quot;&quot; style=&quot;display:none&quot;&gt;product&lt;/span&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;img alt=&quot;book cover&quot; align=&quot;right&quot; class=&quot;&quot; src=&quot;https://imgprx.livejournal.net/f45b39ebeb4abcce9e987dc832a3fce70036ea53/nH31Fc7lEJLodsQSjwa9a8CQdOTCDW-cPAFt-t34uhLIl0qcp0qEDxDcrQ5-By-fdMzQ3k0clPnpHmcsCHPblmuKi1OboQID8BM6yzulbWUXW_kmDXmwcfpsr2NlTA-V&quot; /&gt;&lt;a class=&quot;&quot; href=&quot;http://www.amazon.com/gp/product/0321346939&quot; rel=&quot;nofollow&quot;&gt;

   &lt;cite&gt;Bulletproof Web Design: Improving flexibility and protecting against worst-case scenarios with XHTML and CSS&lt;/cite&gt;

   by Dan Cederholm

&lt;/a&gt;

&lt;blockquote class=&quot;&quot;&gt;&lt;p&gt;

This is a slim (270 spacey pages) primer on robust &lt;abbr title=&quot;Cascading Style Sheets&quot;&gt;CSS&lt;/abbr&gt; practice. It isn&apos;t a reference book, nor really a compendium of recipes; more a set of ransackable case studies through which runs a persuasive essay on how and why to do this stuff right. (The basic precept is a principled separation of concerns: define style for mark-up that is independently semantically sound, rather than hacking div after nested div into your page in order to kludge your target design.)
&lt;/p&gt;&lt;p&gt;
I bought it a couple of years ago to learn how to do CSS-based layout, and did so by coding through many of the examples. I recently read it through a second time and was again impressed by its clarity and cohesion, and by how its elegant solutions do not sacrifice practicality - hence this review and recommendation. (And apart from a few thankfully obsolete IE5-generation workarounds, the content had not dated at all: though it preaches graceful degradation, the book hasn&apos;t yet had to practise it.)
&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;(If it seems strange that I broke blog silence this way - yes, usually I&apos;d put such a brief piece on &lt;a href=&quot;http://anthonybailey.net/tumblelog&quot; rel=&quot;nofollow&quot;&gt;my tumblelog&lt;/a&gt;, but Tumblr eats the &lt;a href=&quot;http://microformats.org/wiki/hreview&quot; rel=&quot;nofollow&quot;&gt;hreview&lt;/a&gt; mark-up.)&lt;/p&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/34471.html#comments</comments>
  <category>software_development</category>
  <category>hreview</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/34156.html</guid>
  <pubDate>Mon, 14 Apr 2008 00:06:30 GMT</pubDate>
  <title>What does BDD offer TDD die-hards?</title>
  <link>http://anthonybailey.net/blog/2008/04/14/what-does-bdd-offer-tdd-die-hards</link>
  <description>&lt;blockquote&gt;
&quot;As a &lt;var&gt;long-serving test-driven developer&lt;/var&gt;, I want to &lt;var&gt;understand how behavior-driven development differs&lt;/var&gt;, so that &lt;var&gt;I can decide whether or not to join the revolution&lt;/var&gt;.&quot;
&lt;/blockquote&gt;


&lt;h4&gt;Introduction&lt;/h4&gt;
&lt;p&gt;
A couple of years ago I was developing medical imaging software for diagnostic radiologists. The field exhibited an archetypal divide between non-coding experts who knew lots about the domain, and developers who did not. In the language of classical XP, we were coding from requirements supplied by a customer. Without a map, we explored many aspects of the customer/testing/developer relationship:
&lt;ul&gt;
&lt;li&gt;the importance of a ubiquitous language spoken across the whole team&lt;/li&gt;
&lt;li&gt;the connection between a spec and an executable test&lt;/li&gt;
&lt;li&gt;the automation of customer-written acceptance tests&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;
Very near the end of that time, I attended &lt;a href=&quot;http://xpday5.xpday.org/&quot; rel=&quot;nofollow&quot;&gt;XP Day 5 in London&lt;/a&gt;. Whilst there I talked some with &lt;a href=&quot;http://sirenian.livejournal.com/&quot; rel=&quot;nofollow&quot;&gt;Elizabeth Keogh&lt;/a&gt;, who was assisting &lt;a href=&quot;http://dannorth.net/&quot; rel=&quot;nofollow&quot;&gt;Dan North&lt;/a&gt; with the birth of &lt;a href=&quot;http://en.wikipedia.org/wiki/Behavior_Driven_Development&quot; rel=&quot;nofollow&quot;&gt;Behavior Driven Development&lt;/a&gt;. It sounded fascinating and &lt;em&gt;very&lt;/em&gt; relevant.
&lt;/p&gt;

&lt;p&gt;
But it became less of an immediate concern, because soon after I changed jobs. I moved to a new language and test suite in the context of a (simpler) domain and a culture where the devs were encouraged to internalize the expert/customer role.
&lt;/p&gt;

&lt;p&gt;
Now, over the past couple of years the BDD meme and tools have been surging in popularity. Meanwhile I&apos;m working well in a classical Test-Driven Development place some indeterminate distance away, catching occasional glimpses in my peripheral vision of what looks like a pleasant enough image in a slightly warped fun-house mirror, and trying to work out how the reflection differs.
&lt;/p&gt;

&lt;p&gt;
A couple of months back &lt;a href=&quot;http://tomtenthij.co.uk/&quot; rel=&quot;nofollow&quot;&gt;Tom ten Thij&lt;/a&gt; gave &lt;a href=&quot;http://tomtenthij.co.uk/2008/1/25/rspec-plain-text-story-runner-on-a-fresh-rails-app&quot; rel=&quot;nofollow&quot;&gt;a great BDD introduction&lt;/a&gt; at our &lt;a href=&quot;http://rubaidh.com/scotrug&quot; rel=&quot;nofollow&quot;&gt;local Ruby Users Group&lt;/a&gt;. But he had to handle heckling from many of the audience who met the following spec:
&lt;dl&gt;
&lt;dt&gt;Given&lt;/dt&gt;
&lt;dd&gt;I&apos;m a software developer who loves TDD and communicating well with customers,&lt;/dd&gt;
&lt;dt&gt;When&lt;/dt&gt;
&lt;dd&gt;I hear a talk on BDD that seems to promise exactly what I get from TDD and good customer communication,&lt;/dd&gt;
&lt;dt&gt;Then&lt;/dt&gt;
&lt;dd&gt;I find myself wondering exactly what all the fuss is about.&lt;/dd&gt;
&lt;/dl&gt;
&lt;/p&gt;

&lt;p&gt;
I took the question back to Liz, and she had interesting things to say. I hope sometime she may write them up properly herself, but in the meantime she said it would be fine if I wrote something. So, here&apos;s an &lt;i&gt;[edited]&lt;/i&gt; transcript of parts of the e-mail conversation we had.
&lt;/p&gt;


&lt;h4&gt;Context&lt;/h4&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
Yesterday at our local Ruby User Group here in Edinburgh we had a
presentation on RSpec and on BDD in general. The talk presented BDD from
first principles rather than assuming previous TDD experience. The
audience was mostly TDD old-timers, so a lot of the talk seemed like an
very familiar tale told in slightly different dialect.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
Our fuzzy consensus was acceptance that BDD is a nicer syntax; its
language is a better fit for the good things that test/spec-driven
development tries to do and hence the way it should be done from first
principles - but, is the change worth it for TDD die-hards who have
already completely internalized xUnit? What else do we get?
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
We realized none of us had ever come across a talk or article
evangelising BDD which particularly spoke to us; for example, by a
someone who&apos;d been very dedicated acolyte of TDD and had many wonderful
things to report once they&apos;d learned to Behave.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
I can&apos;t think of anything off the top of my head that addresses TDD gurus,
which is awful, because we should have sorted this out ages ago. Let me see
if I can help - please let me know if this is any use!
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
I&apos;ll devil&apos;s advocate some.
Personally, I&apos;m a big believer in the importance of language &lt;i&gt;[and]&lt;/i&gt;
I&apos;m simply not experienced enough to make any claim of
having seen it all before &lt;i&gt;[but]&lt;/i&gt;
I&apos;ll proxy for my peers who have been doing/teaching TDD for donkey&apos;s
years.
&lt;/p&gt;


&lt;h4&gt;Philosophy&lt;/h4&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
BDD isn&apos;t just about reworking the syntax of testing, though it started out
that way. It&apos;s evolved into something more; a language of examples that&apos;s
relevant at both a unit and system level, which allows better communication
with the business, and less redundant code.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
DDD &lt;i&gt;[Domain-Driven Design]&lt;/i&gt; provides the nouns, verbs and adjectives,
and BDD provides all the other
words which let you make sentences out of them. (Dan North, Eric Evans and I
were chatting about this at OOPSLA; I can&apos;t remember the exact words they
used, but this is close.)
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
It&apos;s all about the language. You don&apos;t really get anything else... but
language is pretty powerful! Changing the words we use can change the way we
think, and we don&apos;t have to change our technology to do it.
&lt;/p&gt;


&lt;h4&gt;Territorial dispute&lt;/h4&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
TDD is mostly about development - about taking a specification or acceptance
criteria, at either a system or unit level, and making the associated tests
pass. BDD assumes that it&apos;s not easy to get the right acceptance criteria in
the first place, so the language - including the famous &quot;should&quot; - is designed
to allow the original assumptions about the behaviour of the system to be
questioned; to have discussions about that behaviour without having to
translate from the technical world, either in speech (which helps us devs
talk to BAs and the business) or mentally (which helps us realise when we
need to ask a question). Of course, this is very closely aligned with DDD.
It&apos;s also why I prefer &quot;behaviour&quot; to &quot;spec&quot;; because it&apos;s easier to question
behaviour than a specification.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
I disagree with this characterization. Particularly at the lower levels
where the developer may be doing more of the work than the domain
expert, traditional TDD is very much about exploring and evolving the
behaviour of a system, one test at a time, asking questions rather than
blindly coding up an existing design or specification.
I completely buy the idea that the language of BDD helps make the
openness to change explicit, though.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
The best TDDers do BDD already, at least at a unit level. It&apos;s possible that
they don&apos;t think of elements of code as stakeholders, though; at least, I
haven&apos;t found any native TDDers with that mindset. It changes the names of
classes, at the very least. I am also aware that some die-hard, expert TDDers
concentrate more on the technology when they&apos;re teaching than the
conversations around tests.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
It helps my understanding if I consider BDD to
be taking a concept of TDD that fits particularly well with driving from
behaviors, and turning the dials on that concept up to ten. If not plain
wrong, this characterization may play well with an old guard XP/TDD
target audience.
&lt;/p&gt;


&lt;h4&gt;Frameworks&lt;/h4&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
First off, let me put to rest something really important:
You can do BDD in xUnit.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
would you go so far as to say that if you aren&apos;t
starting from scratch there may not sufficient advantage to switch from
xUnit to a more well-Behaved framework even if one falls for BDD in a
big way?
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
Don&apos;t use JBehave. It&apos;s a great teaching tool, but sucks IRL. I tend to use
JUnit. JBehave 2.0 should (when it eventually comes out) be easier. It&apos;s
going to be more like RSpec&apos;s plain text story runner, and consist of a lot
of JUnit exensions.
&lt;/p&gt;


&lt;h4&gt;Talking to business&lt;/h4&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
&lt;i&gt;[BDD offers]&lt;/i&gt; a language of examples that&apos;s relevant at both a unit
and system level, which allows better communication with the business
We use the word &apos;scenario&apos; or &apos;example&apos; because you don&apos;t go to the business
and say &apos;Give me an acceptance test&apos;. You say &apos;Give me an example&apos; or &apos;Give
me a scenario where that happens&apos;.
It becomes easier to maintain acceptance tests - and they become
human-readable!
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
Would you venture further? Non-developers can edit the acceptance test?
Non-developer can write the test when paired with developer as
translator? Non-developer can even write the test unambiguously without
direct developer assistance, given some further translation layer like a
plain-text story runner?
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
Absolutely. This has worked very well with our QAs.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
The last was a feature of the talk I attended. It drew attention from
the old TDD guard, who were all very XP-story-focussed and some of whom
had developed such translation layers themselves. It provoked both a
&quot;these BDD people sure have the right idea&quot; response as well as a &quot;and
it&apos;s an idea we had a while back, and is separable from the question of
changing terminology at the xUnit level&quot; one.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
Good. &quot;Should&quot; is trivial compared with the given / when / then language.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
Partly putting words in their mouths, and partly exploring something I
thought might be interesting: if you do end up with another layer
between the non-developer and the runnable test/behavior/spec - and our
experience is that perhaps this is worthwhile - then some of the
communication advantages of using BDD at the bottom layer are diluted.
If you have to use a translation
layer like a story runner to pre-process a more plain text description
of behavior, then using BDD terminology in the target code doesn&apos;t help
you so much with respect to communicating with the non-developer,
because they don&apos;t see that code, they see the source story. At that
point the BDD communication argument perhaps reduces to the DDD one
(albeit one I buy) that using business language as much as possible in
the code itself is worthwhile even when only the developer sees it.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
I guess I was wondering whether you&apos;d challenge the pre-condition - can
one make behaviors expressed in the production code language
sufficiently like plain English to be writeable by the non-developer?
(Perhaps it depends on the language?)
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
RSpec&apos;s stories now work in plain English. We hope JBehave 2.0&apos;s will be the
same. It&apos;s a nice little given / when / then DSL.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
I guess my point was that some long-time TDDers have so internalized
some of the translations from dev-centric terminology to plain English,
that they might consider a test very easy to read way before the
non-developers do. But purging such language habits would probably ease
indigestion nevertheless. And if BDD terminology becomes the standard,
there&apos;s also a communication benefit &lt;strong&gt;amongst&lt;/strong&gt; developers - the next
wave may well see &lt;code&gt;TestCase&lt;/code&gt;/test/assert as strange dinosaur language.
&lt;/p&gt;


&lt;h4&gt;Outside-in&lt;/h4&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
&lt;i&gt;[The BDD spec]&lt;/i&gt; leads to the first piece of code which the human stakeholders need,
which is the UI - the mechanism through which users (or 3rd party apps, say)
interact with our system, and through which behaviour is perceived. So this
is how we develop with BDD - from the outside-in.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
This was a part of BDD missing from the talk we heard, and it sounds
interesting. 
I enjoyed your &lt;a href=&quot;http://sirenian.livejournal.com/42871.html&quot; rel=&quot;nofollow&quot;&gt;real life example&lt;/a&gt;.
&lt;i&gt;[Re TDD]&lt;/i&gt; with &quot;the YAGNI of outside-in&quot; - whilst YAGNI itself is a TDD
cornerstone, I haven&apos;t heard the tenet that therefore one should always
start with the user interface layer.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
If you don&apos;t start with the interface, how do you know that you need it? How
do you know that the stakeholder code will be able to use what you&apos;re writing
in the way that you&apos;re writing it? You can pretend that you already have the
code, work out how you&apos;re going to use it, then code the real thing later -
this is exactly what we do with TDD anyway! Now we&apos;re taking that pattern
into production code too.
&lt;/p&gt;


&lt;h4&gt;Code has needs too!&lt;/h4&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
We use the same language of examples, to describe behaviour that provides
some benefit, at both a unit and a system level. The stakeholder at a unit
level becomes the other piece of code which needs that behaviour - so unless
we have some code already, we can&apos;t start.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
This analogy between human and code clients is not one I&apos;d heard
advanced quite so strongly in this context - is it important to BDD?
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
Yes!
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
&lt;i&gt;[In TDD]&lt;/i&gt; this definitely isn&apos;t an angle I&apos;ve
seen pushed hard. Trying to make client use of the new code readable,
sure, but not the kind of anthropomorphism you&apos;re advocating.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
I&apos;m not thinking of the stakeholders as human, as such, though it&apos;s a good
analogy - code changes just as much as people do! BDD is very need-driven.
Why are you coding that? Who&apos;s it for? What is going to benefit from that
line of code? It changes the names of classes, at the very least.
&lt;i&gt;[...]&lt;/i&gt;
We&apos;ve started naming things based on the responsibility to its stakeholder,
or its job, instead of the design pattern. As an example, we&apos;ve started
calling repositories after the plurals of whatever you get out of them - so,
&quot;&lt;code&gt;Puzzles&lt;/code&gt;&quot; for my sudoku creator, as opposed to
&quot;&lt;code&gt;PuzzleRepository&lt;/code&gt;&quot;.
&lt;/p&gt;


&lt;h4&gt;Given/Then, When&lt;/h4&gt;

&lt;p&gt;&lt;b&gt;Ant&lt;/b&gt;: 
Random aside... is it perhaps the case that most mocking layers for
xUnits (at least in languages that don&apos;t love closures) make given/when/then
expression harder? It seems that expressing the expectations of mocks
should go in the &quot;then&quot; section, but they usually assume they&apos;ll be set
up before you execute the code under test within the &quot;when&quot; section.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Liz&lt;/b&gt;: 
Check this new toy out: &lt;a href=&quot;http://mockito.googlecode.com/&quot; rel=&quot;nofollow&quot;&gt;Mockito&lt;/a&gt;
My friend Szczepan Faber made it, based on EasyMock. It doesn&apos;t make you set
up any expectations unless you need something to return (eg: given three
fridges in stock). Instead, you get to ask it afterwards whether the
interactions needed happened. No &lt;code&gt;finishedRecording()&lt;/code&gt;, and it&apos;ll automatically
return null, 0 etc. if you haven&apos;t set up a particular stub.
&lt;/p&gt;


&lt;h4&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;
Well, I hope you found that as interesting as I did.I&apos;d love it if the &quot;TDD old guard&quot; (who I&apos;ve quite possibly
misrepresented) could comment below to take the conversation further...
&lt;/p&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/34156.html#comments</comments>
  <category>software_development</category>
  <lj:security>public</lj:security>
  <lj:reply-count>3</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/33958.html</guid>
  <pubDate>Mon, 04 Feb 2008 23:16:51 GMT</pubDate>
  <title>Credits where credits due</title>
  <link>http://anthonybailey.net/blog/2008/02/04/credits-where-credits-due</link>
  <description>(A &lt;a href=&quot;http://worldofmongoose.blogspot.com/2008/02/do-credits-on-tv-matter.html&quot; rel=&quot;nofollow&quot;&gt;piece about TV credits on Mongoose World&lt;/a&gt; caused in turn by &lt;a href=&quot;http://news.bbc.co.uk/1/hi/entertainment/7222679.stm&quot; rel=&quot;nofollow&quot;&gt;this piece from the BBC&lt;/a&gt; provoked a rant from me on that subject and particularly how it relates to machinima. It seems to have broken my writer&apos;s block, so I&apos;ve copied/pasted/edited it here.)&lt;br /&gt;&lt;br /&gt;Full screen credits on plain old broadcast television might still be reasonable, because how else do you get the information? But that medium is increasingly dead. We shall speak of it no more.&lt;br /&gt;&lt;br /&gt;Full screen credits on TV as we increasingly watch it (DVR, DVD, IP) seem anomalous. Pack them into an information burst: if I want to read them, I&apos;ll pause and advance through individual frames. If I&apos;m on a smart device, put the credits in metadata I can browse with that device. If the device is Net-enabled, put them on a page I can navigate to from the program. Don&apos;t make me sit through this stuff. Brand a little if you must, but if I care about obscure details, I&apos;ll seek out the information, and be very happy to read much more than you could cram into the credit footage.&lt;br /&gt;&lt;br /&gt;Full screen credits in typical machinima (and other YouTube-length pieces) are a sign the medium is far too indebted to its older media parents, and is too slavishly following their inappropriate conventions. See above: viewer is almost certainly watching on a Net-enabled device. And a minute of credits on a five minute piece is a real tax on my time!&lt;br /&gt;&lt;br /&gt;Further, there should be two default downloads/streams for episodic machinima:&lt;ul&gt;&lt;li&gt;There should be the new episode for returning viewers (without credits, of course - we already saw them so many times. You can do a &quot;previously&quot; if the plot so demands.)&lt;/li&gt;&lt;li&gt;And there should be everything from the first up to the new episode in a single download/stream for people coming to the story for the first time.&lt;/li&gt;&lt;/ul&gt;These are your two markets - cater to them. The second is particularly ill-served by having to watch umpteen short previous episodes in order to catch-up, where tedious credits/theme song prevent me getting into your wonderful art.&lt;br /&gt;&lt;br /&gt;(Sorry for the explosion of highly subjective opinion. I don&apos;t know why I care so much about it. I remember I tried and failed to convince Hugh to do this kind of thing with Bloodspell.)&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/33958.html#comments</comments>
  <category>machinima</category>
  <lj:security>public</lj:security>
  <lj:reply-count>7</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/33734.html</guid>
  <pubDate>Tue, 23 Oct 2007 23:30:18 GMT</pubDate>
  <title>&apos;Spell is out</title>
  <link>http://anthonybailey.net/blog/2007/10/23/spell-is-out</link>
  <description>&lt;img src=&quot;https://imgprx.livejournal.net/1a7e1dbe0e65fd959cf46e64adbd05b8812bb113/nH31Fc7lEJLodsQSjwa9a98uiNqQi2jtz7MxOp6eg9NM9KfPMQ0m20mAoogkJNwxscKXoWlFZcDYvRVI-O_oiUYxBmCKTfHnyL1m_2-Gb4su7SQuModL0B9yCEGLc5GXLE8tZF2-7le9K8cSWlR__asNDYoZMBmgJRhscS8O37M&quot; alt=&quot;BloodSpell stills&quot; align=&quot;right&quot; style=&quot;margin: 1em;&quot; /&gt;
&lt;p&gt;
Independent film outfit &lt;a href=&quot;http://strangecompany.org&quot; rel=&quot;nofollow&quot;&gt;Strange Company&lt;/a&gt; have released their feature-length &lt;a href=&quot;http://wikipedia.org/wiki/Machinima&quot; rel=&quot;nofollow&quot;&gt;machinima&lt;/a&gt; movie, the &quot;punk fantasy&quot; &lt;a href=&quot;http://bloodspell.com&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;BloodSpell&lt;/cite&gt;&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;
My opinions on the film are necessarily messy. I&apos;m an &lt;a href=&quot;http://anthonybailey.net/blog/2007/09/09/origins-of-the-word-machinima&quot; rel=&quot;nofollow&quot;&gt;advocate&lt;/a&gt; of the medium (machinima is shooting movies within virtual worlds, often using video games), and a friend of the creators - indeed, I worked on one of the tools used to create the film. So I&apos;m unfairly biased. I&apos;m also not a great person to have on your side, because I don&apos;t let such things mellow my criticisms or get me hyped - at best I do faint praise, and damn you.
&lt;/p&gt;&lt;p&gt;
&lt;cite&gt;BloodSpell&lt;/cite&gt; hits a huge range of highs and lows. Almost every aspect - story, performance, cinematography, art, technology/effects, pacing, dialogue - has parts that are truly great, and parts that are pretty poor. (The exception is the audio: sound and soundtrack are good throughout.) A spread of quality is not unusual in a film, but the range is particularly wide here. There are many genius moments and scenes. There are many embarassing ones.
&lt;/p&gt;&lt;p&gt;
The film is strong at start and end, weak in the middle. This is partly due to the order of shooting: Strange Company learned heaps about their machinima technologies and about movie-making as they created the piece; originally released in episodic chunks, they returned to completely redo the opening scene when editing together this version. It&apos;s also partly due to happenstance - the second scene was already strong, whilst the film serves as an archetypal illustration of the cinema textbook tendency to have the story sag in the middle.
&lt;/p&gt;&lt;p&gt;
This is by a fair way the best machinima feature film I&apos;ve seen. The dated technology is necessarily distracting, but didn&apos;t spoil my enjoyment. Whilst previous machinima movies have excited me about the future potential of the medium, this one is real, now. It simply works as a decent movie in it&apos;s own right - I&apos;d watch it through if it came on TV the right midweek evening, probably whilst bestowing it the odd sarcastic aside because, you know, it&apos;s lucky to be on the channel I&apos;m indulging.
&lt;/p&gt;&lt;p&gt;
It&apos;s also probably the best budget independent film of its genre (epic action fantasy drama with nods to comedy and contemporary culture - the one word summary is &quot;Buffy&quot;.) This is almost by definition: you simply can&apos;t shoot real film (or TV) of this flavor for the few thousand pounds it took to make &lt;cite&gt;BloodSpell&lt;/cite&gt;. (Also this genre of film is not blessed with many success stories. This one can only have helped.)
&lt;/p&gt;&lt;p&gt;
The film was made by volunteers, is &lt;a href=&quot;http://bloodspell.com/commons&quot; rel=&quot;nofollow&quot;&gt;licensed&lt;/a&gt; under a &lt;a href=&quot;http://creativecommons.org/licenses/by-nc-sa/2.5/&quot; rel=&quot;nofollow&quot;&gt;BY-NC&lt;/a&gt; Creative Commons licence, and you can &lt;a href=&quot;http://www.bloodspell.com/film/list/&quot; rel=&quot;nofollow&quot;&gt;download or stream it&lt;/a&gt; for free. I&apos;d even encourage fans of the genre to do so if it didn&apos;t contradict my disclaimer at the start!
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;&lt;/p&gt;</description>
  <comments>https://anthonybailey.livejournal.com/33734.html#comments</comments>
  <category>machinima</category>
  <lj:security>public</lj:security>
  <lj:reply-count>2</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/33442.html</guid>
  <pubDate>Sun, 30 Sep 2007 21:27:20 GMT</pubDate>
  <title>Digital Privacy Management is inEFFable</title>
  <link>http://anthonybailey.net/blog/2007/09/30/digital-privacy-management-is-ineffable</link>
  <description>&lt;p&gt;

It&apos;s increasingly convenient to manage personal data up in the cloud. Eben Moglen &lt;a href=&quot;http://itc.conversationsnetwork.org/shows/detail1897.html&quot; rel=&quot;nofollow&quot;&gt;worries&lt;/a&gt; that people entrust important data to organisations without thinking of the downside. Drawing an analogy with open source in software, he encourages people to store data themselves rather than pumping it into proprietary information silos.
&lt;/p&gt;

&lt;p&gt;
I am persuaded by the argument as I&apos;ve phrased it above. It&apos;s timely to consider investing in keeping copies of the personal data that is important to you, because otherwise you&apos;re going to lose it when the silo closes. Ideally you would keep &lt;em&gt;the&lt;/em&gt; copy rather than &lt;em&gt;a&lt;/em&gt; copy, - you would manage the canonical resource and publish it. This is because you have the most interest in and ability to ensure the ongoing correctness of the data. Because DIY is hard, third-party service providers will help you; but they should be neutral hosts rather than aggregators motivated by their own uses for the information.
&lt;/p&gt;

&lt;p&gt;
Actually Moglen seems to be making the stronger argument that you should hold the data because you need to be able to &lt;em&gt;control&lt;/em&gt; it, not just &lt;em&gt;publish&lt;/em&gt; it. Commercial entities will enter into contracts with you about what use they are allowed to make of this data that you own and are generously granting them access to. His argument is phrased in terms of privacy - your right to control the use of digital data about you. Maybe you&apos;ll even sell access and usage rights.
&lt;/p&gt;

&lt;p&gt;
And this is where I differ from him and a whole bunch of organizations with whom usually I find myself in agreement. Trading overzealous stereotyping for a reduced risk of misquoting, I will pick the &lt;a href=&quot;http://www.eff.org/&quot; rel=&quot;nofollow&quot;&gt;Electronic Frontier Foundation&lt;/a&gt; as a specific example of what I find to be a widespread and questionable position. I find their stance on issues of &lt;a href=&quot;http://www.eff.org/Privacy/&quot; rel=&quot;nofollow&quot;&gt;privacy&lt;/a&gt; to be very much at odds with the pragmatic approach they take to, say, &lt;a href=&quot;http://www.eff.org/IP/fairuse/&quot; rel=&quot;nofollow&quot;&gt;DRM&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
On the latter, essentially they say: trying to control how digital information is copied and used doesn&apos;t work very well. The technologies are too easy to break, and they prevent unintended new uses of the content, restricting freedoms and stifling innovation. Therefore we should avoid purely technical solutions, and retire historic business models that now rely on them. Instead play nice with the world as it is, and try to nudge it in the directions you desire.
&lt;/p&gt;

&lt;p&gt;
That all sounds right to me. So how on Earth will we be able to use any kind of Digital Privacy Management mechanism to control how &lt;em&gt;personal&lt;/em&gt; information is copied and used? Bits are bits, and once you publish them you just don&apos;t get to control their copying and use. The hazily envisaged DPM is DRM, only without a law-buying cartel behind it. It&apos;s not going to work. Move on, and start discussing and tackling the problems that can arise in a space where there are plausible solutions, please.
&lt;/p&gt;

&lt;p&gt;
(You&apos;ll also find the open source analogies work better once technical controls are abandonned, I believe.)
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;
&lt;/p&gt;</description>
  <comments>https://anthonybailey.livejournal.com/33442.html#comments</comments>
  <category>copyfighting</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/33236.html</guid>
  <pubDate>Sun, 09 Sep 2007 17:58:52 GMT</pubDate>
  <title>Origins of the word &quot;machinima&quot;</title>
  <link>http://anthonybailey.net/blog/2007/09/09/origins-of-the-word-machinima</link>
  <description>
&lt;p&gt;
Machinima was spelled slightly differently when first-born. The

first use of the term, as &quot;machinema&quot;, appeared in an e-mail I sent
on the &apos;&lt;code&gt;q2demos&lt;/code&gt;&apos; mailing list on 5 Jan 1998.
Here is the quote from the mail in question. Conveniently, it happened to
go on to explain the need to coin the term.
&lt;/p&gt;

&lt;blockquote&gt;&lt;strong&gt;Anthony:&lt;/strong&gt;&lt;pre&gt;
I think with a new tool-set and a greater awareness of the skills
required to make a good piece of machinema[*] we can expect to see
some truly adventurous stuff being made. Fine and fun as they can be,
slapstick and B-movie action horror are just the start of what *could*
be done with this new medium. If I was a film student with some
technical savvie, I&apos;d be beginning to look at using this stuff as an
alternative to or prototype for an expensive real-world production.

[*]Machinema... yes, sorry, it&apos;s a bit of a contrived term... but what
in general *are* we going to call these pieces of cinema that are made
using 3D engines? Not only is &quot;Quake movie&quot; an ugly and confusing
term, it&apos;s also fast going to become outdated as other technologies
become relevant. (c: Any ideas?
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;

I chose &quot;machinema&quot; to rhyme with cinema. I used &quot;machine&quot; as a base

only because I didn&apos;t find an easy pun with &quot;engine&quot; in it. I spelled

it with the &apos;e&apos; because it made it look a bit like cinema. I don&apos;t

believe it to be the best neologism in the world, and I apologize for

that - I didn&apos;t know the term was going to get widespread.

&lt;/p&gt;

&lt;p&gt;

The word began to be used fairly regularly on the mailing list

and gradually in other related fora, but that was about
 all.
So far as I know, it&apos;s first &quot;public&quot; appearance is in a review

I wrote for GameSpy Industry&apos;s Quake portal site PlanetQuake.com,

first published on 02 Apr 1999. (&lt;a href=&quot;http://web.archive.org/web/20000104160349/http://planetquake.com/reviews/nightfall.shtm&quot; rel=&quot;nofollow&quot;&gt;Slightly broken copy of now dead page courtesy of the
Internet Archive&lt;/a&gt;)
&lt;/p&gt;

&lt;p&gt;
Hugh Hancock of Strange Company wrote up some &quot;machinima&quot; techniques on 10 Jun
1999. We were already in e-mail contact so we discussed the new spelling.
&lt;/p&gt;

&lt;blockquote&gt;&lt;strong&gt;Anthony:&lt;/strong&gt;&lt;pre&gt;
&amp;lt;pedantry&amp;gt;
I&apos;m very happy that you&apos;ve adopted my silly whimiscal term for cinema
generated by desktop machines, but is there any reason that you have
changed the spelling? The &apos;e&apos;s in both &quot;cinema&quot; and &quot;machine&quot; seem to
suggest the natural spelling for the mangled combination is
&quot;machinema.&quot; It&apos;s a pun rather than a derivation, so I don&apos;t see any
linguistic pressure to follow the path of e.g. &quot;machinist.&quot;
&amp;lt;/pedantry&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;blockquote&gt;&lt;strong&gt;Hugh:&lt;/strong&gt;&lt;pre&gt;
As a linguist I&apos;d prefer to use the &quot;ima&quot;, a more common suffix than &quot;ema&quot;,
and go with the normal derivation, but to be perfectly honest the main
reason we&apos;ve changed the spelling is I forgot how you originally spelled it
and &quot;ima&quot; looked more natural! Sorry...
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;blockquote&gt;&lt;strong&gt;Anthony:&lt;/strong&gt;&lt;pre&gt;
I didn&apos;t like &quot;machinima&quot; at first because it seemed to lose the
&quot;cinema&quot; pun, at least at the lexical level. But it&apos;s still there
phonically, and now I realise there is a genuine derivation from
&quot;anima&quot; going on as well, so the new spelling actually maybe combines
something plausible and word-play. Anyway, in the interests of
uniformity I&apos;ll adopt your spelling.
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;
&lt;a href=&quot;http://machinimafordummies.com/pages/machiniwhatnow&quot; rel=&quot;nofollow&quot;&gt;Hugh tells the machinima
etymology story&lt;/a&gt; from his side in a far more self-deprecating and entertaining style 
within the book
&lt;a href=&quot;http://machinimafordummies.com/&quot; rel=&quot;nofollow&quot;&gt;&lt;cite&gt;Machinima for Dummies&lt;/cite&gt;&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
The term crossed the chasm for certain when hub-site machinima.com was
launched at the start of 2000.
&lt;/p&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/33236.html#comments</comments>
  <category>machinima</category>
  <lj:security>public</lj:security>
  <lj:reply-count>3</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/32869.html</guid>
  <pubDate>Sun, 19 Aug 2007 18:07:58 GMT</pubDate>
  <title>Blipvert</title>
  <link>http://anthonybailey.net/blog/2007/08/19/blipvert</link>
  <description>&lt;p&gt;
I&apos;m wondering why there isn&apos;t more machinima on &lt;a href=&quot;http://blip.tv/&quot; rel=&quot;nofollow&quot;&gt;blip.tv&lt;/a&gt;. There is &lt;a href=&quot;http://www.blip.tv/posts/?topic_name=machinima&quot; rel=&quot;nofollow&quot;&gt;some&lt;/a&gt;, but this video publishing service seems like such a good fit with the needs of machers I would have expected more.
&lt;/p&gt;


&lt;p&gt;
I became aware of blip through &lt;a href=&quot;http://www.itconversations.com/shows/detail1895.html&quot; rel=&quot;nofollow&quot;&gt;this recent interview with co-founder Mike Hudack&lt;/a&gt; by Jon Udell. (Good podcast - says some interesting things in general about web service businesses.) 
&lt;/p&gt;

&lt;p&gt;
The company seems to really get what a user-gen content aggregator and publisher needs to do to succeed by pleasing their users. You can read their own &lt;a href=&quot;http://blip.tv/about/http://blip.tv/about/&quot; rel=&quot;nofollow&quot;&gt;overview&lt;/a&gt;, but items from the interview that impressed me included&lt;ul&gt;
&lt;li&gt;a strong distaste for service lock-in (for example, they will automatically mirror your upload to the Internet Archive if you want),&lt;/li&gt;
&lt;li&gt;being very open to working with other distributors and publishers (for example, building a system to share tags and download stats),&lt;/li&gt;
&lt;li&gt;staying in the background to let creators control branding (for example, they don&apos;t embed their logo),&lt;/li&gt;
&lt;li&gt;sensible advertising options (you can use their advertising and share the profits, or do your own, or none),&lt;/li&gt;
&lt;li&gt;providing a strong free service with professional upgrade.&lt;/li&gt;
&lt;/ul&gt;
The whole thing sounds like the right business model: provide a service which offers sustainable long-term value that supports creators.
&lt;/p&gt;

&lt;p&gt;
The disclaimer: I&apos;ve not used the service. (Anyone who has care to comment?)
&lt;/p&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/32869.html#comments</comments>
  <category>machinima</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/32763.html</guid>
  <pubDate>Thu, 19 Jul 2007 00:46:32 GMT</pubDate>
  <title>Regression Therapy - Contentful Testing</title>
  <link>http://anthonybailey.net/blog/2007/07/19/regression-therapy-contentful-testing</link>
  <description>
&lt;h1&gt;Regression Therapy - Contentful Testing&lt;/h1&gt;
&lt;img style=&quot;float: right; margin: 1.5em; margin-top: 0&quot; alt=&quot;Contentful bear&quot; src=&quot;https://imgprx.livejournal.net/0aea737ec2f4cb5cd600b9333773d709935d3cd7/nH31Fc7lEJLodsQSjwa9a5t2mSc9jMgM6AgoKQWgzmydUF_kThfccfQooDeKjJbYf5HVuo-j3vghII1Ihrm5uw&quot; /&gt;
&lt;p&gt;
This article is a fleshing out of a ten-slides-in-ten-minutes talk that
&lt;a href=&quot;http://anthonybailey.tumblr.com/post/5687247&quot; rel=&quot;nofollow&quot;&gt;I originally gave in July 2007&lt;/a&gt; 
at &lt;a href=&quot;http://www.amazondc.com/&quot; rel=&quot;nofollow&quot;&gt;work&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;
Since then I talked on the same subject at the Scotland on Rails 2008 conference. &lt;a href=&quot;http://anthonybailey.net/tumblelog/2008/04/08/contentful-slides-from-my-talk-at-scotland-on-etc&quot; rel=&quot;nofollow&quot;&gt;Slides and so forth are available.&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;1. Introduction&lt;/h2&gt;
&lt;p&gt;
Regression testing is usually seen as the poorer cousin of &quot;proper&quot; domain-abstracted assertion-based testing.
Often rightly so!
&lt;/p&gt;&lt;p&gt;
However, with the right support in place, I have found that this form of testing can work very well in certain contexts.
&lt;/p&gt;&lt;p&gt;
This article addresses one such context: testing the view content generated by a web app.
I discuss the background,
then present a concrete example in the form of a plug-in for &lt;a href=&quot;http://rubyonrails.org/&quot; rel=&quot;nofollow&quot;&gt;Rails&lt;/a&gt;.
&lt;/p&gt;

&lt;hr /&gt;

&lt;h2&gt;2. Three reasons to test&lt;/h2&gt;
&lt;p&gt;
For the purpose of this discussion, I identify three overlapping but distinguishable uses of tests in software development.
&lt;/p&gt;

&lt;h3&gt;To preserve existing good behaviour&lt;/h3&gt;
&lt;p&gt;
Tests can be used to maintain known good behaviour, preventing accidental bad changes (also known as &quot;regressions&quot;.)

The tests provide a safety net during refactorings, and enfore a Hippocratic  &quot;first, do no harm&quot; oath during other work.
&lt;/p&gt;&lt;span style=&quot;background: #eee; font-size: 120%; font-weight: bold; color: green&quot;&gt;
....................................&lt;font color=&quot;red&quot;&gt;!&lt;/font&gt;..&lt;font color=&quot;red&quot;&gt;!&lt;/font&gt;...........................&lt;font color=&quot;red&quot;&gt;!&lt;/font&gt;...........
&lt;/span&gt;&lt;p&gt;
The test stays green whilst all is well. A red bar tells us that we&apos;ve messed up and broken something.
&lt;/p&gt;

&lt;h3&gt;To drive intended changes&lt;/h3&gt;
&lt;p&gt;
Tests can be used to change (often, to add) behaviour, providing context to an intended good change.

The archetypal example is classic &lt;abbrev title=&quot;Test-driven development&quot;&gt;TDD&lt;/abbrev&gt;,
creating tests first in order to define the problem,
and to guide the design and implementation of a solution.
&lt;/p&gt;&lt;span style=&quot;background: #eee; font-size: 120%; font-weight: bold; color: green&quot;&gt;
&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;&lt;font color=&quot;red&quot;&gt;&amp;gt;&lt;/font&gt;&amp;gt;
&lt;/span&gt;&lt;p&gt;
New tests flash red and are put back to green by introducing production code.
&lt;/p&gt;

&lt;h3&gt;To understand emergent change&lt;/h3&gt;
&lt;p&gt;
A less often discussed use of testing is to explore and validate emergent behaviour.
&lt;/p&gt;&lt;p&gt;
In a complex system it can be hard to prejudge or predict every knock-on effect
of a deliberate change to one part of that system.
Tests can provide a context for understanding and controlling such changes and consequences.
&lt;/p&gt;&lt;span style=&quot;background: #eee; font-size: 120%; font-weight: bold; color: green&quot;&gt;
.....&lt;font color=&quot;red&quot;&gt;!!??&lt;small&gt;?&lt;small&gt;?&lt;small&gt;?&lt;small&gt;?&lt;/small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/font&gt;...................&lt;font color=&quot;red&quot;&gt;!!??&lt;small&gt;?&lt;small&gt;?&lt;small&gt;?&lt;small&gt;?&lt;/small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/font&gt;............&lt;font color=&quot;red&quot;&gt;!!??&lt;small&gt;?&lt;small&gt;?&lt;small&gt;?&lt;small&gt;?&lt;/small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/font&gt;..............
&lt;/span&gt;&lt;p&gt;

In this way of working, changes cause flashes of red that are observed
and then often approved,
updating expectations to recolor things back to green again.
&lt;/p&gt;

&lt;hr /&gt;

&lt;h2&gt;3. Three ways to test&lt;/h2&gt;
&lt;p&gt;
Next I&apos;ll categorize three methods of testing,
paying particular attention to their use in the context of testing view content.
&lt;/p&gt;

&lt;h3&gt;Live testing&lt;/h3&gt;
&lt;p&gt;
In a scandalously unrepeatable manner that sacrifices reliable coverage, we can test by hand and verify by eye.
&lt;/p&gt;&lt;p&gt;
Drive the web app through the browser and see if looks right.
We all do this.
It shouldn&apos;t be sniffed at; it is genuinely useful because it is so cheap.
However, once the system gets sufficiently complex, it doesn&apos;t hold
&lt;abbrev title=&quot;Does WATIR hold it? Perhaps! I&amp;amp;apos;m not the right person to ask.&quot;&gt;water&lt;/abbrev&gt;.
I won&apos;t consider manual testing further in this article.
&lt;/p&gt;

&lt;p style=&quot;margin-top: 2em&quot;&gt;
To automate testing, we have to be able to provoke the generation of view content that we can then test.
Assuming a good web app framework that allows us to do this (no small thing, but not the topic of interest today),
there are then two means of testing the content.
&lt;/p&gt;

&lt;h3&gt;Assertion testing&lt;/h3&gt;
&lt;p&gt;
We can explcitly check individual desired properties of the the resulting content.
&lt;/p&gt;

&lt;h3&gt;Regression testing&lt;/h3&gt;
&lt;p&gt;
Or, we can compare the content in its entirety against a previously validated known good copy.
&lt;/p&gt;

&lt;p style=&quot;margin-top: 2em&quot;&gt;
I&apos;ll now discuss in greater detail the relative merits of testing view content through assertion and regression.
&lt;/p&gt;
 
&lt;hr /&gt;

&lt;h2&gt;4. &lt;code style=&quot;font-size: 120%&quot;&gt;assert_equals(expected, test_method)&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;
Assertion tests are prevalent in contemporary developer testing, with good reason.
They tend to be very effective, given sufficient investment &amp;ndash;
we need to express the properties that care about succinctly,
and at an appropriate level of abstraction within the domain.
&lt;/p&gt;&lt;p&gt;
The Rails web framework has evolved a best-of-breed solution for assertion testing view content
in the form of &lt;code&gt;assert_select&lt;/code&gt;.
It uses CSS selectors to locate content, and neatly expresses the conditions it should satisfy.
Here&apos;s a simple example:
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: #0dd; color: black&quot;&gt;&lt;pre&gt;
class CartExampleTest
  def test_total
    get &quot;/store/add_to_cart&quot;, :id =&amp;gt; rails_book.id
    &lt;span style=&quot;background: #cff; font-weight: bold&quot;&gt;assert_select &quot;div#cart tr.total td:last-of-type&quot;, &quot;$39.95&quot;&lt;/span&gt;
  end
end
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;
This is pretty nice.
But it doesn&apos;t escape some downsides of assertion testing
which happen to be particularly troublesome for view content.
&lt;/p&gt;

&lt;h3&gt;Coverage is selective&lt;/h3&gt;
&lt;p&gt;
We can only capture the behaviors that we think to test for.
The importance of many properties of view content are not obvious until we&apos;ve accidentally changed them.
&lt;/p&gt;

&lt;h3&gt;Exploration is expensive&lt;/h3&gt;
&lt;p&gt;
Assertion tests are generally great for catching regressions and for driving changes.
But they are poor for my third type of test use, that of exploring change.
The developer has to run around rebalancing the books,
fixing up test expectations to agree with the unexpected consequences of a change.
&lt;/p&gt;

&lt;h3&gt;Explicitness is verbose&lt;/h3&gt;
&lt;p&gt;
Many aspects of the view are worth caring about.
It takes too much code to express them all explicitly;
translation, even into a well-designed and succinct language, still takes time.
The most concise summary of all the properties of a piece of content is the content itself&amp;hellip;
&lt;/p&gt;

&lt;hr /&gt;

&lt;h2&gt;5. Regression (past life)&lt;/h2&gt;
&lt;p&gt;
&amp;hellip;which leads us to our next alternative.
&lt;/p&gt;&lt;p&gt;
Regression tests work by checking current content against expected content.
We test by comparing the entirety of what we generate against some previously approved copy.
The expected content might be quoted verbatim in the test; more often it is stored in a file.
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: #0dd; color: black&quot;&gt;&lt;pre&gt;
class CartExampleTest
  def test_total
    get &quot;/store/add_to_cart&quot;, :id =&amp;gt; rails_book.id
    &lt;span style=&quot;background: #cff; font-weight: bold&quot;&gt;assert_equals File.new(&apos;expected.html&apos;).read, @response&lt;/span&gt;
  end
end
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;
This is clearly very cheap to express, and capturing existent good behaviour needs no translation: just a copy and paste of the current results.
&lt;/p&gt;&lt;p style=&quot;margin-top: 2em&quot;&gt;
But like assertion testing, regression testing view content comes with some downsides.
&lt;/p&gt;

&lt;h3&gt;Tests don&apos;t come first&lt;/h3&gt;
&lt;p&gt;
Again this form of testing is good for two of the three uses of testing that I identified.
It is ideal for exploring changes,
and unsurprisingly it catches regressions.
But, it is very awkward to drive new behavior.
&lt;/p&gt;&lt;p&gt;
However, this problem is not serious in the context of view content.
Although it would not be plausible to test-drive the generation of content through regression testing,
it is not clear that one would ever want to.
View content tends to come into existence in a concrete form,
designed or composed in toto
rather than being built up one abstract essence at a time.
Even for those who usually love to test first, test-last of view content does not seem so detestable.
&lt;/p&gt;&lt;p style=&quot;margin-top: 2em&quot;&gt;
The main problem with regression testing is that it is very expensive if we act naively in response to diffs.
There are two common pain points.
&lt;/p&gt;
 
&lt;h3&gt;Tests are brittle and fragile&lt;/h3&gt;
&lt;p&gt;
Comparing against a complete text copy means that we see every change, even ones we don&apos;t actually care about.
Every difference needs explicit attention.
&lt;/p&gt;

&lt;h3&gt;Tests are usually noisy&lt;/h3&gt;
&lt;p&gt;
Because there is no abstraction, one change may break many tests.
Similar differences need attention in multiple places.
&lt;/p&gt;&lt;p&gt;
These workflow costs multiply as the system under regression test grows.
Investing in the abstraction of assertion tests is usually preferrable.
Even in the domain of view content, regression tests will prove too costly if we do not work to make them less so.
&lt;/p&gt;

&lt;hr /&gt;

&lt;h2&gt;6. &lt;strike&gt;Regression&lt;/strike&gt; Contentful testing&lt;/h2&gt;
&lt;p&gt;
So: let&apos;s attempt to address the problems, and turn regression testing into contentful testing.
&lt;/p&gt;

&lt;h3&gt;Lessen the noise&lt;/h3&gt;
&lt;p&gt;
Information can be defined as any difference that makes a difference.
The diffs that don&apos;t are the noise in regression tests that we want to reduce.
&lt;/p&gt;&lt;dl&gt;
&lt;dt&gt;Ignore insignificant change&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;
Some textual changes in HTML source
(for example, certain whitespace in content;
and formatting, quoting, capitalization and attribute order within the mark-up itself)
won&apos;t affect how the content is displayed.
&lt;/p&gt;&lt;p&gt;
These can be ignored by allowing a little abstraction back in.
We can still use standard text-based diff tools,
but to compare unique text representations of &lt;abbrev title=&quot;Document Object Model&quot;&gt;DOM&lt;/abbrev&gt;-normalized content.
&lt;/p&gt;&lt;/dd&gt;
&lt;dt&gt;&lt;abbrev title=&quot;Don&amp;amp;apos;t repeat yourself&quot;&gt;DRY&lt;/abbrev&gt; up which content is tested&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;
Rather than see the same diff to the same repeated content over and over,
we can focus regression tests on those parts of content that vary across our testcases.
&lt;/p&gt;&lt;/dd&gt;
&lt;/dl&gt;

&lt;h3&gt;Smooth the workflow&lt;/h3&gt;
&lt;p&gt;
In good automation fashion, we will make the common tasks in the workflow as cheap and as easy as we can.
&lt;/p&gt;&lt;p&gt;
It has to be simple
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;to create a new regression test,&lt;/li&gt;
&lt;li&gt;to inspect diffs from the expected content when changes occur, and&lt;/li&gt;
&lt;li&gt;to accept the changes once they have been checked over and seen to be OK.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
And, this needs to work well in batch.
We should be able to detect, review and accept changes in many tests at a time when need be.
&lt;/p&gt;

&lt;h3&gt;The Contentful Rails plug-in&lt;/h3&gt;
&lt;p&gt;
I put together a plug-in that tries to do these things within Rails.
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: black; color: cyan&quot;&gt;&lt;pre&gt;
% script/plugin install svn://rubyforge.org/var/svn/contentful
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;
The plug-in was evolved in, then extracted from, a small spare-time web application.
I&apos;ve since re-used it successfully in other Rails projects.
If you write Rails applications, you can read more and download the plug-in at the
&lt;a href=&quot;http://contentful.rubyforge.org/&quot; rel=&quot;nofollow&quot;&gt;Contentful website&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;
For this discussion, Contentful is simply a single concrete example
of a general approach I believe should translate across language boundaries,
or from my Rake automation commands into your favorite &lt;abbrev title=&quot;Interactive development environement&quot;&gt;IDE&lt;/abbrev&gt;.
&lt;/p&gt;

&lt;hr /&gt;

&lt;h2&gt;7. Capturing content to create tests&lt;/h2&gt;
&lt;p&gt;
With Contentful plugged-in, we can check the content generated in a test by saying &lt;code&gt;assert contentful&lt;/code&gt;.
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: #0dd; color: black&quot;&gt;&lt;pre&gt;
class CartExampleTest
  def test_total
    get &quot;/store/add_to_cart&quot;, :id =&amp;gt; rails_book.id
    &lt;span style=&quot;background: #cff; font-weight: bold&quot;&gt;assert_contentful&lt;/span&gt;
  end
end
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;
Then when we run the test for the first time, the test passes
- and it generates the expected content from the current content, as a side effect.
In accord with Rails&apos; culture of convention over configuration,
we locate the expected content in a standard place,
derived from the name of the test.
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: black; color: cyan&quot;&gt;&lt;pre&gt;
% rake test
Started
...................................!...............
Finished in 3.487022 seconds.

  1) Contentful Notification:
test_total(CartExampleTest):
Generated /depot/&lt;span style=&quot;color: #cff; font-weight: bold&quot;&gt;test/contentful/cart_example/total/expected.html&lt;/span&gt;
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;
To avoid duplication, we can focus on a particular subset of the content using a &lt;abbrev title=&quot;Cascading Style Sheet&quot;&gt;CSS&lt;/abbrev&gt; selector. This allows us to ignore components that are common across all our views, such as navigation sidebars and the like.
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: #0dd; color: black&quot;&gt;&lt;pre&gt;
class CartExampleTest
  def test_total
    get &quot;/store/add_to_cart&quot;, :id =&amp;gt; rails_book.id
    &lt;span style=&quot;background: #cff; font-weight: bold&quot;&gt;select_contentful &quot;div#cart&quot;&lt;/span&gt;
  end
end
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: black; color: cyan&quot;&gt;&lt;pre&gt;
% rake test
Started
...................................!...............
Finished in 3.494442 seconds.

  1) Contentful Notification:
test_total(CartExampleTest):
Generated /depot/test/contentful/cart_example/total/&lt;span style=&quot;color: #cff; font-weight: bold&quot;&gt;div#cart.&lt;/span&gt;expected.html
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h2&gt;8. Detecting changes and inspecting diffs&lt;/h2&gt;
&lt;p&gt;
Now our tests are up, we should set them running.
(Running everything is the norm,
but Contentful will build and execute a suite containing only its own tests if asked.
I&apos;ll show that here.)
&lt;/p&gt;&lt;p&gt;
Here&apos;s what happens when we&apos;ve broken something:
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: black; color: cyan&quot;&gt;&lt;pre&gt;
% rake test:content
Testing expectations in test/contentful
Started
..F.....
Finished in 0.808864 seconds.

  1) Failure:
test_total(CartExampleTest)
&lt;span style=&quot;color: #cff; font-weight: bold&quot;&gt;diff test/contentful/cart_example/total/*.to_diff&lt;/span&gt;
to see the content change
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;
The failing test will have written a temporary &lt;code&gt;changed.html&lt;/code&gt; file next to &lt;code&gt;expected.html&lt;/code&gt;.
Additionally it generates a second pair of files
(&lt;code&gt;expected.to_diff&lt;/code&gt; and &lt;code&gt;changed.to_diff&lt;/code&gt;)
which are the same HTML DOMs,
but with some added line-breaks and other normalization to make them usefully comparable using a standard text diff.
&lt;p&gt;&lt;/p&gt;
(Whenever a test passes, the stale three files get cleaned away.)
&lt;/p&gt;&lt;p&gt;
As well as using the suggested command-line to examine an individual failure,
we can inspect all current diffs by running a single command.
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: black; color: cyan&quot;&gt;&lt;pre&gt;
% rake test:diff
Finding changes in test/contentful
! Diff in cart_example/total/changed.html
91c91
&amp;lt; &amp;lt;td id=&quot;total&quot;&amp;gt;
&amp;lt; Total
---
&amp;gt; &amp;lt;td id=&quot;total&quot; class=&quot;grand&quot;&amp;gt;
&amp;gt; Grand Total
! Diff in another_example/something_else/changed.html
&lt;var&gt;[etc...]&lt;/var&gt;
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;
(Additionally, if we want to focus on a subset of all the current changes,
we can do so by running within a subdirectory of &lt;code&gt;test/contentful&lt;/code&gt;.)
&lt;/p&gt;

&lt;hr /&gt;

&lt;h2&gt;9. Accepting change&lt;/h2&gt;
&lt;p&gt;
If a set of changes are good,
then often we can tell this by casting an eye over the diffs and observing a plausible pattern.
&lt;/p&gt;&lt;p&gt;
(Sometimes one can grep the diffs for extra certainty.
For bonus points, script anything you find yourself doing by hand three times!)
&lt;/p&gt;&lt;p&gt;
If all looks good, we want to accept a bunch of changes.
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: black; color: cyan&quot;&gt;&lt;pre&gt;
% rake test:accept
Finding changes in test/contentful/cart_example
! Accepting cart_example/total/changed.html
! Accepting another_example/something_else/changed.html
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;
That was a bit better than opening up an editor and copying and pasting the content, right?
&lt;/p&gt;&lt;p&gt;
(Again we can refine our acceptance to a subset of changes by running within a subdirectory.)
&lt;/p&gt;&lt;p&gt;
Also, since expected content is generated when absent,
we can alternatively use the file system to our advantage,
and update expectations by removing particular subdirectories and then re-running tests.
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: black; color: cyan&quot;&gt;&lt;pre&gt;
% rm test/contentful/further/specific/*
&lt;var&gt;[etc...]&lt;/var&gt;
Generated /depot/test/contentful/further/specific/expected.html
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h2&gt;10. Making a vice out of a virtue&lt;/h2&gt;
&lt;p&gt;
Personally, I really like my content tests to be a permanent part of the test suite.
Once the workflow is smooth, I find them well worth their maintenence cost.
I like the total coverage; they allow serendipidous discovery of changes I didn&apos;t consider.
&lt;/p&gt;&lt;p&gt;
However, even if you won&apos;t buy the entire bridge that I&apos;m trying to sell you, perhaps I can interest you in a strut:
use the virtues of contentful testing as a &lt;a href=&quot;http://www.artima.com/weblogs/viewpost.jsp?thread=171323&quot; rel=&quot;nofollow&quot;&gt;vice&lt;/a&gt;.
(Sorry for the UK spelling. Translate it into the US &quot;vise&quot; if you like, but you&apos;ll spoil my pun.)
&lt;/p&gt;&lt;p&gt;
Suppose we want to perform a pervasive refactoring. For example,
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;to &lt;a href=&quot;http://anthonybailey.livejournal.com/29792.html&quot; rel=&quot;nofollow&quot;&gt;change&lt;/a&gt; the templating framework we&apos;re using, or&lt;/li&gt;
&lt;li&gt;to factor out a set of view helpers and partials.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
Big changes are risky.
It would be nice to temporarily pin everything about current content tightly down in place whilst we work.
When using Contentful, then we can add a bonus content assertion to every existing functional and integration test
by setting a single Rails config flag in &lt;code&gt;environment.rb&lt;/code&gt;:
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: #0dd; color: black&quot;&gt;&lt;pre&gt;
CONTENTFUL_AUTO = true
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;
Running tests once generates expectations and locks down all the current content.
Then we can perform our refactoring under their full protection.
When done, we unset the config flag and delete the temporary expectations before checking in the safely refactored code.
&lt;/p&gt;&lt;blockquote style=&quot;font-family: monospace; font-size: 120%; padding: 1em; background: black; color: cyan&quot;&gt;&lt;pre&gt;
% wget &lt;a style=&quot;color: cyan&quot; href=&quot;http://contentful.rubyforge.org/&quot; rel=&quot;nofollow&quot;&gt;http://contentful.rubyforge.org/&lt;/a&gt;
&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;
Thanks for reading! Comments are most welcome.
&lt;/p&gt;

&lt;hr /&gt;</description>
  <comments>https://anthonybailey.livejournal.com/32763.html#comments</comments>
  <category>software_development</category>
  <category>rails</category>
  <lj:mood>content</lj:mood>
  <lj:security>public</lj:security>
  <lj:reply-count>7</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/32421.html</guid>
  <pubDate>Mon, 04 Jun 2007 18:14:04 GMT</pubDate>
  <title>The views expressed here...</title>
  <link>http://anthonybailey.net/blog/2007/06/04/the-views-expressed-here-etc</link>
  <description>Something I forgot to do on &lt;a href=&quot;http://anthonybailey.livejournal.com/26347.html&quot; rel=&quot;nofollow&quot;&gt;joining my current employer&lt;/a&gt;...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The views I express here on my blog do not necessarily reflect the views of Amazon.com.&lt;/b&gt;&lt;br /&gt;</description>
  <comments>https://anthonybailey.livejournal.com/32421.html#comments</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>1</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://anthonybailey.livejournal.com/31984.html</guid>
  <pubDate>Fri, 25 May 2007 21:48:37 GMT</pubDate>
  <title>A Feedsum Engine</title>
  <link>http://anthonybailey.net/blog/2007/05/25/a-feedsum-engine</link>
  <description>
&lt;p&gt;
A couple of weeks ago I noticed that I was avoiding subscribing to some informative feeds because they were a bit &lt;em&gt;too&lt;/em&gt; informative. I don&apos;t want to see as many as a dozen separate news items across the course of a single day, because it makes too much noise in the feed aggregator and gets in the way of rarer, more valuable entries. (In my case, the aggregator takes the form of &lt;a href=&quot;http://anthonybailey.livejournal.com/friends/&quot; rel=&quot;nofollow&quot;&gt;my LJ Friends page&lt;/a&gt;.)
&lt;/p&gt;

&lt;p&gt;
&lt;img src=&quot;https://imgprx.livejournal.net/7980b12741cf1e64877f5db667026286526e5014/nH31Fc7lEJLodsQSjwa9a_hqN2v98QmwYU6B11fiVcXm25hUWQ14qiXekjE_1cJcisNbYqm9qVHKZIQVM_-7r74RhGmG_gEFyY0LHsRF9Qs&quot; alt=&quot;Feed icon&quot; align=&quot;left&quot; style=&quot;padding: 2em&quot; /&gt;
I realized I wanted the equivalent of a digest e-mail for feeds - a daily summary or similar. This sounded like a job for a web service, so after failing to find any existing solution, I registered &lt;a href=&quot;http://feedsum.com/&quot; rel=&quot;nofollow&quot;&gt;&lt;code&gt;feedsum.com&lt;/code&gt;&lt;/a&gt; and coded up a little Rails app that sucks in a source feed, collates items into daily batches, and generates a derived feed in which each item summarizes all the source items for one day.
&lt;/p&gt;

&lt;p&gt;
At first this was simply a stateless service, but I found that source feeds often dried up very quickly - by the end of the day, the earliest items could already have been pushed out. So now I stash source items in a database whenever the source feed is pulled. I also found that syndicators such as LiveJournal were not sufficiently patient to wait for my app to spin up in clunky development mode, starting up a fresh Ruby before pulling the source and generating a summary - they often timed out before the service was done. So finally I have had to learn how to deploy a proper production Rails app using mongrel proxies and all that. There were some fiddly one-time set-up details, but once up and running Capistrano is pure deploy joy.
&lt;img src=&quot;https://imgprx.livejournal.net/bd6c7f392e04ad7ff8123a2365fd5578078ca37c/nH31Fc7lEJLodsQSjwa9a_hqN2v98QmwYU6B11fiVcXgg-3tr1x3Q8SL6AThNWqV5Z6WYZKX2tFfLkQKXuixPVys2ku2u1OcyrJtkBqqK5c&quot; alt=&quot;Feed icon&quot; align=&quot;right&quot; style=&quot;padding: 2em&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;
Currently I&apos;m using the service to source three LJ syndications: &lt;span  class=&quot;ljuser  i-ljuser  i-ljuser-type-Y     &quot;  data-ljuser=&quot;slashdot_daily&quot; lj:user=&quot;slashdot_daily&quot; &gt;&lt;a href=&quot;https://slashdot-daily.livejournal.com/profile&quot;  target=&quot;_self&quot;  class=&quot;i-ljuser-profile&quot; &gt;&lt;img  class=&quot;i-ljuser-userhead&quot;  src=&quot;https://l-stat.livejournal.net/img/syndicated.png?v=6283?v=228.1&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://slashdot-daily.livejournal.com/&quot; class=&quot;i-ljuser-username&quot;   target=&quot;_self&quot;   &gt;&lt;b&gt;slashdot_daily&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;, &lt;span  class=&quot;ljuser  i-ljuser  i-ljuser-type-Y     &quot;  data-ljuser=&quot;machinifeedaily&quot; lj:user=&quot;machinifeedaily&quot; &gt;&lt;a href=&quot;https://machinifeedaily.livejournal.com/profile&quot;  target=&quot;_self&quot;  class=&quot;i-ljuser-profile&quot; &gt;&lt;img  class=&quot;i-ljuser-userhead&quot;  src=&quot;https://l-stat.livejournal.net/img/syndicated.png?v=6283?v=228.1&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://machinifeedaily.livejournal.com/&quot; class=&quot;i-ljuser-username&quot;   target=&quot;_self&quot;   &gt;&lt;b&gt;machinifeedaily&lt;/b&gt;&lt;/a&gt;&lt;/span&gt; and &lt;span  class=&quot;ljuser  i-ljuser  i-ljuser-type-Y     &quot;  data-ljuser=&quot;arstechnicdaily&quot; lj:user=&quot;arstechnicdaily&quot; &gt;&lt;a href=&quot;https://arstechnicdaily.livejournal.com/profile&quot;  target=&quot;_self&quot;  class=&quot;i-ljuser-profile&quot; &gt;&lt;img  class=&quot;i-ljuser-userhead&quot;  src=&quot;https://l-stat.livejournal.net/img/syndicated.png?v=6283?v=228.1&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://arstechnicdaily.livejournal.com/&quot; class=&quot;i-ljuser-username&quot;   target=&quot;_self&quot;   &gt;&lt;b&gt;arstechnicdaily&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;. The service can probably handle a further light load yet so others (LJ users or any other feed consumer) are welcome to give it a beta test.
It&apos;s easy to use: to get a daily summary of some feed
&lt;blockquote&gt;&lt;strong&gt;&lt;code&gt;http://example.com/path/index.xml&lt;/code&gt;&lt;/strong&gt;&lt;/blockquote&gt;
simply request
&lt;blockquote&gt;&lt;strong&gt;&lt;code&gt;http://feedsum.com/daily/example.com/path/index.xml&lt;/code&gt;&lt;/strong&gt;&lt;/blockquote&gt;
(You can do other neat stuff like &lt;strong&gt;&lt;code&gt;http://feedsum.com/every/8/hours/...&lt;/code&gt;&lt;/strong&gt; and so forth but the daily summaries tend to be the useful ones.)
&lt;/p&gt;

&lt;p&gt;
Do try it out and please tell me if e.g. it completely chokes on any source feeds.
(And to avoid a rush of dupes, could anyone who uses it to register further LJ syndication accounts add a link in a comment below.)
&lt;/p&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>https://anthonybailey.livejournal.com/31984.html#comments</comments>
  <category>software_development</category>
  <lj:security>public</lj:security>
  <lj:reply-count>4</lj:reply-count>
</item>
</channel>
</rss>
