<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 <title>Notes from Ken</title>
 <link href="http://www.xythian.com/notes/feed" rel="self"/>
 <link href="http://www.xythian.com/notes/" />
 <updated>2011-08-13T20:24:49.957878+00:00</updated>
 <id>http://www.xythian.com/notes/feed</id>
 
 <entry>
   <title>New site</title>
   <author><name>Ken</name></author>
   <link href="/notes/2011/07/new-site"/>

   <published>2011-07-28T08:00:00+00:00</published>
   <id>tag:xythian.com,2011-07-28:new-site</id>
   <content type="html">&lt;div&gt;
&lt;h2&gt;A new site?&lt;/h2&gt;
&lt;p&gt;For historical hosting-related reasons my personal sites were spread
across two domains and three hostnames (www.xythian.com, photos.xythian.com, and
notes.xythian.net).  www.xythian.com was a purely static site
generated ages ago by a bespoke template system written in
Python. photos.xythian.com ran Singleshot 2 and had my public photos.
notes.xythian.net was my WordPress-powered blog.&lt;/p&gt;
&lt;p&gt;The new site consolidates the old static site, photos, and blog into
one site (www.xythian.com) and I&#39;ve put permanent redirects in to the
old sites to map the old resources to their new homes.&lt;/p&gt;
&lt;h2&gt;Why?&lt;/h2&gt;
&lt;p&gt;I wanted to consolidate my hosting and simplify discovery for the
content I publish.&lt;/p&gt;
&lt;p&gt;Why host anything at all?  I run my web presence on software I control
rather than using application hosting services because I want to
control it rather than be at the mercy of some company for my site.&lt;/p&gt;
&lt;p&gt;What I publish has changed over the years -- a lot of the casual
sharing is now done via social networking sites which means less of
that goes into the blog or photo site.&lt;/p&gt;
&lt;h2&gt;Design of the new site&lt;/h2&gt;
&lt;h3&gt;Audience &amp;amp; Contents&lt;/h3&gt;
&lt;p&gt;Judging by my access logs, people appear to have one of three intents
when visiting my site:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Seek. Seeking a solution to a technical problem or pictures of
   something in particular
   (&lt;a href=&#34;/photos/2008/07/40d-1000230&#34;&gt;actual size&lt;/a&gt; is a
   common entry point).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Follow.  People following the notes, photos, or both.  These
     people are mostly using feed readers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Browse.  Usually these folks got the address from someone
     (usually me) and are coming to see what&#39;s here.&lt;br&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The new site should facilitate all of these uses.  Canonical,
stable URLs help get things indexed properly for Seekers.   I plan to
delegate site search to Google Custom Search once the site is indexed
rather than running my own search.  Most people came in via a major
web search engine rather than using the old site&#39;s search.&lt;/p&gt;
&lt;p&gt;The two major types of content are still in seperate feeds (notes,
photos) and they are redirected from the old homes of those feeds so
followers should have a relatively transparent experience (although
when the cut-over happens there may be some repeat posts).&lt;/p&gt;
&lt;p&gt;Having a single new site in place of the multiple older sites should
make discovery and navigation easier for browsers.&lt;/p&gt;
&lt;h3&gt;Devices and browsers&lt;/h3&gt;
&lt;p&gt;The new site (attempts to) uses HTML5 and CSS and make a single site
that should lay out adequately on a variety of screen sizes.  I tested
on a collection of browsers I had handy and didn&#39;t worry about exact
pixel-perfect rendering everywhere.&lt;/p&gt;
&lt;p&gt;Navigation is suppressed for printing using media selectors.  The
overwhelming majority of (non-crawler) traffic to my site uses modern
browsers.&lt;/p&gt;
&lt;h2&gt;URIs&lt;/h2&gt;
&lt;p&gt;I updated a bunch of links from posts and pages -- the Internet seems to decay.  A lot of
links scattered in the last several years of notes posts were no
longer valid.  Some of them I could update and some I just removed.
Dismayingly, some of these links were from the last few months.  I&#39;m
afraid a lot of people have forgotten (or, more likely, never learned)
the lessons of
&lt;a href=&#34;http://www.w3.org/Provider/Style/URI.html&#34;&gt;from the past&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Of course, I changed almost all the URIs on my sites with this
change.  The consolidation of hostnames and domains that
I wanted to do involved changing almost all of the URIs for
everything.  I thought about the design of the new site&#39;s URIs and
contents before I thought about the layout and other styling
attributes.&lt;/p&gt;
&lt;p&gt;I switched to a /YYYY/MM/slug from /YYYY/MM/DD/slug for the notes
posts (matching the usual format of URLs used by the photos site).
Notes and posts are still kept in their own trees (/notes/ and
/photos/) because judging by access logs the audiences are nearly
disjoint.  I dropped the trailing &#34;/&#34; from the canonical version of
these URLs because they&#39;re not directories.  All of the media and
other static resources live under one of a few top-level directories
so I can easily set the caching behavior on the lot of them.&lt;/p&gt;
&lt;p&gt;The few &#34;legacy&#34; pages on the static site survived at nearly the same
URL although a few of those are orphaned -- they&#39;re not linked from
the new site, but search engines and other links still can direct
traffic to them.  These mostly were things I moved to the
&lt;a href=&#34;http://github.com/xythian/codebag&#34;&gt;codebag&lt;/a&gt; github project but didn&#39;t
want to make a straight redirect since that would be too abrubt given
the reorganization.&lt;/p&gt;
&lt;h2&gt;Comments&lt;/h2&gt;
&lt;p&gt;The new site has no support for comments.  I am still considering if
and how to handle comments.  The options include using something like
Disqus, rolling my own comment service, and not supporting comments
directly on the site.  Today most feedback about things I post comes
via mail, IM, Facebook, or Twitter.&lt;/p&gt;
&lt;p&gt;Combine this with the fact that ratio of legitimate comments to spam
on the WordPress blog was vanishingly low.  The other sites didn&#39;t support
comments -- although the photo site did for a while.  Support for
comments is a lot of surface area without much benefit, unfortunately.&lt;/p&gt;
&lt;p&gt;I may post an email address more prominently to provide a channel for
feedback directly on the site.&lt;/p&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Media backups and workflow</title>
   <author><name>Ken</name></author>
   <link href="/notes/2011/07/media-backups-and-workflow"/>

   <published>2011-07-07T20:18:00+00:00</published>
   <id>tag:xythian.com,2011-07-07:media-backups-and-workflow</id>
   <content type="html">&lt;div&gt;
