<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>thesecretdogproject</title>
	<atom:link href="http://www.thesecretdogproject.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.thesecretdogproject.com</link>
	<description></description>
	<lastBuildDate>Mon, 12 Dec 2011 19:50:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>The cost of everything, the value of nothing</title>
		<link>http://www.thesecretdogproject.com/2011/12/the-cost-of-everything-the-value-of-nothing/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=the-cost-of-everything-the-value-of-nothing</link>
		<comments>http://www.thesecretdogproject.com/2011/12/the-cost-of-everything-the-value-of-nothing/#comments</comments>
		<pubDate>Mon, 12 Dec 2011 19:50:50 +0000</pubDate>
		<dc:creator>tom</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.thesecretdogproject.com/?p=1012</guid>
		<description><![CDATA[When I was a lad, I used to devour guitar magazines. My favourite articles in these magazines were the gear reviews. I&#8217;d read page after page about guitars, amplifiers and effects pedals that I&#8217;d never be able to afford, weighing &#8230; <a href="http://www.thesecretdogproject.com/2011/12/the-cost-of-everything-the-value-of-nothing/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>When I was a lad, I used to devour guitar magazines.  My favourite articles in these magazines were the gear reviews.  I&#8217;d read page after page about guitars, amplifiers and effects pedals that I&#8217;d never be able to afford, weighing the merits of the kit. It was complete fantasy: my guitar setup in the real world consisted of a Squire Stratocaster and a Peavey practise amp.  But the fantasy was fun all the same.</p>
<p>One of the side-effects of this imaginary shopping was that I got quite a good feel for what instruments cost.  For a time, I would have been able to give you a good benchmark price for pretty much any mainstream guitar or amplifier from 1960 onwards. All this knowledge was entirely theoretical, though.  I didn&#8217;t really have any feeling for the value of any of this gear.  My dad bought this home to me one day when he observed that I was talking like a man who knew the cost of everything, but the value of nothing.</p>
<p>I was reminded of this pithy phrase recently when working on some code with a colleague. We were working on his PC, which for a coder is rather like driving someone elses car: nothing is quite where you expect it.  I wanted to do a bit of editing, and my colleague suggested I use his SlickEdit install.  When I demurred, wanting to use vim instead, he was a little put out.  &#8220;You&#8217;ve 300 quid&#8217;s worth of SlickEdit sat there, and you want to use vim?&#8221;</p>
<p>But I did want to use vim.  The funny thing was that it was actually more effective. We were trying to track down the definition of a function in the codebase.  I minimised vim in the shell using CTRL-z, then ran ctags to generate a database of the code.  Returning to vim, I used vim&#8217;s ctags bindings to quickly navigate to the definition of the function. My colleague missed this, however, and took over from me to open SlickEdit.  &#8220;This is what SlickEdit&#8217;s good at&#8221;, he said, before proceeding to perform exactly the operations I&#8217;d done, but in about twice the time.</p>
<p>We&#8217;ll work at my PC next time.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesecretdogproject.com/2011/12/the-cost-of-everything-the-value-of-nothing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Of build farms and BASH queues</title>
		<link>http://www.thesecretdogproject.com/2011/12/of-build-farms-and-bash-queues/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=of-build-farms-and-bash-queues</link>
		<comments>http://www.thesecretdogproject.com/2011/12/of-build-farms-and-bash-queues/#comments</comments>
		<pubDate>Sun, 11 Dec 2011 22:21:41 +0000</pubDate>
		<dc:creator>tom</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.thesecretdogproject.com/?p=1010</guid>
		<description><![CDATA[I recently wanted to implement a simple build farm for our build servers at work. Currently we have a pool of three machines whose job it is to watch the repository for checkins on various projects, and build each update &#8230; <a href="http://www.thesecretdogproject.com/2011/12/of-build-farms-and-bash-queues/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I recently wanted to implement a simple build farm for our build servers at work. Currently we have a pool of three machines whose job it is to watch the repository for checkins on various projects, and build each update to ensure that the build is still in working order.</p>
<p>Our present implementation has a per-project script which runs on each machine as a cronjob.  This script is responsible for checking the SCM for updates, checking out updated code, running the build, and emailing the results out to the project team. So far, it works well, but it has a number of limitations.  Firstly, a lot of the code for checking the SCM, checking out code, and emailing people is common across the per-project scripts.  While this code doesn&#8217;t change much, it&#8217;s a shame to duplicate it unnecessarily.  Worse than that, however, is that each machine in the pool runs only one project build.  If one project has a busy day, then that machine may be swamped while all the others are idling.  We could get a greater build coverage by sharing the load between all the build machines.</p>
<p>How best to do this?  I decided early on that a master-slave configuration would be easiest to implement and administer.  All the configuration for the builds could live on the build master, while the slaves could be relatively &#8220;dumb&#8221; machines easily added to (or removed from) the pool.  I also decided that the nature of the managing and running the build processes was sequential in nature.  You check the SCM, you check out some code, you run a build, you email people.</p>
<p>Beyond this basic characterisation of the task at hand, I also had some restrictions which limited my implementation choices.  I needed to use a language which would let me implement the build farm, meaning that a scripting language was going to be the best choice.  I also wanted something that could be easily maintained by the whole team.  These two restrictions combined to suggest shell script as the most sensible choice of language.  This wasn&#8217;t such a bad idea: more or less every Linux box has BASH, and it&#8217;s easy to use BASH to leverage other common Linux command line tools.</p>
<p>With these restrictions in mind, I came up with the basic design of the system.  The master machine would be configured via. an ini file which would specify the projects to be built, and the machines in the build pool.  The master would be an event driven system centred around an input queue.  Firstly, a &#8220;scan&#8221; request on the input queue would trigger the master to examine the project SCMs for code changes.  If any were changes were detected, the master would generate a build script for that project (based on shared library code combined with a small piece of project-specific code) and send the script to a job runner machine for processing.  Once the build had completed on the runner machine would generate a &#8220;job complete&#8221; event on the master&#8217;s input queue, which would trigger report emails from the master to the project team.  The inter-machine communications would be managed using ssh and scp.</p>
<p>The tricky bit turned out to be implementing the queues, which are quite an essential element of the system.  The canonical shell IPC mechanism is the named pipe (fifo).  The trouble with fifos, insofar as my design goes,  is that it is necessary to have a process listening on a pipe in order for a blocking write into the pipe to return. Try it for yourself!</p>
<table border="0" bgcolor="#e8e8e8" width="100%" style="margin:0.2em 0;">
<tr>
<td style="padding:0.5em;">
<pre style="margin:0; padding:0;"># Create a fifo, then write some data into it
# This will block until you read from the fifo
tom@gibbon:~$ mkfifo /tmp/myfifo
tom@gibbon:~$ echo "Hello world" &gt; /tmp/myfifo

# Now open a new terminal and read from the fifo
tom@gibbon:~$ cat /tmp/myfifo
Hello world

# Your original echo command will now return in your first terminal</pre>
</td>
</tr>
</table>
<p>This wouldn&#8217;t work too well in my scheme because I was looking to push events around the system using ssh.  If the job runner wanted to report the results of a build to the master and had to wait around until the master was ready to read the result, that wouldn&#8217;t be ideal.</p>
<p>If fifos were out, then, perhaps a regular file would do.  If the queue was a plain old file, it would be easy enough to append data to the end of the file, and also easy enough to read data from the front of the file.  Sounds good so far.  The trouble with a regular file, however, is two-fold.  Firstly, you can&#8217;t tell when something has been written to the file without periodically polling it, something like this:</p>
<table border="0" bgcolor="#e8e8e8" width="100%" style="margin:0.2em 0;">
<tr>
<td style="padding:0.5em;">
<pre style="margin:0; padding:0;"># Create a regular file, and wait for it to grow
tom@gibbon:~$ touch /tmp/myqueue.txt
tom@gibbon:~$ while true; do test $(stat -c %s /tmp/myqueue.txt) -gt 0 &amp;&amp; break; done

# Now open a new terminal and echo into the file
tom@gibbon:~$ echo "Hello world" &gt; /tmp/myqueue.txt

# Your while loop will now return in your first terminal
# Note your CPU use has rocketed because of the spinning while loop!</pre>
</td>
</tr>
</table>
<p>This works reasonably enough, especially if you add a short sleep in the while loop to prevent hammering the CPU.  Polling is a bit ugly, though.  It would be much nicer if you could somehow block on the file changing.  Happily, there is a solution, in the form of the excellent <a href="https://github.com/rvoicilas/inotify-tools/wiki/">inotify-tools</a>, specifically inotify-wait:</p>
<table border="0" bgcolor="#e8e8e8" width="100%" style="margin:0.2em 0;">
<tr>
<td style="padding:0.5em;">
<pre style="margin:0; padding:0;"># Create a regular file, and wait for it to be modified
tom@gibbon:~$ touch /tmp/myqueue.txt
tom@gibbon:~$ inotifywait -e modify /tmp/myqueue.txt

# Now open a new terminal and echo into the file
tom@gibbon:~$ echo "Hello world" &gt; /tmp/myqueue.txt

# inotifywait will now return.  Note your CPU hasn't been
# working overtime :-)</pre>
</td>
</tr>
</table>
<p>The second part of the two-fold trouble with a regular file is that two processes can modify the same file at the same time with unpredictable results.  We need some kind of locking infrastructure.  The following approach works well, making use of the shell&#8217;s &#8220;noclobber&#8221; mode to reduce races between checking the file exists and writing to it:</p>
<table border="0" bgcolor="#e8e8e8" width="100%" style="margin:0.2em 0;">
<tr>
<td style="padding:0.5em;">
<pre style="margin:0; padding:0;"># $1 -- filename
lock() {
    while ! ( set -o noclobber; echo "$$" &gt; "${1}.lock" ) 2&gt;/dev/null
    do
        sleep 1
    done
}

# $1 -- filename
unlock() {
    rm -f "${1}.lock"
}</pre>
</td>
</tr>
</table>
<p>Note this is a &#8220;busy&#8221; lock&#8201;&#8212;&#8201;that is, we&#8217;re periodically doing something while waiting for the lock to become free.  In this case, checking to see whether the lockfile exists.  This can be improved upon by leveraging inotifywait once more:</p>
<table border="0" bgcolor="#e8e8e8" width="100%" style="margin:0.2em 0;">
<tr>
<td style="padding:0.5em;">
<pre style="margin:0; padding:0;"># $1 -- filename
lock() {
    while ! ( set -o noclobber; echo "$$" &gt; "${1}.lock" ) 2&gt;/dev/null
    do
        inotifywait -e delete_self "${1}.lock" &amp;&gt; /dev/null
    done
}

# $1 -- filename
unlock() {
    rm -f "${1}.lock"
}</pre>
</td>
</tr>
</table>
<p>Now the locking process simply sleeps until the lockfile has been deleted by the process holding it.  Insofar as interprocess locking goes, this is pretty good, but there is one remaining gotchya in that it is possible to create deadlocks should the process holding the lock unexpectedly exit before releasing the lock.  We can solve that with a trap:</p>
<table border="0" bgcolor="#e8e8e8" width="100%" style="margin:0.2em 0;">
<tr>
<td style="padding:0.5em;">
<pre style="margin:0; padding:0;"># $1 -- filename
lock() {
    while ! ( set -o noclobber; echo "$$" &gt; "${1}.lock" ) 2&gt;/dev/null
    do
        inotifywait -e delete_self "${1}.lock" &amp;&gt; /dev/null
    done
    # We now hold the lock
    trap "rm -f ${1}.lock" EXIT
}

# $1 -- filename
unlock() {
    rm -f "${1}.lock"
}</pre>
</td>
</tr>
</table>
<p>The downside of this, of course, is that it rather rudely overrides any existing trap which is set for SIGEXIT.  Is it possible to save the previous trap and restore it later?  I leave this as an exercise for the reader.</p>
<p>Putting all of this together, then, we can implement a fairly nice queue interface for Bash:</p>
<table border="0" bgcolor="#e8e8e8" width="100%" style="margin:0.2em 0;">
<tr>
<td style="padding:0.5em;">
<pre style="margin:0; padding:0;"># Lock the queue to prevent access from another process
# $1 -- queue file
queue_lock() {
    while ! ( set -o noclobber; echo "$$" &gt; "${1}.lock" ) 2&gt;/dev/null
    do
        inotifywait -e delete_self "${1}.lock" &amp;&gt; /dev/null
    done
}

# Unlock the queue to enable writing again
# $1 -- queue file
queue_unlock() {
    rm -f "${1}.lock"
}

# Wait on the queue being modified
# $1 -- queue file
queue_wait() {
    test -f "$1" &amp;&amp; inotifywait -e modify "${1}" &amp;&gt;/dev/null
}

# Add an entry to the queue
# $1 -- queue file
# $2 -- entry
queue_push() {
    echo "$2" &gt;&gt; "$1"
}

# Remove an entry from the queue
# $1 -- queue file
queue_pop() {
    local e=$(head -n1 "$1")
    awk 'NR != 1 { print }' $1 &gt; ${1}.new &amp;&amp; mv ${1}.new ${1}
    echo "$e"
}

# Get current length of the queue
# $1 -- queue file
queue_length() {
    test -f "$1" || echo 0
    wc -l $1 | cut -d " " -f1
}</pre>
</td>
</tr>
</table>
<p>This test script demonstrates the queue in action:</p>
<table border="0" bgcolor="#e8e8e8" width="100%" style="margin:0.2em 0;">
<tr>
<td style="padding:0.5em;">
<pre style="margin:0; padding:0;">#!/bin/bash

QUEUE=/tmp/queue

# include the queue interface
. $(dirname $0)/libqueue.sh

#
# Some wrapper functions for queue addition/removal
#

# $1 -- n items
add_to_queue() {
    local i=0
    for ((i=0;i&lt;$1;i++))
    do
        queue_lock $QUEUE
        queue_push $QUEUE "Item $i"
        queue_unlock $QUEUE
        echo "&gt; pushed : Item $i"
    done
}

# $1 -- n items
remove_from_queue() {
    local i=0
    local err=
    local ent=
    for ((i=0;i&lt;$1;i++))
    do
        test 0 -eq $(queue_length $QUEUE) &amp;&amp; queue_wait $QUEUE
        queue_lock $QUEUE
        ent="$(queue_pop $QUEUE)"
        queue_unlock $QUEUE
        test "$ent" = "Item $i" &amp;&amp; err="" || err="ERROR"
        echo "&lt; popped : $ent $err"
    done
}

# Spawn subshell processes to add to/remove from the queue
( add_to_queue 1000 ) &amp;
( remove_from_queue 1000 ) &amp;
wait $!</pre>
</td>
</tr>
</table>
<p>Any there you go!  Multiprocess, block-free queues in Bash.  Huzzah!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesecretdogproject.com/2011/12/of-build-farms-and-bash-queues/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>thesecretdogproject code quality checklist</title>
		<link>http://www.thesecretdogproject.com/2011/11/thesecretdogproject-code-quality-checklist/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=thesecretdogproject-code-quality-checklist</link>
		<comments>http://www.thesecretdogproject.com/2011/11/thesecretdogproject-code-quality-checklist/#comments</comments>
		<pubDate>Fri, 25 Nov 2011 08:55:50 +0000</pubDate>
		<dc:creator>tom</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.thesecretdogproject.com/?p=987</guid>
		<description><![CDATA[As a part of my day-job, I was tasked earlier this year with improving the stability of our software stack. This was a wide ranging brief, involving tracking down and fixing bugs at every level, from the kernel up to &#8230; <a href="http://www.thesecretdogproject.com/2011/11/thesecretdogproject-code-quality-checklist/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><img style="border-width: 0;" src="http://www.thesecretdogproject.com/wp-content/uploads/2011/11/wtfm.jpg" alt="Code Reviewing by WTFs per minute" /></p>
<p>As a part of my day-job, I was tasked earlier this year with improving the stability of our software stack. This was a wide ranging brief, involving tracking down and fixing bugs at every level, from the kernel up to the UI. It often required poking into the dusty corners that other programmers preferred to ignore, unearthing weird behaviours we never had the time to understand during development. On the whole, it was a task which demanded a cast-iron cynicism, a well-developed sense of suspicion, and not a little patience!</p>
<p>Over the course of my time on stability-watch, I noticed that I was increasingly guiding my suspicion by a barely-conscious mental checklist, a list of signs that a particular area of the code might be worth a further look. Like <a href="http://www.joelonsoftware.com/articles/fog0000000043.html">Joel On Software’s 12-point team checklist</a> I was developing my own secretdogproject checklist of code quality.</p>
<p>So, with no further ado, here’s my checklist of bad signs to look out for in code. These aren’t language-specific issues, since most coders are pretty good at picking these out. Rather, they’re more holistic signs of quality in a code base which might help signpost areas of poor quality for review.</p>
<h3><a name="_does_the_code_live_in_a_sensible_place_and_have_a_sensible_name"></a>Does the code live in a sensible place and have a sensible name?</h3>
<p>Each component of a codebase should have a name that communicates something about what that component does.</p>
<p>When combined, components should make use of a coherent directory hierarchy in order to communicate something about how the components fit together as a whole.</p>
<h3><a name="_does_the_code_have_any_documentation"></a>Does the code have any documentation?</h3>
<p>As any true hacker knows, the best approach when in doubt about what some code does is to <a href="http://encyclopedia2.thefreedictionary.com/Use+the+Source+Luke">use the source</a>. But sometimes, a paragraph of top-level design information, written in a high-level human language like English, can save hours of grubbing around in the code.</p>
<p>At a bare minimum, you should have a readme. Bonus points for autogenerated API docs.</p>
<h3><a name="_does_the_code_build_cleanly"></a>Does the code build cleanly?</h3>
<p>Compiler warnings are a hint that your code is wrong, and you ignore such hints at your peril. Good code should compile without warnings.</p>
<p>Bonus points if you’ve configured the build to treat warnings as errors to prevent future warnings creeping into the build.</p>
<h3><a name="_does_the_code_have_a_test_strategy"></a>Does the code have a test strategy?</h3>
<p>Code can be tested in many different ways.  Some components lend themselves to unit testing.  Others are better tested in-situ using test harnesses or other scaffolding. Whatever the best approach is for your component, you should have a developer test strategy in place, and it should be obvious how to use it.</p>
<p>Bonus points for including links to archived test results in the component documentation.</p>
<h3><a name="_does_the_code_look_nice"></a>Does the code look nice?</h3>
<p>If people spend time making a thing look nice, that probably means that they care about that thing. This applies as much to code as it does to a house or a garden. A consistent aesthetic in code means that the implementers took the time to make it look good, which may imply that they also took the time to consider corner cases, double check API call documentation, and prototype the implementation to chase out any unforeseen snags.</p>
<p>It doesn’t matter, by the way, what your coding convention is — so long as one is evident, and it is consistent throughout.</p>
<h3><a name="_do_the_comments_make_sense"></a>Do the comments make sense?</h3>
<p>Code comments should be hints to the reader about what is going on. This isn’t the place for top-level design information. Comments should act as signposts to document why we’re currently doing what we’re doing. Since code is typically read many more times than it is written, handy implementer’s hints can be invaluable for future maintenance.</p>
<p>Comments are a good indicator of code quality. If a comment is out-of-date, or looks like it may have been copied-and-pasted from somewhere else (e.g. the comment is out of context), that may be a hint that someone wasn’t paying full attention when they made their changes.</p>
<h3><a name="_does_the_code_have_a_good_heritage"></a>Does the code have a good heritage?</h3>
<p>One of the joys of modern source code management systems is that the history of each file in the code base is tracked. A developer can look back at how the code has changed over time, and this can be a valuable tool for estimating the quality of the code.</p>
<p>Bad signs include lots of change (which may indicate the design of the code is broken or fragile), poor changeset granularity (&#8220;big-bang&#8221; changes are easier to mess up and more difficult to test) and poor checking commenting (indicating the coder didn’t care enough or didn’t have time to write a decent comment).</p>
<p>Bonus points for documentation of why the change was made, the level of testing carried out, and references to bug/issue tracking tickets further describing the change.</p>
<h3><a name="_is_the_code_doing_anything_ugly_or_stupid"></a>Is the code doing anything ugly or stupid?</h3>
<p>Every programmer knows that, every so often, one has to hack things a little to get them going. Whether you’re programming around a weird library bug, breaking an abstraction in order to get at some data you need, or adding an expeditious but aesthetically troubling function which you’ll clean up after this release is out the door (honest guv), sometimes a bit of outright hackery is the best way to get the job done.</p>
<p>The trouble with these little hacks is that, over time, they accumulate in a codebase to form <a href="http://en.wikipedia.org/wiki/Technical_debt">technical debt</a>. As with financial debt, you need to keep on top of it lest interest payments become prohibitive. This is partially what <a href="http://en.wikipedia.org/wiki/Code_refactoring">code refactoring</a> is about: going back over the old ground to make good the things you missed or had to ignore the first time around.</p>
<p>If a code base contains a lot of hacks, it’s a good sign that the authors haven’t been able to carry out any refactoring work. This in turn suggests the code may be fragile, bug-prone, and difficult to extend.</p>
<h3><a name="_is_there_any_evidence_of_code_review"></a>Is there any evidence of code review?</h3>
<p>As every competent coder should know, defects are cheaper to fix the earlier they’re discovered in the development cycle. In an ideal world, careful attention during system specification and design should minimise defects throughout the project. But in the real world, designs are not perfect. Even worse, programmers are only human and may introduce new errors of their own as they’re coding!</p>
<p>One well-understood method of catching errors at the coding stage is code review: formal inspections of work designed to catch programming faults. It is an effective way of improving code quality.</p>
<p>If there is evidence that a component has been subject to a code review process, it is far less likely to contain errors than an unreviewed component.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesecretdogproject.com/2011/11/thesecretdogproject-code-quality-checklist/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Border Trilogy</title>
		<link>http://www.thesecretdogproject.com/2011/11/the-border-trilogy/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=the-border-trilogy</link>
		<comments>http://www.thesecretdogproject.com/2011/11/the-border-trilogy/#comments</comments>
		<pubDate>Mon, 21 Nov 2011 23:14:31 +0000</pubDate>
		<dc:creator>tom</dc:creator>
				<category><![CDATA[Books]]></category>

		<guid isPermaLink="false">http://www.thesecretdogproject.com/?p=984</guid>
		<description><![CDATA[It&#8217;s been an age since I finished this book, but I haven&#8217;t been able to write a review of it yet. There are many excuses for this: I&#8217;ve been starting a business, building walls in my front garden, enjoying the &#8230; <a href="http://www.thesecretdogproject.com/2011/11/the-border-trilogy/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.thesecretdogproject.com/wp-content/uploads/2011/11/cormac-mccarthy_the-border-trilogy.jpg" style="border-width: 0;" alt="Cover the The Border Trilogy"></p>
<p>It&#8217;s been an age since I finished this book, but I haven&#8217;t been able to write a review of it yet.  There are many excuses for this:  I&#8217;ve been starting a business, building walls in my front garden, enjoying the summer.  Beyond that I suspect this is just a difficult book (strictly: set of books) to review.  It&#8217;s a <strong>big</strong> book, both in the physical sense and the metaphysical sense.</p>
<p>Where <em>No Country For Old Men</em> and <em>The Road</em> are terse, <em>The Border Trilogy</em> is sprawling and lyrical.  Sentences are long, free-flowing; reminiscent of Kerouac at times in their loping narrative.  The landscapes of Mexico and Texas and the desert loom large, as does the physicality of the animals and people inhabiting these empty places.</p>
<p>Throughout all three books, there is an elegiac sense of mourning for something lost. Each novel has loss at its core, whether of a lover, a home, a family or a means of living.  And this loss is amplified by a temporal dislocation of the narrative: it is difficult to place any of the books in a particular period of time, although references to wars and some technologies serve to give vague hints.  The overall sense is one of a timelessness about to come to an end.  At the end of the trilogy, when Billy Parham, old and drifting, marvels at seeing the rare sight of a cup hung up by a spring for travellers to drink from, you share his sense of bewilderment at something gone without a chance to mark its passing.</p>
<p>But <em>The Border Trilogy</em> isn&#8217;t just about nostalgia for a better, or at least more certain, time.  In among the dense, beautiful pages there is much more to be found.  Quite apart from the arresting and off-kilter central narratives there are many small stories and vignettes sewn into the fabric of the novels.  Itinerant priests muse on the nature of dedication; hobos ask deep questions about the nature of reality; circus performers tell stories of love; prison-bound gangland bosses explore the ethics of suffering.  Where <em>The Road</em> is purposefully grey and empty, <em>The Border Trilogy</em>, for all its enduring love of sparse desert landscapes, is full of the horrific strangeness of life.  These aren&#8217;t easy reading books, but they are books you should read.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesecretdogproject.com/2011/11/the-border-trilogy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Debugging with GDB and Python &#8212; LJ article now freely available!</title>
		<link>http://www.thesecretdogproject.com/2011/08/debugging-with-gdb-and-python-lj-article-now-freely-available/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=debugging-with-gdb-and-python-lj-article-now-freely-available</link>
		<comments>http://www.thesecretdogproject.com/2011/08/debugging-with-gdb-and-python-lj-article-now-freely-available/#comments</comments>
		<pubDate>Sat, 20 Aug 2011 13:00:08 +0000</pubDate>
		<dc:creator>tom</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.thesecretdogproject.com/?p=978</guid>
		<description><![CDATA[Debugging with GDB and Python — LJ article now freely available! The article I had published in the June edition of Linux Journal has just become freely available on their website. You can read it here]]></description>
			<content:encoded><![CDATA[<p>Debugging with GDB and Python — LJ article now freely available!</p>
<p>The article I had published in the June edition of Linux Journal has just become freely available on their website. You can <a href="http://www.linuxjournal.com/article/11027">read it here</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesecretdogproject.com/2011/08/debugging-with-gdb-and-python-lj-article-now-freely-available/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Movivation vs. Moaning</title>
		<link>http://www.thesecretdogproject.com/2011/08/movivation-vs-moaning/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=movivation-vs-moaning</link>
		<comments>http://www.thesecretdogproject.com/2011/08/movivation-vs-moaning/#comments</comments>
		<pubDate>Fri, 05 Aug 2011 15:45:17 +0000</pubDate>
		<dc:creator>tom</dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[Waffle]]></category>

		<guid isPermaLink="false">http://www.thesecretdogproject.com/?p=976</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.thesecretdogproject.com/wp-content/uploads/2011/08/motivation_vs_moaning.jpg" style="border-width: 0;" alt="A graph of motivation vs moaning"></p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesecretdogproject.com/2011/08/movivation-vs-moaning/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The subtle art of noise reduction</title>
		<link>http://www.thesecretdogproject.com/2011/06/the-subtle-art-of-noise-reduction/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=the-subtle-art-of-noise-reduction</link>
		<comments>http://www.thesecretdogproject.com/2011/06/the-subtle-art-of-noise-reduction/#comments</comments>
		<pubDate>Mon, 27 Jun 2011 22:15:09 +0000</pubDate>
		<dc:creator>tom</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.thesecretdogproject.com/?p=969</guid>
		<description><![CDATA[I recently installed Ubuntu on an old PC I wanted to act as a temporary server for a website. Seeing as this box has to live in my home office, I wanted it to be as quiet as possible. In &#8230; <a href="http://www.thesecretdogproject.com/2011/06/the-subtle-art-of-noise-reduction/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I recently installed Ubuntu on an old PC I wanted to act as a temporary server for a website.  Seeing as this box has to live in my home office, I wanted it to be as quiet as possible.</p>
<p><a href="http://www.thesecretdogproject.com/wp-content/uploads/2011/06/concentration.gif"><img class="alignnone size-full wp-image-970" title="concentration" src="http://www.thesecretdogproject.com/wp-content/uploads/2011/06/concentration.gif" alt="A cartoon illustrating the difficulty of concentration in a noisy environment" width="398" height="328" /></a></p>
<p>In the past I&#8217;ve built PCs for music recording purposes and designed them to be as quiet as possible by using large case fans, passive CPU coolers, and super-efficient power supplies.  In this case, I had the PC and whatever was in my spares box at my disposal.  Here&#8217;s how I quieted it down.</p>
<h2>Remove surplus components</h2>
<p>This PC used to be a graphics workstation, so it had a beefy graphics card as well as a pair of hard drives in a RAID array.  I don&#8217;t need any of that for a server, so I removed all the extraneous components I could from the case.  Fewer components means less power draw, hence less heat to remove from the case.  Fewer cables connecting components to the motherboard means fewer obstructions to smooth airflow.</p>
<h2>Ensure fans are using speed control</h2>
<p>Most modern motherboards offer a speed control pin for fans.  These can be used to slow down case and CPU fans when the box isn&#8217;t so hot.  Slower fans mean less noise.</p>
<h2>Install lm-sensors and fancontrol</h2>
<p><a href="http://www.lm-sensors.org/">lm-sensors</a> provides hardware monitoring support in Linux, and <a href="http://www.lm-sensors.org/wiki/man/fancontrol">fancontrol</a> is a script which works with the sensor data to control the speed of fans in the system.</p>
<p>Ubuntu packages both, so you can install them with aptitude:</p>
<p><code>aptitude install lm-sensors fancontrol</code></p>
<p>Once the packages are installed, you can set them up for use with sensors-detect.  This script works out which fans are attached to which PWM controllers by modifying PWM output settings while you listen for changes in fan speed.  It then goes on to figure out the maximum and minimum PWM settings for the fans in your box, and allows you to configure temperature/fanspeed relationships.</p>
<h2>Test it out!</h2>
<p>With fancontol running, my Ubuntu server is no noisier than the road outside my house.  This is an acceptable noise level for me.</p>
<p>However, I wanted to be sure that the fan controller was doing what it said on the tin.  As such, I whipped up a simple shell script to log CPU and case temperature against fan speed:</p>
<p><code><br />
#!/bin/bash<br />
#<br />
# Log temperature information from sensors<br />
#</code></p>
<p><code>readonly SAMPLE_INTERVAL=30 # seconds<br />
readonly HEADER_INTERVAL=10 # samples<br />
readonly LOGFILE=/root/templog.csv</p>
<p>do_header() {<br />
echo "# Time (UNIX epoch) , CPU temp (degC) , Case temp (degC) , CPU fan speed (RPM)"<br />
}</p>
<p>do_templog() {<br />
echo "$(date +%s) , $(sensors | awk '/Core0/ { cpu = substr($3, 2, 4); } \<br />
/fan1/ { rpm = $2; } \<br />
/temp2/ { case = substr($2, 2, 4); } \<br />
END { print cpu,",",case,",",rpm; }')"<br />
}</p>
<p>count=0</p>
<p></code></p>
<p><code>while true<br />
do<br />
if test $count -eq 0<br />
then<br />
do_header<br />
count=$HEADER_INTERVAL<br />
fi<br />
do_templog<br />
sleep $SAMPLE_INTERVAL<br />
count=$((count - 1))<br />
done &gt;&gt; $LOGFILE<br />
</code></p>
<p>I tried a quick test of system response by subjecting the CPU to some computational stress:</p>
<p><code>dd if=/dev/urandom | gzip -c -9 &gt; /dev/null</code></p>
<p>With a few of these pipelines running in parallel, the CPU stayed more-or-less 100% busy.</p>
<p>Here&#8217;s a graph of the system response:</p>
<p><a href="http://www.thesecretdogproject.com/wp-content/uploads/2011/06/templog_curve.png"><img class="alignnone size-thumbnail wp-image-971" title="templog_curve" src="http://www.thesecretdogproject.com/wp-content/uploads/2011/06/templog_curve-150x150.png" alt="Graph of CPU temperature and fanspeed response under stress" width="150" height="150" /></a></p>
<p>As you can see, the system is behaving as it should.  As the CPU is loaded, core temperature increases and fan speed ramps up in response.  Removing the CPU load allows the core to cool, and the fan slows down again.  Perfect.</p>
<p>Just for fun I left my script running in the background for the next few days.  Here&#8217;s a graph of the data:</p>
<p><a href="http://www.thesecretdogproject.com/wp-content/uploads/2011/06/templog.png"><img class="alignnone size-thumbnail wp-image-972" title="templog" src="http://www.thesecretdogproject.com/wp-content/uploads/2011/06/templog-150x150.png" alt="CPU temperature and fan speed over the course of a few days" width="150" height="150" /></a></p>
<p>Aside from a few outliers, the fan speed looks pretty much stable until the CPU temperature gets to around 35 degrees, which is the trigger temperature for a speed increase.  At that point there is quite a lot of fluctuation in fan speed.  It would be interesting to see whether hysteresis could be added to the fancontrol script to compensate for that.</p>
<h2>In conclusion</h2>
<p>With a little bit of effort you can reduce the noise generated by a standard PC, without necessarily buying any specialist parts.  If you&#8217;ve got to share a room with that PC, the results can be more than worth it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesecretdogproject.com/2011/06/the-subtle-art-of-noise-reduction/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The course of true computing never did run smooth</title>
		<link>http://www.thesecretdogproject.com/2011/06/the-course-of-true-computing-never-did-run-smooth/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=the-course-of-true-computing-never-did-run-smooth</link>
		<comments>http://www.thesecretdogproject.com/2011/06/the-course-of-true-computing-never-did-run-smooth/#comments</comments>
		<pubDate>Tue, 21 Jun 2011 22:26:25 +0000</pubDate>
		<dc:creator>tom</dc:creator>
				<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.thesecretdogproject.com/?p=964</guid>
		<description><![CDATA[How long should it take to install Ubuntu server on a PC, would you think? In my case, all evening! I had an old PC on which I wanted to install Ubuntu&#8217;s most recent LTS release (&#8220;Lucid Lynx&#8221;). In ordinary &#8230; <a href="http://www.thesecretdogproject.com/2011/06/the-course-of-true-computing-never-did-run-smooth/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>How long should it take to install Ubuntu server on a PC, would you think?  In my case, all evening!</p>
<p>I had an old PC on which I wanted to install Ubuntu&#8217;s most recent LTS release (&#8220;Lucid Lynx&#8221;). In ordinary circumstances, this should take about an hour or so.  However, it just so happens that my PC has a specific model of NEC DVD drive which is subject to <a href="https://bugs.launchpad.net/ubuntu/+source/linux/+bug/682159">this Ubuntu installer bug</a>.</p>
<p><img src="http://www.thesecretdogproject.com/wp-content/uploads/2011/06/lynx.jpg" style="border-width: 0;" alt="A Lucid Lynx"></p>
<p>So what to do?</p>
<p>First off, I tried downloaded the minimal install image and burning that to CD.  Some folks <a href="http://ubuntuforums.org/showthread.php?t=1756948">on the Ubuntu forum</a> seemed to have success with this approach.  But not me.  My PC simply turned its nose up at the minimal install CD.</p>
<p>Next, I investigated booting the install image from a USB flash device.  I used the most excellent <a href="http://unetbootin.sourceforge.net/">unetbootin</a> tool to extract the ISO image onto a USB flash drive, and asked the PC to boot from that. It worked!  Or, at least, it worked insofar as booting the installer.  Sadly, one of the installer&#8217;s first jobs is to talk to the CD to check the contents of the image.  So I was back to square one.</p>
<p>Or was I?  After some fruitless banging of my forehead against my desk, I hit upon a cunning workaround.  Boot from the USB drive, then insert the CD and let the installer have a look at it.  Then, when the installer pauses to ask a question, log in on another virtual terminal, umount the CD drive, and mount the USB device in it&#8217;s place.  That way, the installer thinks it has the CD mounted, and all the files it needs are there&#8201;&#8212;&#8201;but it doesn&#8217;t have to talk to the CD drive itself, and thereby avoids the bug I tripped over in the first place.</p>
<p>Finally, I have my Ubuntu Server install.  And it only took two CDs, a USB flash drive, and an evening of time.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesecretdogproject.com/2011/06/the-course-of-true-computing-never-did-run-smooth/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Poor Kids</title>
		<link>http://www.thesecretdogproject.com/2011/06/poor-kids/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=poor-kids</link>
		<comments>http://www.thesecretdogproject.com/2011/06/poor-kids/#comments</comments>
		<pubDate>Fri, 10 Jun 2011 11:32:17 +0000</pubDate>
		<dc:creator>tom</dc:creator>
				<category><![CDATA[Waffle]]></category>

		<guid isPermaLink="false">http://www.thesecretdogproject.com/?p=961</guid>
		<description><![CDATA[Did you see Poor Kids earlier this week? Focusing on child poverty in the UK, it presents a truly shocking picture of life below the poverty line. It&#8217;s not comfortable viewing, but it is well worth watching. You can catch &#8230; <a href="http://www.thesecretdogproject.com/2011/06/poor-kids/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Did you see <a href="http://www.bbc.co.uk/programmes/b011vnls">Poor Kids</a> earlier this week?  Focusing on child poverty in the UK, it presents a truly shocking picture of life below the poverty line.  It&#8217;s not comfortable viewing, but it is well worth watching.  You can catch it still on iPlayer.</p>
<p>Besides being heart-wrenchingly sad, <em>Poor Kids</em> left me feeling angry and frustrated.  The film is crammed with injustice.  From the benefits-cutting which left one family prey to short-term loan offers (with the associated prohibitive interest rates), to the utilities companies and hire firms who make low-income families pay over the odds for services, there are countless examples of poor people getting a rough deal simply because they are poor.  As an example, If I wanted to take out a personal loan from my bank (the Cooperative), the <em>highest</em> interest rate I could pay would be 20.9% APR.  By contrast, if I were forced to use someone like Provident Personal Credit, the <em>lowest</em> interest rate I could pay would be 272.2% APR.  I know the finance companies would argue that low income customers represent a higher risk, and the relatively high APR reflects that, but that doesn&#8217;t make it fair.</p>
<p>A rough deal from financiers is only the start of it.  The kids in the film suffered illness due to poor housing conditions, were bullied at school because they didn&#8217;t have the right clothes, were bored on the streets due to a lack of things to do, and felt a lack of self-worth that even drove one girl to attempt suicide.  If you&#8217;re poor, you get a rough deal from the whole of society.</p>
<p>The thing that saddened me the most about <em>Poor Kids</em>, though, was how little optimism they felt for the future.  School seemed less an education than something to be endured, or possibly an opportunity for a free meal.  Pessimism about jobs and about the challenges of adulthood abounded. And the terrible thing about that sort of pessimism that it becomes a self-fulfilling prophecy. If you know there is no way out of your situation, you are much less likely to even try.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesecretdogproject.com/2011/06/poor-kids/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Singadraw</title>
		<link>http://www.thesecretdogproject.com/2011/05/singadraw/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=singadraw</link>
		<comments>http://www.thesecretdogproject.com/2011/05/singadraw/#comments</comments>
		<pubDate>Fri, 20 May 2011 14:46:12 +0000</pubDate>
		<dc:creator>tom</dc:creator>
				<category><![CDATA[Waffle]]></category>

		<guid isPermaLink="false">http://www.thesecretdogproject.com/?p=958</guid>
		<description><![CDATA[I&#8217;ve just come across Singadraw, a lovely blog charting the experience of moving to a new city, a new job, and a new country. Fantastic stuff.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just come across <a href="http://singadraw.wordpress.com/">Singadraw</a>, a lovely blog charting the experience of moving to a new city, a new job, and a new country.  Fantastic stuff.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thesecretdogproject.com/2011/05/singadraw/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

