<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>~jshirley</title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/" />
    <link rel="self" type="application/atom+xml" href="http://our.coldhardcode.com/jshirley/atom.xml" />
    <id>tag:our.coldhardcode.com,2008-08-14:/jshirley//2</id>
    <updated>2008-12-20T15:51:59Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.23-en</generator>

<entry>
    <title>How to hire Perl Hackers in 2008</title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/2008/12/how-to-hire-perl-hackers-in-20.html" />
    <id>tag:our.coldhardcode.com,2008:/jshirley//2.26</id>

    <published>2008-12-20T15:24:26Z</published>
    <updated>2008-12-20T15:51:59Z</updated>

    <summary>This is a post in response to &quot;How to not get hired&quot;. In modern times, with the wonderful business of head-hunters and body placement shops you can&apos;t rely on getting quality candidates through traditional job posting channels unless you have...</summary>
    <author>
        <name>J. Shirley</name>
        <uri>http://www.coldhardcode.com/</uri>
    </author>
    
    <category term="hiring" label="hiring" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perl" label="perl" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://our.coldhardcode.com/jshirley/">
        <![CDATA[This is a post in response to "<a href="http://avatraxiom.livejournal.com/95669.html">How to not get hired</a>".<br />
<br />
In modern times, with the wonderful business of head-hunters and body placement shops you can't rely on getting quality candidates through traditional job posting channels unless you have a lot of time on your hands.&nbsp; Most of that time is spent throwing away resumes.&nbsp; This is the first step to being successful: <b>throw away bad resumes</b>.&nbsp; This is even true if you suspect it to be bad.&nbsp; You may toss out some good candidates, but for the first round focus on candidates that know how to write a resume (and ideally use spell check and don't write Java Scripts).<br /><br />The second step to being successful is to define testing criteria.&nbsp; If you want experienced developers, not only do you have to be prepared to pay for them (in addition to creating an environment they would want to be in) but you have to know what it means.&nbsp; An experienced developer or an experienced Perl developer are two different things.&nbsp; React accordingly.<br /><br />I'm also a proponent of sample code, but I don't believe it's all that helpful.&nbsp; The people who submit terrible sample code tend to be the same people who submit terrible resumes.&nbsp; If someone truly wants a job, they're going to care about the sample code they submit.&nbsp; This, however, is very closely tied into the pay rate.&nbsp; If you offer low pay, expect low quality -- chances are they are junior and haven't figured out the "right way" yet.<br /><br />If your first round of candidates all have the same style and there aren't any clear winners, something is repeling the quality developers.&nbsp; React accordingly; either adjust your qualifications or restructure what you are offering.<br /><br />There is always a shortage of high quality developers, as they always know someone who is looking to hire them.&nbsp; Good developers are more likely to find employment through their social network than through a job posting site.&nbsp; This puts companies without being able to tap their social network for new developers at a distinct disadvantage.<br /><br />This means you're bound to get spammed with a ton of poorly written resumes by people who don't want the job for more than a few weeks.&nbsp; If you expect gold from these folks, you're going to get lead.<br /><br />It's not their fault, it is yours.&nbsp; Just as ridiculous as their sample code may be, it's ridiculous to assume skilled developers are just waiting to be picked up by some lucky company.<br /><br />On a side note, expecting a Perl developer to know Moose on a $25-$30 an hour contract job with a cap of 20 hours is almost as bad as expecting a free lunch... but good luck on hiring, I know how frustrating it can be.<br /><br /> ]]>
        
    </content>
</entry>

<entry>
    <title><![CDATA[Now with ActionStreams (and a fix for "&lt;mt:event&gt; not found")]]></title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/2008/12/now-with-actionstreams-and-a-f.html" />
    <id>tag:our.coldhardcode.com,2008:/jshirley//2.23</id>

    <published>2008-12-12T21:38:09Z</published>
    <updated>2008-12-12T22:27:50Z</updated>

    <summary><![CDATA[I've setup ActionStreams before, and I really dig the idea.&nbsp; I'm setting it up here, because of the CPAN ActionStreams plugin.&nbsp; All of this centers around the work I'm doing for the Enlightened Perl Organisation (or Organization, depending upon your...]]></summary>
    <author>
        <name>J. Shirley</name>
        <uri>http://www.coldhardcode.com/</uri>
    </author>
    
    <category term="actionstreams" label="actionstreams" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="movabletype" label="movable type" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mt" label="mt" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plugins" label="plugins" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://our.coldhardcode.com/jshirley/">
        <![CDATA[I've setup ActionStreams before, and I really dig the idea.&nbsp; I'm setting it up here, because of the CPAN ActionStreams plugin.&nbsp; All of this centers around the work I'm doing for the Enlightened Perl Organisation (or Organization, depending upon your Atlantic Ocean perspective).<br /><br />One thing that bothered me is that the tags didn't work right with the templates provided in the distribution.&nbsp; Movable Type rightfully complained that some of the tags simply didn't exist.&nbsp; Trying to save the widget template gave me this error:<br /><blockquote><ul><li><pre>&lt;mt:authorevents&gt; at line 9 is unrecognized.</pre></li><li><pre>&lt;mt:eventdate&gt; at line 23 is unrecognized.</pre></li><li><pre>&lt;mt:event&gt; at line 22 is unrecognized.</pre></li><li><pre>&lt;mt:event&gt; at line 24 is unrecognized.</pre></li><li><pre>&lt;mt:event&gt; at line 25 is unrecognized.</pre></li><li><pre>&lt;mt:eventmodifieddate&gt; at line 26 is unrecognized.</pre></li><li><pre>&lt;mt:eventdate&gt; at line 27 is unrecognized.</pre></li></ul></blockquote>Well, that sucks!&nbsp; Fortunately, the fix is a quick search and replace.&nbsp; You just have to change the following:<br /><br />
<table style="border: 1px solid rgb(0, 0, 0); margin: auto; width: 80%;">
<tbody><tr><td>mt:authorevents</td><td>=&gt;</td><td>mt:ActionStreams</td></tr>

<tr><td>mt:eventdate</td><td>=&gt;</td><td>mt:StreamActionDate</td></tr>

<tr><td>mt:event</td><td>=&gt;</td><td>mt:StreamAction</td></tr>

<tr><td>mt:eventmodifieddate</td><td>=&gt;</td><td>mt:StreamActionModifiedDate</td></tr>
</tbody></table>

<br />That should get you going!<br /><b><br />Update:</b> Some other things I had to debug to get everything working that I thought I'd list here:<br /><ol><li>Check your blog Activity Log for errors.&nbsp; I was missing XML::Parser, so the Vox plugin was stopping everything from going and nothing was happening.</li><li>Make sure both your blog author name <b>and</b> your display name are the same in every template bit, otherwise ActionStream can't find your stream.</li></ol><br />]]>
        
    </content>
</entry>

<entry>
    <title>Writing Catalyst Components</title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/2008/11/writing-catalyst-components.html" />
    <id>tag:our.coldhardcode.com,2008:/jshirley//2.19</id>

    <published>2008-11-18T14:39:34Z</published>
    <updated>2008-11-18T14:42:44Z</updated>

    <summary><![CDATA[This is a posting about a wiki node on writing Catalyst Components I just wrote up at the Catalyst wiki, that I hope gets a bit wider views.&nbsp; People often times ignore wikis; less so than blogs anyway.Writing Catalyst Components...]]></summary>
    <author>
        <name>J. Shirley</name>
        <uri>http://www.coldhardcode.com/</uri>
    </author>
    
    <category term="catalyst" label="catalyst" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://our.coldhardcode.com/jshirley/">
        <![CDATA[<i>This is a posting about a wiki node on <a href="http://dev.catalystframework.org/wiki/gettingstarted/howtos/WritingComponents">writing Catalyst Components</a> I just wrote up at the <a href="http://dev.catalystframework.org/wiki/">Catalyst wiki</a>, that I hope gets a bit wider views.&nbsp; People often times ignore wikis; less so than blogs anyway.<br /></i><br /><font style="font-size: 1.5625em;"><b>Writing Catalyst Components<br /></b></font><br /><div id="current">  <p>The first step to really working with Catalyst
is to venture out and write your own components. Whether it is a view
or model they share the same common ancestor, which is
Catalyst::Component. Catalyst::Component is an important part of
Catalyst, as it sets up the model, view or controller object. Catalyst
will handle instantiation (calling -&gt;new) as well as calling a setup
method called <code>COMPONENT</code>.  While both of these methods can be overridden, it is better to override <code>COMPONENT</code> if you need to execute code at instantiation time.  </p>

<p><strong>Important Note:</strong> whatever object is returned from <code>COMPONENT</code>, Catalyst treats as the object for that model or view.  This means that if you return a different object from an overridden <code>COMPONENT</code> method, that is what you will get back from calling <code>$c-&gt;model("Foo");</code>.</p>

<p>More on that further down, for now a very simple model class that has default configuration:</p>

<pre><code>package MyApp::Model::Foo;<br /><br />use warnings;<br />use strict;<br /><br /># You must inherit from Catalyst::Model, which in turn inherits from Catalyst::Component<br />use base qw/Catalyst::Model Catalyst::Accessor::Fast/;<br /><br /># Make an accessor for 'foo'.  Inheriting from Catalyst::Accessor::Fast lets us easily do that<br />__PACKAGE__-&gt;mk_accessors('foo');<br /><br /># All Catalyst components have -&gt;config available to them.  This is merged in with the application-level<br /># configuration after instantiation.<br />__PACKAGE__-&gt;config(<br />   'foo' =&gt; 'default foo value'<br />);<br /><br />1;<br /></code></pre>

<p>That's it, that is all that is there for your model to exist.
Catalyst (and friends) handle everything else. If you want to get at
the 'foo' variable, you simply have to use the accessor:</p>

<pre><code>$c-&gt;model("Foo")-&gt;foo; # returns 'default foo value';<br />$c-&gt;model("Foo")-&gt;foo('new value');<br /></code></pre>

<p>It's important to remember that while Catalyst does some abstraction of the mundane code, it is still <strong>just perl</strong>.  That means that if you add a method to the Foo model above, it will be available via <code>$c-&gt;model("Foo")</code>, which as discussed above, is simply an instantiation of MyApp::Model::Foo.</p>

<p>So, to change this, override the <code>COMPONENT</code> method:</p>

<pre><code>package MyApp::Model::Foo;<br /><br />use base 'Catalyst::Model';<br /><br />use External::Module;<br /><br />sub COMPONENT {<br />    my ( $self ) = @_;<br />    return External::Module-&gt;new;<br />}<br /></code></pre>

<p>Now, all calls to <code>$c-&gt;model("Foo")</code> return the
instant of External::Module. Use this wisely, and also sparingly. If
you find yourself binding to external modules, it is highly recommended
to use <a href="http://search.cpan.org/dist/Catalyst-Model-Adaptor/"><strong>Catalyst::Model::Adaptor</strong></a> to do it, rather than writing the code yourself.</p><p><br /></p>
 </div> ]]>
        
    </content>
</entry>

<entry>
    <title>Dear Apple: Please make an external multitouch pad</title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/2008/10/dear-apple-please-make-an-exte.html" />
    <id>tag:our.coldhardcode.com,2008:/jshirley//2.14</id>

    <published>2008-10-23T00:05:37Z</published>
    <updated>2008-10-24T01:11:19Z</updated>

    <summary><![CDATA[I don't think it is unreasonable for Apple to create a multitouch trackpad.&nbsp; Something like the FingerWorks gesture pad, but without the absolutely insane price tag.There's Apple Pricing, and then there is crazy insane pricing.&nbsp; I'll pay for the former.So,...]]></summary>
    <author>
        <name>J. Shirley</name>
        <uri>http://www.coldhardcode.com/</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://our.coldhardcode.com/jshirley/">
        <![CDATA[I don't think it is unreasonable for Apple to create a multitouch trackpad.&nbsp; Something like the FingerWorks gesture pad, but without the absolutely insane price tag.<br /><br />There's Apple Pricing, and then there is crazy insane pricing.&nbsp; I'll pay for the former.<br /><br />So, pretty please with sugar on top, give me a multitouch trackpad that works well and preferably has a larger surface than the MBP.<br /><br />While I'm making <strike>demands</strike>requests, please hurry up and have scriptable gestures on the MBPs.&nbsp; I want to be able to interact with QuickSilver and related software with gestures, as well as better support for multitouch in my apps.<br /><br />Resizing and rotating photos gets old quickly.<br /> ]]>
        
    </content>
</entry>

<entry>
    <title>&quot;Federated Login&quot; evolves to &quot;Contextual Web&quot;</title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/2008/10/federated-login-evolves-to-con.html" />
    <id>tag:our.coldhardcode.com,2008:/jshirley//2.13</id>

    <published>2008-10-04T16:51:59Z</published>
    <updated>2008-10-04T20:49:59Z</updated>

    <summary><![CDATA[Federated Login has been closely examined by so many parties that I'm surprised there isn't a published guide on best practices.&nbsp; There is still so much left to do in the arena that trying to implement a flexible and just...]]></summary>
    <author>
        <name>J. Shirley</name>
        <uri>http://www.coldhardcode.com/</uri>
    </author>
    
    <category term="contextualweb" label="contextual web" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="decentralization" label="decentralization" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="federatedlogin" label="federated login" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="widgets" label="widgets" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://our.coldhardcode.com/jshirley/">
        <![CDATA[Federated Login has been <a href="http://sites.google.com/site/oauthgoog/UXFedLogin">closely examined</a> by so <a href="http://openid.yahoo.com/">many</a> <a href="http://openid.net/">parties</a> that I'm surprised there isn't a published guide on best practices.&nbsp; There is still so much left to do in the arena that trying to implement a flexible and just "better" authentication and signup system gets frustrating.&nbsp; <br /><br />Standing on the shoulders of giants that are pontificating doesn't get you anything but a nosebleed.<br /><br />I have a work (as in, the day job that pays the bills) task to improve cohesion, retention and reduce confusion.&nbsp; Sounds like a job for a more robust login system to me.&nbsp; When I think of a more robust login system, I immediately think of Federated Login and making use of OpenID and other methodologies to increase cohesion.<br /><br />I launched Roostermatic with OpenID support, with the intention of experimenting with some ideas there on a smaller codebase and then hopefully expanding those offerings into a more robust solution for work.&nbsp; The problem is that it isn't quite so analogous as I had hoped.<br /><br />Work has membership ID numbers (to register for most events, you have to purchase a membership), the current legacy identity token is email which isn't so great because amongst non-tech users email changes and they continue to login with their email address.&nbsp; Which isn't valid anymore, because they never told us their new email.<br /><br />What inevitably happens is they simply create a new account and buy a membership, then we lose their history (which is important when dealing with things like racing licenses).<br /><br />This is why I think the dialog that says, quite directly, "Do you already have a password?" helps.&nbsp; Then the option of "No, help me login" makes more sense.&nbsp; However, it doesn't address the point that "identity" is increasingly variable.<br /><br />With OpenID and other auth solutions in the mix (Google Auth, Facebook, etc) now the identity itself becomes confusing.<br /><br />At this point, I think that we're going to see a natural decentralization of web applications and the idea of Federated Login is simply a growing pain in that direction.<br /><br />To clarify what I mean by natural decentralization of web applications is a tendancy to be built using RESTful principles and various APIs, which are then exposed based on context.&nbsp; So, perhaps rather than decentralization think of it more in terms of "<a href="http://blog.hangerhead.com/2008/03/coining-phrase-contextual-web.html">Contextual Web</a> Applications".<br /><br />Now, I do mean something subtly different in the two terms and I'll hope to clarify the distinctions.<br /><br />Decentralization means that the applications themselves are decentralized.&nbsp; You can see this already happening with Dashboard widgets (Google Homepage, etc) and even to a lesser extent with Facebook applications.<br /><br />Applications are context-aware, but even more importantly they're beginning to have different front-ends that talk to the same backends.&nbsp; It's a refinement from a foundational application that doesn't have a user-facing interface.&nbsp; Instead, it has web-services interface that talks to a refinement stack that then serves the application based on context.<br /><br />This is where the Contextual Web meets Decentralization.&nbsp; It is perfectly feasible for an application to join several applications and splice them together based on context.&nbsp; To further the point, I'll bring back my work example.<br /><br />I manage the application stack for an event management and registration system.&nbsp; This handles users who need to purchase a membership, manage their competition licenses, and finally register for events.&nbsp; It also allows the individuals who host the races to setup the race information, scheduling, and specific items.<br /><br />It obviously is a case of a singular application, right?&nbsp; I'm not so sure anymore.&nbsp; Why should our application care about event scheduling?&nbsp; There is a great deal of code that goes into tracking the dates that is pointless.&nbsp; If we stored a reference to another application that handled the scheduling, we would end up with less code and offset a lot of responsibility.&nbsp; The hidden gain is that our events would be broadcasted to a larger audience.<br /><br />The work would be simple, too.&nbsp; Create an event object, which has a relationship to a Google Calendar entry that tracks the dates, stores the location and description.&nbsp; We would have a very simple event object at this point, that only serves as a conduit from our application stack to Google Calendar.&nbsp; And, the next step is tracking the individual racing groups that can be purchased.&nbsp; This is where our application requires explicit trust, since we deal with money.<br /><br />I have, however, reduced our application space down significantly by using a different application to store the scheduling information.<br /><br />This is how I view decentralization.&nbsp; To move on to Contextual Web piece, this is the front-end applications.&nbsp; An application should be aware of who the user is, and through what environment the application is being used.<br /><br />This means that if a user authenticates through Facebook, consider redirecting to a built-in facebook view (if possible).&nbsp; Or, assume a user enters through a Google Calendar link to the site, support Google Auth and attempt to pull in authentication information from Google Auth.&nbsp; All of these things will require action on the end-users part (accepting that the site wants to use OpenID, Facebook Auth, Google Auth, etc) but the experience can be mostly seamless I believe.&nbsp; Especially if context is preserved.&nbsp; Our events don't require our full-fledged application to be used for registration, just that we control the connection.&nbsp; By this, we could have an iframe view inside of Facebook so if a user wants to register for an event a friend has registered for, they could do it without ever leaving Facebook.&nbsp; Only on the users first time inside the application would we require them to associate their membership with their Facebook account, and that check would be simple because we'd just have to ask if they had a membership previously.&nbsp; If they did not, we just add that into the shopping cart and they check out entirely on Facebook.<br /><br />We email them the receipt, they get their purchase history available to them, and we invite them to create a password on the main site.&nbsp; The membership ID number or Facebook authentication mechanism will be associated at the time of creation, or, when they provide their membership number to register for the event.&nbsp; This would, of course, require a change to the registration page to allow them to input (and verify) their membership ID.<br /><br />We do have a bit of an advantage over other sites because our members come to see us in person, so our fraud rates are ridiculously low.&nbsp; People also can't really try anything bad, because our accounting is easily able to be audited and verified.<br /><br />I'm still thinking of how to do these things on more general purpose applications, but I fully believe this is the way forward for web applications.&nbsp; I hope, anyway.<br /><br /><br />]]>
        
    </content>
</entry>

<entry>
    <title>Free Trials Done Wrong</title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/2008/09/free-trials-done-wrong.html" />
    <id>tag:our.coldhardcode.com,2008:/jshirley//2.12</id>

    <published>2008-09-15T16:55:13Z</published>
    <updated>2008-09-15T21:20:22Z</updated>

    <summary><![CDATA[A fairly frequent subject of discussion that comes in blogs and news feeds is&nbsp;piracy.&nbsp; Piracy regarding games, software and justifications, etc.A common response in people justifying piracy is that it is often times easier and better to grab a cracked...]]></summary>
    <author>
        <name>J. Shirley</name>
        <uri>http://www.coldhardcode.com/</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://our.coldhardcode.com/jshirley/">
        <![CDATA[A fairly frequent subject of discussion that comes in blogs and news feeds is&nbsp;piracy.&nbsp; Piracy regarding games, software and justifications, etc.<br /><br />A common response in people justifying piracy is that it is often times easier and better to grab a cracked version than some ridiculously limited and crippled demo version.&nbsp; In this, I wholly agree.<br /><br />I grabbed a piece of software that initially prompted me to register and had a convenient "Not Now" button.&nbsp; I promptly clicked that button, as I'm not going to spend $40 to see if a piece of software works.<br /><br />30 minutes later, it tells me, "Oh, your 30 minutes is up so I'm going to quit now."&nbsp; Application state gone, only option is to buy the product.&nbsp; This is a bad experience.<br /><br />These are the types of behaviors that make it easy to justify pirating software.&nbsp; It's cool to nag.&nbsp; It's cool to have a trial period of the <i>full</i> version (thank you TextMate).&nbsp; The idea of exiting after 30 minutes is ridiculous. <br /><br />So, instead they lost all possibility of ever getting a customer on my end and likely anything else that they do.&nbsp; If they pay such little attention to user experience, it certainly isn't an app I would grow to rely on.<br /><br />Please, if you are working on a desktop application and want to let users try it then do that.&nbsp; Let them try it as if they own it.&nbsp; Just remind them that they don't.&nbsp; Intruding in their work flow is a straight trip to the garbage.<br /><br /><br />]]>
        
    </content>
</entry>

<entry>
    <title>A review of Varnish</title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/2008/09/a-review-of-varnish.html" />
    <id>tag:our.coldhardcode.com,2008:/jshirley//2.11</id>

    <published>2008-09-13T21:35:28Z</published>
    <updated>2008-09-13T21:52:37Z</updated>

    <summary><![CDATA[After several respected peers mentioned Varnish, I decided to give it a try.&nbsp; For reasons that are fairly complex, so here's the story from the top.The way our MogileFS cluster works here (and I'm just about finished with the new...]]></summary>
    <author>
        <name>J. Shirley</name>
        <uri>http://www.coldhardcode.com/</uri>
    </author>
    
    <category term="images" label="images" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="media" label="media" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mogilefs" label="mogilefs" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ucc" label="ucc" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ucm" label="ucm" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="varnish" label="varnish" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://our.coldhardcode.com/jshirley/">
        <![CDATA[After several respected peers mentioned Varnish, I decided to give it a try.&nbsp; For reasons that are fairly complex, so here's the story from the top.<br /><br />The way our MogileFS cluster works here (and I'm just about finished with the new front-end media management code, so stay tuned next week) is quite simple.&nbsp; <br /><br />To start with, when designing it, I threw out the idea that we should pregenerate any of the image sizes/formats.&nbsp; Instead, we simply filter and scale to a max size (configurable, but currently set to 1280x1024) and then we throw out all the meta data (EXIF profiles, etc) that we can.&nbsp; This drastically reduces the size on disk, and then to spit out resized images it doesn't take long (I haven't finished stress testing this yet, but I'll post when I do).<br /><br />So, now I have files stored in the MogileFS cluster that are stripped down versions of the originals.&nbsp; For the sake of simplicity, just think of those as the original (if I were running something like SmugMug, I would store it in the original size, but then extract the meta data into a separate data node).<br /><br />Now, when a request comes in for a media asset, we just enforce it follows a specific convention.&nbsp; In our case, the URL looks like:<br /><blockquote>http://static.cartionary.com/images/{uuid}/{mutations}.{ext}<br /></blockquote>For now, we just serve images, so that part is easy to deal with.&nbsp; The UUID is the unique identifier that we use to store the image and {mutations} is any series of programmatic mutations.<br /><br />If the {uuid} isn't known to the system (the test is if MogileFS knows the key), it returns 404.<br /><br />If it is, the system then parses {mutations}, which can also simply be 'original' and it will return out the original copy (or rather, the raw data stored in MogileFS).&nbsp; Mutations are a format that I've simply concocted to determine rotation, scaling and anything else we can come up with.&nbsp; For example: "s=s" means "size=small" (other sizes are "m", "l", "xl").<br /><br />Combining that upstream with as permanent of a cache as we can gives us better results, because we don't have to generate thumbnails that may never be used.&nbsp; They're generated on demand, and then cached on our proxy for as long as we reasonably can keep them.<br /><br />The reason why I went with Varnish, over lighttpd+mod_cache or Squid, is simply that Varnish (from the varnishcmd command) allows you to purge cached items via regular expression.&nbsp; Which means that if we want to delete an image from the entire cluster we just have to delete it from MogileFS then issue:<br /><blockquote>varnishadm -T :6082 url.purge {uuid}<br /></blockquote>Done!&nbsp; All requests for that UUID will end up as a 404.<br /><br />That's the reason why I picked Varnish over lighttpd+mod_cache and Squid (or, rather to be more specific, picking something that doesn't rely mostly on HTTP PURGE) because we'd have to know every image ever generated (that's a lot).&nbsp; This is also why I decided to do away with the idea of generating permanent thumbnail and other modified images.<br /><br />Every time you need to do some operation, or make some change, you're stuck with however many user contributed images * number of generated images.&nbsp; It's costly, silly, and most of those images will sit dormant except for the occasional .&nbsp; CPU time is really <i>really</i> cheap. Disk space, too.&nbsp; So make your caching huge and your media cluster fast.<br /><br />The decision really comes down to the fact that I'd rather have the CPU deal with on-demand requests, and have the user have to wait an extra second or two, then have a developer have to get "creative".&nbsp; The reality of it is that a user, in most cases, won't have to wait.<br /><br />When an image is uploaded, have a job (or preload it in the resulting HTML displayed to the user) that asks the caching cluster for the expected image sizes (small, medium, large) and then they're saved until the cluster runs out of disk space, then the least recently used items fall off and won't be missed.<br /><br />I'm happy to be building this system in a day and age where I can make that decision and expect it to work out well.&nbsp; I've dealt with two other high traffic photo-centric organizations, and I experienced the pain of not doing it this way.<br /><br />I'm eager to experience the pain of doing it my way now.<br />]]>
        
    </content>
</entry>

<entry>
    <title>Using the right tool for the job</title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/2008/09/using-the-right-tool-for-the-j.html" />
    <id>tag:our.coldhardcode.com,2008:/jshirley//2.10</id>

    <published>2008-09-04T22:01:14Z</published>
    <updated>2008-09-04T22:01:14Z</updated>

    <summary>If you haven&apos;t read Zed Shaw&apos;s C2I2 Hypothesis, you should really do so now.&#160; I mean it, go read it.&#160; I&apos;d like you to come back here but if you don&apos;t that&apos;s ok, I&apos;ll understand. The main gist is properly...</summary>
    <author>
        <name>J. Shirley</name>
        <uri>http://www.coldhardcode.com/</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://our.coldhardcode.com/jshirley/">
        <![CDATA[<p>If you haven't read Zed Shaw's <a href="http://www.zedshaw.com/essays/c2i2_hypothesis.html" target="_blank">C2I2 Hypothesis</a>, you should really do so now.&#160; I mean it, go read it.&#160; I'd like you to come back here but if you don't that's ok, I'll understand.</p>  <p>The main gist is properly identifying just what type of person you are working with, and to a more significant degree, what type of person you are (which is variable).&#160; I have my own thoughts on the specifics that he lists that I'll likely write up later, but for now just reading it is a good start to continue my current thoughts.</p>  <p>I think that it equally important to understand the tools you are using. It seems a lot of people use a specific tool because they don't really think about other tools. If a problem looks like a nail, they use a hammer.&#160; While I hate metaphors when they're not necessary, I think using the nail/hammer metaphor does work for this case.</p>  <p>What ends up happening is the, &quot;When all you have is a hammer, every problem looks like a nail.&quot; syndrome.&#160; Conversely, if you have a vast array of tools at your disposal, you are going to over-complicate problems.&#160; There is a very important balance that must be maintained.</p>  <p>If I had to pick over-engineering a problem, versus simply driving a nail in a plank of wood and calling it a deck, I'd over-engineer it every time. This is coming from years of experience, and several contracts that seemed to extend in two-week intervals where I was expecting to find another gig every two weeks.&#160; One of those went for 2 years, adding two-weeks worth of &quot;enhancements&quot;. It was all hammer and planks of wood. Absolutely terrible.</p>  <p>The reason why I'm writing this is because a discussion popped up where I expressed my confusion in people using plain vanilla mod_perl, then being frustrated with testability and other nuances. Someone pointed out that mod_perl is a perl runtime inside of Apache that gives you programmatic hooks into Apache.</p>  <p>Fantastic.&#160; However, that doesn't enter into what my point was.&#160; People use mod_perl because that is the only tool they know.&#160; I believe this is the case with most PHP-based engineering shops.&#160; They use PHP because that is the tool they, or the managers, know.</p>  <p>The problem with this mentality is that by not knowing the tools, you are doomed to work within the confines of what you know.&#160; While the skillset and knowledge may evolve, it won't have a renaissance or giant evolutionary leap.</p>  <p>This is the key reason for learning other toolsets and libraries that are available.&#160; It isn't about jumping to trendy and shiny technology, it is about defining your own capabilities in relative scope to what other technology is around.</p>  <p>It's very easy to spot this type of individual, which I view as a blessing.&#160; If a person ever argues against a tool (or rather, using a tool in place of something that they know) you can count on them being very limited in their ability to accurately scope and understand a problem.&#160; They will mutate the problem to be solved with the tools at their disposal.</p>  <p>In context of Zed's C2I2 hypothesis, I've been struggling to really distinguish between a collaborator and an implementer.&#160; They were very much the same in my mind.&#160; Thinking about the usage and understanding of tools has helped clear this up for me.</p>  <p>A collaborator doesn't know the details of the tools.&#160; They follow cookbook recipes.&#160; Contrast that to an implementer, who still follows cookbook recipes but understands the tools that are being used.</p>  <p>The inventor, of course, usually is the one building the tools.&#160; If a tool doesn't fit an implementers agenda, they'll either move on or smash at it until it works.&#160; An inventor will go in and fix the tool.&#160; A collaborator will be that guy on the mailing list you wish would go away, and probably be the first in line to argue against other tools they've never used.</p>]]>
        
    </content>
</entry>

<entry>
    <title>A kind word for github</title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/2008/08/a-kind-word-for-github.html" />
    <id>tag:our.coldhardcode.com,2008:/jshirley//2.9</id>

    <published>2008-09-01T00:01:39Z</published>
    <updated>2008-09-01T00:27:16Z</updated>

    <summary>You know a project is successful and well built when you get people trying a product simply because some additional accessory is built around it.Imagine buying a computer because the case was that good.A car because the seats were so...</summary>
    <author>
        <name>J. Shirley</name>
        <uri>http://www.coldhardcode.com/</uri>
    </author>
    
    <category term="git" label="git" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="goodsoftware" label="good software" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://our.coldhardcode.com/jshirley/">
        <![CDATA[You know a project is successful and well built when you get people trying a product simply because some additional accessory is built around it.<br /><br />Imagine buying a computer because the case was <i>that good</i>.<br /><br />A car because the seats were <i>so comfortable<br /></i><br />That, precisely, is what <a href="http://github.com/">github</a> is. <a href="http://git.or.cz/">Git</a> is fantastic software, sound engineering principles went into it and it works very well. I still use subversion+svk for nearly everything, because that is just what most places use and I'll never be able to get away from that software.<br /><br /><a href="http://github.com/">Github</a> just makes me wish I could.&nbsp; It is excellent work, astoundingly simple and put together very well.<br /><br /> ]]>
        
    </content>
</entry>

<entry>
    <title>A hesitant plug...</title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/2008/08/a-hesitant-plug.html" />
    <id>tag:our.coldhardcode.com,2008:/jshirley//2.7</id>

    <published>2008-08-19T01:57:11Z</published>
    <updated>2008-08-19T01:57:11Z</updated>

    <summary>After Rick Segal mentioned Windows Live Writer, I figured that I had nothing to lose if I gave it a try. The problem with that thought is that I did have something to lose. And lose it I did. I...</summary>
    <author>
        <name>J. Shirley</name>
        <uri>http://www.coldhardcode.com/</uri>
    </author>
    
    
    <content type="html" xml:lang="en-us" xml:base="http://our.coldhardcode.com/jshirley/">
        <![CDATA[<p>After <a href="http://ricksegal.typepad.com" target="_blank">Rick Segal</a> mentioned Windows Live Writer, I figured that I had nothing to lose if I gave it a try.</p>  <p>The problem with that thought is that I did have something to lose. And lose it I did. I lost my belief that Microsoft couldn't produce a program that is worse than any other alternative.</p>  <p>I don't like to unnecessarily hate on Microsoft, but I find their products to be absolutely terrible when compared with sufficiently advanced alternatives. In the case of Windows Live Writer, there is no alternative.</p>  <p>A few folks have pointed out Mars Edit and other offerings (on OS X, as that is my platform of choice currently) but they really aren't as good as Live Writer.&#160; Even under Linux I couldn't find anything that is just better than Live Writer.</p>  <p>It still isn't perfect, but it works extremely well. Now my only hope is that Microsoft will lose something... the irritating need to bundle a staggeringly large amount of irrelevant software with Live Writer. Until they do that, I don't think I can recommend Live Writer to people who won't just blindly click &quot;Continue&quot; without seeing what other crap they're installing. If you do read before clicking, definitely check it out.</p>  <p>It seems to be working fantastically with Movable Type 4, but I still need to figure out how to manage static pages.</p>]]>
        
    </content>
</entry>

<entry>
    <title>An experiment in transparency</title>
    <link rel="alternate" type="text/html" href="http://our.coldhardcode.com/jshirley/2008/08/an-experiment-in-transparency.html" />
    <id>tag:our.coldhardcode.com,2008:/jshirley//2.6</id>

    <published>2008-08-18T20:28:42Z</published>
    <updated>2008-08-18T20:31:55Z</updated>

    <summary><![CDATA[I am finding it hard to stay on target, but I'm still getting stuff done.&nbsp; This is mostly exhibited by my attention to the examples area.&nbsp; It's a distraction, but I think it has value.&nbsp; I really need to close...]]></summary>
    <author>
        <name>J. Shirley</name>
        <uri>http://www.coldhardcode.com/</uri>
    </author>
    
        <category term="worklog" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="worklog" label="worklog" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-us" xml:base="http://our.coldhardcode.com/jshirley/">
        <![CDATA[I am finding it hard to stay on target, but I'm still getting stuff done.&nbsp; This is mostly exhibited by my attention to the <a href="http://our.coldhardcode.com/jshirley/examples/testing.html">examples area</a>.&nbsp; It's a distraction, but I think it has value.&nbsp; I really need to close the loop on the remaining work on Cartionary to launch the "full" version of it so we can start to generate some buzz and get some actual users on the site.<br /><br />For now, this will be where I let everybody know exactly what I'm getting done (or not getting done).<br /><br />Public shaming should work, right?<br /> ]]>
        
    </content>
</entry>

</feed>