&lt;p&gt;I have a lot of photos and video -- the result of several years of enthusiastic DSLR use.&lt;/p&gt;

&lt;p&gt;A few months ago I purchased a new NAS box and assembled a new backup scheme.  This is a brief overview of how it works and some information about how I made some of the decisions.&lt;/p&gt;

&lt;p&gt;My media tree&#39;s &#34;source of truth&#34; is my desktop machine&#39;s data drive -- currently a RAID 0 (striped) array of two 2TB disks.  I download photos using &lt;a href=&#34;http://http://www.breezesys.com/Downloader/&#34;&gt;Downloader Pro&lt;/a&gt; into a directory structure like this:&lt;/p&gt;

&lt;blockquote&gt;
H:\photos\YYYY\YYYY-MM-DD-name\filename.CR2&lt;br&gt;
H:\videos\YYYY\YYYY-MM-DD-name\filename.MTS/AVI
&lt;/blockquote&gt;

&lt;p&gt;using the download path template:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Directory: h:\{default,{E9},photos}\{Y}\{Y}-{m}-{D}-{J}
  Filename: {T8}{o}&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first bit is what automatically splits photos into one tree and videos into another tree.  The rest uses the year, month, day, original filename and type, and abbreviated camera model to assemble a file path like:&lt;/p&gt;

&lt;blockquote&gt;
H:\photos\2011\2011-01-28-macro\5D2_MG_7004.CR2
&lt;/blockquote&gt;

&lt;p&gt;Where &#34;5D2&#34; is the abbreviated name I&#39;ve given to my DSLR.  Downloader Pro prompts for this when it sees files from a camera that it&#39;s never seen before (it&#39;s reading the EXIF data).  &#34;macro&#34; there is the &#34;job code&#34;, which is something I enter for each download and is just a name to give me some idea what&#39;s in the directory.  Usually it&#39;s the name of where or what I was shooting for that outing.&lt;/p&gt;

&lt;p&gt;I use Downloader Pro because it gave me the flexibility I wanted to download into the directory structure that was reasonably navigable independent of any management tools.&lt;/p&gt;

&lt;p&gt;I use FileBack PC to back both of these trees and the rest of the interesting files on the desktop to a Synology DS-1511+ array which can deal with one disk failure without losing data and has ample room for growth.  That in turn backs itself up to an external 3TB USB disk every morning.   Periodically I plug one of a rotating set of drives into a machine or the NAS and sync everything to that disk and bring it off-site.&lt;/p&gt;

&lt;p&gt;Currently the photo+video tree totals about 1TB and all of the data together is around 1.5TB which means it still comfortably fits onto inexpensive 2TB USB disks for the off-site rotation.&lt;/p&gt;

&lt;p&gt;Some data I keep on the NAS but don&#39;t back up -- things that are easily replicated but are merely convenient to have locally such as ISOs for Ubuntu v.current.&lt;/p&gt;

&lt;p&gt;I&#39;ve gone through a few backup targets since I started downloading into this tree and using  FileBack PC to back things up.  In that time I&#39;ve had one catastrophic disk failure and restored successfully from the then-current backup target (an NSLU2 and USB disk).&lt;/p&gt;

&lt;p&gt;I periodically (once a month or so, I need to automate this) run an md5sum on all of the files on the NAS, source-of-truth disk, and USB backup target and verify that the things I expect to match across those (&amp;#8230;all of the data files&amp;#8230;) do in fact still match.  I haven&#39;t yet caught a discrepancy here (and don&#39;t really expect to given the total size of my data and probability of uncorrected, uncaught disk errors) but I have detected developing disk failures by exercising all the bytes and hearing/seeing the attempts to correct bad sectors.   I replace disks if they give any signs of failing or after a couple of years.&lt;/p&gt;

&lt;p&gt;I have a single Lightroom 3 catalog into which I&#39;ve imported all of the photos (~42000 as of this writing) and (for many) assigned keywords and ratings so I can search for images.&lt;/p&gt;

&lt;p&gt;The usual workflow now is to download the new batch of photos, import them into Lightroom, and make a pass or two over them giving them ratings from 1 to 5 stars.  From there depending on the sort of outing it was I share the &#34;selected&#34; photos directly from Lightroom.  I use &lt;a href=&#34;http://regex.info/blog/lightroom-goodies&#34;&gt;Jeffrey Friedl&#39;s plugins&lt;/a&gt; to export to the places I share photos.&lt;/p&gt;

&lt;p&gt;Sometimes I run the phone&#39;s GPS during an outing so I can geotag the photos although I haven&#39;t yet done much to take advantage of this data.&lt;/p&gt;

&lt;p&gt;I&#39;ve been revamping my keyword tree now that I have some more experience using Lightroom and may make a future post about that.  The summary version is &#34;group keywords into a tree&#34; like &#34;animal &amp;gt; dog &amp;gt; breed &amp;gt; particular-dog (when applicable)&#34; or &#34;location &amp;gt; CA &amp;gt; San Francisco &amp;gt; Golden Gate Park&#34; and arrange so when I export the photo all the higher level keywords get exported along with the details.  This is just to speed keyword entry and ensure I&#39;m using consistent names.  Some keywords are not exported and I use only to search within Lightroom.&lt;/p&gt;

&lt;p&gt;I don&#39;t yet have a very good story for managing video clips or projects.&lt;/p&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Mock service dependencies</title>
   <author><name>Ken</name></author>
   <link href="/notes/2011/04/mock-service-dependencies"/>

   <published>2011-04-16T05:34:34+00:00</published>
   <id>tag:xythian.com,2011-04-15:mock-service-dependencies</id>
   <content type="html">&lt;div&gt;
&lt;p&gt;Suppose you&#39;re building a service that depends on several other
services to work. You write a bunch of code and carefully include
error handling code and have a plan for what happens if each
service your new service calls fails. Naturally, you want to test
your code. These services are invoked over a network. Perhaps
they&#39;re web services but they may be some other network protocol.
Suppose further your code is nicely factored so there&#39;s a &#34;client&#34;
class that presents the network service as a library API to the
rest of the service.&lt;/p&gt;
&lt;p&gt;There are a few approaches to ensure you have tests that exercise
as much of your own service&#39;s code as possible.&lt;/p&gt;
&lt;p&gt;All of these approaches share the idea that you want to have a mock
service that you can instruct how to reply so each test can
exercise an aspect of the &#34;target&#34; services code.&lt;/p&gt;
&lt;p&gt;One approach is to write &#34;mock&#34; services at the library level --
swap out the code that calls out to the network with tame code you
tell what to do as part of the test set-up. This would involve
preparing to return predetermined results for a given request (a
proper response or an error of some kind).&lt;/p&gt;
&lt;p&gt;Another approach is to &#34;mock&#34; out at the &#34;service transport&#34; level
-- keep the client implementation that thinks it&#39;s making, say,
HTTP requests but swap out the HTTP client with a library that
accepts HTTP requests at the API level and replies with appropriate
HTTP responses.&lt;/p&gt;
&lt;p&gt;A third approach is to &#34;mock&#34; the network service at the network
level. This last approach involves writing a complete enough
implementation of the target service to behave like the target
service that can be instructed to reply with a proper response, a
malformed response of some kind, or an error after some specified
time (as fast as possible, normally, except when exercising timeout
handling code) .. or even to do things like close the network
connection before responding, or simply never respond at all. This
exercises the entire stack of client code and permits testing of
the service code and the network client code. It can be more work
than the first two approaches, but almost provides the most
confidence that as much of the service is exercised as possible. It
also makes the test code more resilient to internal refactoring of
the service since more of it is adhering to the externally visible
API boundary (which presumably is more costly to change anyway)
rather than introducing another surface acting as an API boundary.
This mock service implementation can also be used with other client
implementations helping to reduce the amount of code involved.&lt;/p&gt;
&lt;/div&gt;
</content>
 </entry>
 
</feed>
