<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Pat Maddox, B.D.D.M.F.]]></title>
  <link href="http://patmaddox.com/atom.xml" rel="self"/>
  <link href="http://patmaddox.com/"/>
  <updated>2012-01-27T13:53:40-08:00</updated>
  <id>http://patmaddox.com/</id>
  <author>
    <name><![CDATA[Pat Maddox]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Some Resources for People Who Want to Learn Smalltalk]]></title>
    <link href="http://patmaddox.com/blog/some-resources-for-people-who-want-to-learn-smalltalk.html"/>
    <updated>2011-12-19T11:59:00-08:00</updated>
    <id>http://patmaddox.com/blog/some-resources-for-people-who-want-to-learn-smalltalk</id>
    <content type="html"><![CDATA[<p>If you want to learn Smalltalk, you can get started easily. First head over to <a href="http://amber-lang.net/learn.html">Learn Smalltalk with ProfStef</a> where you can learn Smalltalk syntax in about five minutes using <a href="http://amber-lang.net/">Amber Smalltalk</a>, a Smalltalk that runs in your browser via Javascript.</p>

<p>I&#8217;ve had a lot of fun using Amber and find that it makes me super productive when writing Javascript applications. It&#8217;s young though, and has quirks, and the environment lacks some flexibility that more mature implementations have. If you want the full Smalltalk experience, you&#8217;ll want to check out <a href="http://www.pharo-project.org/home">Pharo Open Source Smalltalk</a>. Click on the big &#8220;Download Pharo&#8221; button to get a one-click package that includes a Pharo image and a VM for your platform. The image contains everything you need to write and explore Smalltalk applications – code browsers, refactoring tools, a test runner, object inspectors, workspaces for running snippets of code, version control, and more.</p>

<p>When you start exploring the image you&#8217;ll find lots and lots and lots of Smalltalk. Unlike other programming languages and environments you might be used to, Pharo doesn&#8217;t make a strong distinction between your code and platform code. Everything lives and runs under the same image, and you have access to all of the source code. If you want to understand how the automated extract method refactoring tool works, you can pull up the RBExtractMethodRefactoring class to see the exact steps it takes to perform the refactoring. If you didn&#8217;t know that extract method functionality lives in the RBExtractMethodRefactoring class (as I didn&#8217;t), you can simply inspect the menu item and find out which smalltalk method gets triggered when you select that menu item. Pretty neat.</p>

<p>You can learn a ton from simply digging into Pharo&#8217;s guts. It has a lot of guts though, and you probably have never used a system like Pharo before. The following links should help you make sense of it:</p>

<ul>
<li><a href="http://pharobyexample.org/">Pharo by Example</a> - free book that you can read online or download as PDF. This was my primary resource for learning Pharo</li>
<li><a href="http://book.pharo-project.org/">Pharo - the collaborActive book: Home</a> - another great book, entirely online (I think), and probably more up to date than PBE</li>
<li><a href="http://book.seaside.st/book">Dynamic Web Development with Seaside</a> - an introductory book to Seaside, the continuations-based web framework in Pharo. Also probably a bit out of date, but great for learning Seaside</li>
<li><a href="http://www.pharocasts.com/">Pharocasts</a> - a set of screencasts that goes into some of Pharo&#8217;s interesting nooks and crannies</li>
<li><a href="http://stephane.ducasse.free.fr/FreeBooks.html">Stéphane Ducasse :: Free Online Books</a> - a list of free Smalltalk books for download. Many of them are old. I&#8217;ve only read a few of them. Definitely worth looking into.</li>
</ul>


<p>You can find all of these links via the Pharo home page, but I figured people would find it useful to have everything on one page. I&#8217;ll update this post as I think about and discover new resources for learning Smalltalk.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Backbone.js Testing Pattern - Describe a View's First Render]]></title>
    <link href="http://patmaddox.com/blog/backbone-dot-js-testing-pattern-describe-a-views-first-render.html"/>
    <updated>2011-10-28T12:02:00-07:00</updated>
    <id>http://patmaddox.com/blog/backbone-dot-js-testing-pattern-describe-a-views-first-render</id>
    <content type="html"><![CDATA[<p>While testing my backbone.js views, I’ve come up with a few conventions to keep my tests neatly organized. The first is to have a single describe block to specify what the view looks like when it first renders. This tests the view’s rendering logic and establishes the foundation for the rest of my examples. Here’s a brief example. I have a view which renders a person’s name and adds a CSS class if the person is a minor. Pretty simple. There are three things I’m interested in when testing the first render:</p>

<ul>
<li>show the name</li>
<li>no CSS class if person is over 18</li>
<li>special CSS class if person is under 18</li>
</ul>


<p>Here’s the view spec:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='coffeescript'><span class='line'><span class="nx">describe</span> <span class="nx">PersonView</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>  <span class="nx">describe</span> <span class="s2">&quot;first render&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>    <span class="nx">beforeEach</span> <span class="o">-&gt;</span>
</span><span class='line'>      <span class="vi">@model = </span><span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="nv">name: </span><span class="s1">&#39;Joe&#39;</span><span class="p">)</span>
</span><span class='line'>      <span class="vi">@view = </span><span class="k">new</span> <span class="nx">PersonView</span><span class="p">(</span><span class="nv">model: </span><span class="nx">@model</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="nx">it</span> <span class="s2">&quot;shows the name in an h2&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>      <span class="nx">expect</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="nx">@view</span><span class="p">.</span><span class="nx">render</span><span class="p">().</span><span class="nx">el</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;h2&#39;</span><span class="p">).</span><span class="nx">text</span><span class="p">()).</span><span class="nx">toEqual</span><span class="p">(</span><span class="s1">&#39;Joe&#39;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="nx">it</span> <span class="s2">&quot;does not add the &#39;minor&#39; class to the h2 if person is not a minor&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>      <span class="nx">@model</span><span class="p">.</span><span class="nx">set</span> <span class="nv">age: </span><span class="mi">18</span>
</span><span class='line'>      <span class="nx">expect</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="nx">@view</span><span class="p">.</span><span class="nx">render</span><span class="p">().</span><span class="nx">el</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;h2&#39;</span><span class="p">).</span><span class="nx">hasClass</span><span class="p">(</span><span class="s1">&#39;minor&#39;</span><span class="p">)).</span><span class="nx">toBe</span><span class="p">(</span><span class="kc">false</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="nx">it</span> <span class="s2">&quot;adds the &#39;minor&#39; class to the h2 if person is a minor&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>      <span class="nx">@model</span><span class="p">.</span><span class="nx">set</span> <span class="nv">age: </span><span class="mi">17</span>
</span><span class='line'>      <span class="nx">expect</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="nx">@view</span><span class="p">.</span><span class="nx">render</span><span class="p">().</span><span class="nx">el</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;h2&#39;</span><span class="p">).</span><span class="nx">hasClass</span><span class="p">(</span><span class="s1">&#39;minor&#39;</span><span class="p">)).</span><span class="nx">toBe</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>And now the view that makes this work:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='coffeescript'><span class='line'><span class="k">class</span> <span class="nb">window</span><span class="p">.</span><span class="nx">PersonView</span> <span class="k">extends</span> <span class="nx">Backbone</span><span class="p">.</span><span class="nx">View</span>
</span><span class='line'>  <span class="nv">initialize: </span><span class="o">-&gt;</span>
</span><span class='line'>    <span class="vi">@template = </span><span class="nx">_</span><span class="p">.</span><span class="nx">template</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;person-view-template&#39;</span><span class="p">).</span><span class="nx">html</span><span class="p">())</span>
</span><span class='line'>
</span><span class='line'>  <span class="nv">render: </span><span class="o">-&gt;</span>
</span><span class='line'>    <span class="nx">$</span><span class="p">(</span><span class="nx">@el</span><span class="p">).</span><span class="nx">html</span><span class="p">(</span><span class="nx">@template</span><span class="p">(</span><span class="nv">model: </span><span class="nx">@model</span><span class="p">))</span>
</span><span class='line'>    <span class="nx">$</span><span class="p">(</span><span class="nx">@el</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;h2&#39;</span><span class="p">).</span><span class="nx">addClass</span><span class="p">(</span><span class="s1">&#39;minor&#39;</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@model</span><span class="p">.</span><span class="nx">isMinor</span><span class="p">()</span>
</span><span class='line'>    <span class="k">this</span>
</span></code></pre></td></tr></table></div></figure>


<p>It uses this super simple template:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;script </span><span class="na">type=</span><span class="s">&quot;text/template&quot;</span> <span class="na">id=</span><span class="s">&quot;person-template&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  <span class="o">&lt;</span><span class="nx">div</span> <span class="kr">class</span><span class="o">=</span><span class="s2">&quot;person&quot;</span><span class="o">&gt;</span>
</span><span class='line'>    <span class="o">&lt;</span><span class="nx">h2</span><span class="o">&gt;</span> <span class="p">{{</span> <span class="nx">model</span><span class="p">.</span><span class="nx">name</span><span class="p">()</span> <span class="p">}}</span> <span class="o">&lt;</span><span class="err">/h2&gt;</span>
</span><span class='line'>  <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span><span class='line'><span class="nt">&lt;/script&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>If the view logic is complex I may separate the conditions into separate describe blocks, like this:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
</pre></td><td class='code'><pre><code class='coffeescript'><span class='line'><span class="nx">describe</span> <span class="nx">PersonView</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>  <span class="nx">describe</span> <span class="s2">&quot;first render&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>    <span class="nx">beforeEach</span> <span class="o">-&gt;</span>
</span><span class='line'>      <span class="vi">@model = </span><span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="nv">name: </span><span class="s1">&#39;Joe&#39;</span><span class="p">)</span>
</span><span class='line'>      <span class="vi">@view = </span><span class="k">new</span> <span class="nx">PersonView</span><span class="p">(</span><span class="nv">model: </span><span class="nx">@model</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="nx">describe</span> <span class="s2">&quot;person is not a minor&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>      <span class="nx">beforeEach</span> <span class="o">-&gt;</span>
</span><span class='line'>        <span class="nx">@model</span><span class="p">.</span><span class="nx">set</span> <span class="nv">age: </span><span class="mi">18</span>
</span><span class='line'>
</span><span class='line'>      <span class="nx">it</span> <span class="s2">&quot;shows the name in an h2&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>        <span class="nx">expect</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="nx">@view</span><span class="p">.</span><span class="nx">render</span><span class="p">().</span><span class="nx">el</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;h2&#39;</span><span class="p">).</span><span class="nx">text</span><span class="p">()).</span><span class="nx">toEqual</span><span class="p">(</span><span class="s1">&#39;Joe&#39;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>      <span class="nx">it</span> <span class="s2">&quot;does not add the &#39;minor&#39; class to the h2&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>        <span class="nx">expect</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="nx">@view</span><span class="p">.</span><span class="nx">render</span><span class="p">().</span><span class="nx">el</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;h2&#39;</span><span class="p">).</span><span class="nx">hasClass</span><span class="p">(</span><span class="s1">&#39;minor&#39;</span><span class="p">)).</span><span class="nx">toBe</span><span class="p">(</span><span class="kc">false</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="nx">describe</span> <span class="s2">&quot;person is a minor&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>      <span class="nx">beforeEach</span> <span class="o">-&gt;</span>
</span><span class='line'>        <span class="nx">@model</span><span class="p">.</span><span class="nx">set</span> <span class="nv">age: </span><span class="mi">17</span>
</span><span class='line'>
</span><span class='line'>      <span class="nx">it</span> <span class="s2">&quot;shows the name in an h2&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>        <span class="nx">expect</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="nx">@view</span><span class="p">.</span><span class="nx">render</span><span class="p">().</span><span class="nx">el</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;h2&#39;</span><span class="p">).</span><span class="nx">text</span><span class="p">()).</span><span class="nx">toEqual</span><span class="p">(</span><span class="s1">&#39;Joe&#39;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>      <span class="nx">it</span> <span class="s2">&quot;adds the &#39;minor&#39; class to the h2&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
</span><span class='line'>        <span class="nx">expect</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="nx">@view</span><span class="p">.</span><span class="nx">render</span><span class="p">().</span><span class="nx">el</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;h2&#39;</span><span class="p">).</span><span class="nx">hasClass</span><span class="p">(</span><span class="s1">&#39;minor&#39;</span><span class="p">)).</span><span class="nx">toBe</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>With these tests in place, I can start testing the events. Details on that will be in a future post.</p>

<p><a href="https://plus.google.com/112228256605539819719/posts/hyfjhquWfjS">Join the discussion on Google+</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The UX Problem That Sites Leave Unsolved]]></title>
    <link href="http://patmaddox.com/blog/the-ux-problem-that-sites-leave-unsolved.html"/>
    <updated>2011-10-27T14:40:00-07:00</updated>
    <id>http://patmaddox.com/blog/the-ux-problem-that-sites-leave-unsolved</id>
    <content type="html"><![CDATA[<p>Most sites give you basic account management. GitHub’s organizations allow multiple people to administer an account and manage projects within it. When nobody pays the bills, GitHub lets you know. They put up this big banner alerting all project admins that the private repositories are frozen until you update the credit card.</p>

<p><img src="http://patmaddox.com/images/ux-problem/github-billing-error-message.jpg" title="GitHub’s billing error message" ></p>

<p>Fair enough. I’m not going to solve this billing problem though. The account belongs to someone I worked with a while back who added me to the repository. If they want to address it, they will. In the mean time, I would like to get rid of that banner. After clicking around I found myself on the owners team page where I can add and remove owners.</p>

<p><img src="http://patmaddox.com/images/ux-problem/github-owners-team.jpg" title="GitHub organizations owners team" ></p>

<p>The page gives me all the controls I could ask for&#8230;except one. I can’t remove myself from the owners team! I can kick out anyone else, or add anyone else, but I can’t walk away. I have to ask someone else to kick me out, whether that’s someone else on the team or GitHub support.</p>

<p>Fortunately GitHub’s design is nice and all it takes is one little tweak:</p>

<p><img src="http://patmaddox.com/images/ux-problem/github-owners-team-fixed.jpg" title="My tweak to GitHub’s UI" ></p>

<p>Too subtle?</p>

<p><img src="http://patmaddox.com/images/ux-problem/github-owners-team-fixed-bam.jpg" title="In ya face" ></p>

<p>I’m not really picking on GitHub here. I imagine they will address this or have a good reason not to. I’m simply using it as one real-world example of an important interaction that many UX designers skip over.</p>

<p>Here’s one from Google Analytics. Someone else created and added me to this mystery account three years ago, and as far as I know no longer checks his email for that account.</p>

<p><img src="http://patmaddox.com/images/ux-problem/google-analytics.jpg" title="Google Analytics account page" ></p>

<p>This case is a bit different. I can modify accounts that I’ve created, and I can view stats for an account that someone else shared with me, but I can’ t remove the account from my list.</p>

<p>Just something to keep in mind for those of you developing group functionality in your product. If someone can join or be added to a group, ensure that they have the power to leave, too.</p>

<p><a href="https://plus.google.com/112228256605539819719/posts/jAKX8FF64D5">Join the discussion on Google+</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Hidden Agile Value: Respect]]></title>
    <link href="http://patmaddox.com/blog/the-hidden-agile-value-respect.html"/>
    <updated>2011-10-12T08:39:00-07:00</updated>
    <id>http://patmaddox.com/blog/the-hidden-agile-value-respect</id>
    <content type="html"><![CDATA[<p>Reading the agile manifesto, you won&#8217;t come across the word &#8220;respect,&#8221; but when I read it it’s clear to me that respect is an underlying theme. This dawned on me while having a conversation with my brother&#8217;s girlfriend, Cortni. Cornti is a dental hygienist who practices at a private dental office. Her office manages all of the patients&#8217; dental records via old-school paper files. A few months ago, Cortni asked me what it would take to build software to replace the office&#8217;s existing paper system. She promised to bring me some example records to give me an idea of what she needed to enter into a patient&#8217;s file on a day-to-day basis. We spent about an hour talking about her interactions with her patients, the information she recorded, the frustrations she had with her existing system, and her vision of a software-based system that would solve her problems. At the end of it I must admit I was terrified for my own dental health, having learned of the whole slew of messy, painful dental problems a hygienist looks for and addresses. During that conversation, I learned a lot about how a dental office works, but I was also made painfully aware of just how much I don&#8217;t know about that profession.</p>

<p>We went to lunch and I briefly told her a bit about agile software development, although I never used the term agile. Our convo about agile went like this:</p>

<p>Me: So to overgeneralize, there are two basic approaches to building software. The first is where you and I sit down and talk about everything that I would possibly need to build, and then I go off and build it all, and show it to you when I’m done. In the second way, I&#8217;d build a tiny piece and show it to you, and then figure out what&#8217;s right or wrong about it, and keep building little pieces, getting feedback from you along the way.</p>

<p>Cortni: Hrm&#8230;I think we should do it the second way. I don&#8217;t think the first way would work very well.</p>

<p>Now to give you a bit more background on Cortni, she&#8217;s not what you would call an Agile champion. In fact, she&#8217;s never been involved in any sort of software project, or even in a company that builds software. She grew up on a horse farm in Colorado, roughly 15 minutes away from the nearest town of 1,000 people, and went to dental hygienist school because she &#8220;heard they get paid well and make their own hours.&#8221; That&#8217;s why I found it so amusing that she immediately and intuitively felt that an agile approach to software development might work, whereas a BDUF approach definitely wouldn&#8217;t. Yet that should come as no surprise. She spent three years in school just to get started in her profession. How gauche would it be of me to think that I can write software for her after one conversation, and get it right? How many conversations would we need to have before I could get it right? I don’t think it matters. There’s no way that I can do my job unless I get regular feedback from her on how I’m doing.</p>

<p>Whenever we try to build software, we have to be respectful of all people involved. The first point of the agile manifesto is that software creation is a human act &#8211; performed by imperfect beings in order to solve problems for other imperfect beings. We can respect this first at the team level. Software makers should be held in higher regard than a process you found in a book or learned in a workshop. Process can be instrumental in getting software out the door and enabling a team to continually improve itself and its product, but the moment you honor the process element over the human element, you&#8217;ve missed the point and will only cause your organization harm in the long run.</p>

<p>Respect should extend beyond the software team to the customers and users (which are sometimes a part of the software team, sometimes not, and are often ill-defined, mis-construed, or simply unknown). When developing software for a professional industry like dentistry, it should be obvious that practitioners are highly skilled and that your understanding of their work will always pale in comparison to theirs, even though you can develop sufficient enough understaning to build useful software for them. That’s why we call them &#8220;domain experts,&#8221; and their insight and feedback are critical to the success of a software project of this sort.</p>

<p>Another thing to consider is that not all software is built for skilled professionals. A lot of it is built for internal use by massive organizations whose employees have no choice but to use it. Without addressing the issue of how humane or inhumane it is to force software on a large group of people, it&#8217;s important that we as developers understand that we are partially responsible for the quality of worklife experience that these people have on a regular basis. It&#8217;s difficult for me to express this without sounding like I&#8217;m preaching, but basically we should just try to be aware that some of the software we build will be used by people who have no choice but to use it, other than giving up their jobs.</p>

<p>I have a lot more to say about this subject, but I think this is enough for now. If this resonated with you at all, I would like you to keep the principle of respect at the forefront of your mind today.</p>

<p><a href='https://plus.google.com/112228256605539819719/posts/HSgnoWVaiDL'>Join the discussion on Google+</a></p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How a Coding Obsession Killed My Startup]]></title>
    <link href="http://patmaddox.com/blog/how-a-coding-obsession-killed-my-startup.html"/>
    <updated>2011-08-19T00:00:00-07:00</updated>
    <id>http://patmaddox.com/blog/how-a-coding-obsession-killed-my-startup</id>
    <content type="html"><![CDATA[		<p>When I was 20 years old, I built a web site that earned over $2500/mo and required about three hours a week of support and maintenance. Damn good money for a kid whose rent was $300/mo. I made two huge mistakes that ended up costing me that creampuff income stream.</p><h2>I only did what I knew, instead of learning something new</h2><p>I didn&#8217;t even set out to build a business at first. All I did was write a little program to help me get better at poker. A friend of mine suggested that I turn it into a web site for other people to use, so I did. It took about three weeks of programming on my part, and I paid $200 for custom images to use.</p><p>At first it was great. I had a bit of a reputation on an internet poker forum, so when I launched the product I quickly received a lot of signups. After a few months, the signups started slowing down. So I did the only thing that I thought would bring in more signups - I lowered the price. All that did was cause most of my existing customers to cancel their plan, and not everyone signed up again at the lower rate.</p><p>If I could do it over again, I would have doubled the price for new customers. That way I would make just as much money with half of the signups! More importantly, it would create a sense of urgency for customers. I would have put out an announcement saying that the price would go up in a week, which I suspect would drive some new customers who want to get in at the low rate. And later on, customers would see that the price was increasing over time, so they&#8217;d know that they should sign up quick otherwise it might go up again. Lastly, my existing customers would be more likely to stick around, knowing that if they bailed they would never be able to get that low price again.</p><h2>I sold it</h2><p>This one&#8217;s easy. If you sell a recurring revenue generator for a pile of cash, you end up with a pile of cash and no recurring revenue. I could have bought another revenue generating product, or lived off the cash while I built something else, but instead I bought a fancy car. I was pretty smart for a 20 year-old, but obviously not *that* smart.</p><p>Why&#8217;d I sell it? Because I wanted a fancy car ;)  But mostly because I didn&#8217;t know how to build a business, and I didn&#8217;t even really want to. I just wanted to code. So instead of learning how to build a business, I sold it off to someone else who would.</p><p>It pains me a bit to look back on this and think what it might have become had I stuck with it. But there&#8217;s no way to change it now. The good news is, today I&#8217;m just as interested in the business side of things as I am the coding, and I learned a lot from that first experience. Now I&#8217;ve got the motivation to stick with it and to learn how to grow a business. And next time I won&#8217;t be quite so willing to give up something that makes money while I sleep.</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Agile 2011 trip report]]></title>
    <link href="http://patmaddox.com/blog/agile-2011-trip-report.html"/>
    <updated>2011-08-17T00:00:00-07:00</updated>
    <id>http://patmaddox.com/blog/agile-2011-trip-report</id>
    <content type="html"><![CDATA[		<p>I had the good fortune to attend Agile 2011 in Salt Lake City, where I got to help <a href="http://lunivore.com/">Liz Keogh</a> run her <a href="http://blog.dannorth.net/2010/08/30/introducing-deliberate-discovery/">deliberate discovery</a> workshop. She is brilliant and had a few evil tricks up her sleeve for the workshop, and I think the attendees came away from it excited to dig deeper. I know I’m going to be experimenting more and more with deliberate discovery in the coming months.</p><p>The rest of the conference was pretty great. AgileConf is a weird one for me because it’s so damn big. It’s an industry conference, not a community conference. The exhibit hall is insane (largely due to the sheer amount of shitty-looking project management software on offer). But the catered lunches were delicious (the Grand America Hotel in SLC has amaaaaazing bread pudding), and people that woke up early enough told me that the breakfasts were too.</p><p>There were a lot of great sessions, but my favorite had to be <a href="http://testobsessed.com/">Elizabeth Hendrickson’s</a> tutorial workshop on Exploratory Testing. I walked in to find people hunched over electronic Scrabble games, and Elisabeth had written a test charter to guide people on how to explore them. I didn’t write it down but it was something like “Explore electronic scrabble with the stuff in the box to discover how it works.” In the next round we learned to be more systematic in what to look for, like how to identify variables in the system under test. We didn’t get to do the third round because we spent a good amount of time in conversation between rounds. Elisabeth is extremely knowledgeable and was able to handle any question that people threw at her, and I also love that she invites other people from the audience to answer. She’s great at imparting the information, but also amazing at turning it into a comfortable conversation rather than it feeling like a formal classroom setting.</p><p>I also enjoyed <a href="http://twitter.com/#!/hackerchick">@hackerchick’s</a> talk on Lean Startup and Agile. If you’ve read any of the <a href="http://www.amazon.com/Four-Steps-Epiphany-Steven-Blank/dp/0976470705">books</a> or <a href="http://www.ashmaurya.com/2010/09/lean-startup-is-a-rigorous-process/">articles</a> on Lean Startup, you probably knew most of what she was talking about. But she covered the gamut for people who aren’t all that familiar, and brought stories and excitement to the table to boot.</p><p>As always, the best part of the conference was meeting people. I got to hang out with my <a href="http://addcasts.com/">ADDcasts</a> partner-in-crime, <a href="http://heartmindcode.com/">Dave Brady</a>, and we recorded an episode with <a href="http://twitter.com/mfeathers">Michael Feathers</a>. We also kicked back in high-back chairs and pair programming Smalltalk on a 12-foot projector. Good times. I got to meet <a href="http://agileotter.blogspot.com/">Tim Ottinger</a> who told me about his experiences watching the internet unfold before his eyes. It was also great fun meeting ADDcasts listeners like <a href="http://twitter.com/trptcolin">Colin Jones</a> and <a href="http://twitter.com/davidadsit">David Adsit</a>. And of course there was that time when I sat down next to <a href="http://twitter.com/garybernhardt">Gary Bernhardt</a> for 10 seconds and got up to grab food and look for Gary Bernhardt.</p><p>AgileConf is huge, which brings a bunch of lame stuff but also draws a huge number of super awesome people in. I’m looking forward to next year, and I’ll definitely track down folks that I didn’t manage to meet this year.</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Help me help you]]></title>
    <link href="http://patmaddox.com/blog/help-me-help-you.html"/>
    <updated>2011-08-15T00:00:00-07:00</updated>
    <id>http://patmaddox.com/blog/help-me-help-you</id>
    <content type="html"><![CDATA[		<p>I want to create an information product based on my programming expertise. I don&#8217;t know yet what the topic(s) will be, or if it&#8217;ll come via articles or video or some combination, but I know it will include lots and lots of code. I would appreciate it if you would take a few minutes to <a href="http://www.surveymonkey.com/s/3VL797Q">respond to this four-question survey</a> I made up, to get a better feel for what people would find interesting and valuable.</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A little bit of CoffeeScript]]></title>
    <link href="http://patmaddox.com/blog/a-little-bit-of-coffeescript.html"/>
    <updated>2011-08-15T00:00:00-07:00</updated>
    <id>http://patmaddox.com/blog/a-little-bit-of-coffeescript</id>
    <content type="html"><![CDATA[		<p>Alright so I wrote my first program in CoffeeScript. It&#8217;s my first pass at a blackjack simulator. My thoughts:</p><ul>
<li> Syntax is quick and easy to learn, and fun to use.</li><li> I love the function definition syntax. Love love love.</li><li> Same goes for re-opening classes.</li><li> Scoping can be tricky when passing functions around, but it allows for a lot of power.</li><li> For loops are ugly</li><li> I need to learn how to do operator overloading</li><li> JavaScript is missing a lot of stuff. Need to figure out the ActiveSupport equivalent for JS.</li>
</ul>
<p>All told it only took me a couple hours to skim through the PragProg CoffeeScript book and hack this up. It went fast and I was pleased with how easily I was able to refactor the code as I built it up. Next I&#8217;m going to mess around with adding browser-side features, as well as running it in Node. And I&#8217;m going to figure out how to test it.</p><script src="https://gist.github.com/1148132.js?file=blackjack.coffee"></script>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Interested in CoffeeScript]]></title>
    <link href="http://patmaddox.com/blog/interested-in-coffeescript.html"/>
    <updated>2011-08-13T00:00:00-07:00</updated>
    <id>http://patmaddox.com/blog/interested-in-coffeescript</id>
    <content type="html"><![CDATA[		<p>I just skimmed through the Pragmatic Programmers CoffeeScript book. It looks like a great introduction to the language that covers a lot of ground and does so in enough depth to really get you going. I guess you can do that with such a concise languagee.</p><p>Off the top of my head, things that make CoffeeScript attractive to me:</p><ul>
<li> REPL</li><li> clear syntax</li><li> based on &#8220;the good parts&#8221;</li><li> modules</li><li> inheritance model</li><li> clean function definitions</li><li> jQuery integration</li><li> Node.js &amp; websockets</li><li> It&#8217;s in Rails by default</li><li> A lot of deployment options, including Rack</li>
</ul>
<p>Now I just need to start messing with the language and writing some programs with it.</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[One doctor's model for continuing education]]></title>
    <link href="http://patmaddox.com/blog/one-doctors-model-for-continuing-education.html"/>
    <updated>2011-07-26T00:00:00-07:00</updated>
    <id>http://patmaddox.com/blog/one-doctors-model-for-continuing-education</id>
    <content type="html"><![CDATA[		<p>A friend of mine told me that to be a professional programmer, you must dedicate at least 20 hours each week to professional development. <a href="http://books.google.com/books?id=ik0qCTVzl44C&amp;lpg=PP1&amp;dq=the%20clean%20coder&amp;pg=PT40#v=onepage&amp;q=hours&amp;f=false">That&#8217;s what Uncle Bob claims in his latest book, The Clean Coder,</a> <a href="http://books.google.com/books?id=ik0qCTVzl44C&amp;lpg=PP1&amp;dq=the%20clean%20coder&amp;pg=PT154#v=snippet&amp;q=surgeon&amp;f=false">pointing to surgeons as an example of how to behave professionally.</a></p><p>The 20 hours figure intrigued me. My dad is an ENT surgeon, and he’s managed to keep up for 26 years in a field where “technology turns everything upside down about every two years.” He did the first half of his residency before endoscopes were in wide use, which required him to peel back the scalp and skin around the eyes in order to drill a hole into a patient’s sinus. Later, endoscopes gave him access to more parts of the body, while causing much less damage to the patient. Nowadays he uses the Fusion Navigator, which he describes as “a GPS for the body.” Impressively, he’s kept up with changing medical technology in the face of distractions such as living in a decompression chamber for a week as a part of his underwater medicine training; setting up hospitals in Thai jungles; and overseeing the medical support infrastructure for 15,000 Marines deployed to Iraq.</p><p>I asked him how he’s done it. What follows is what he told me. Of course, this is just one doctor, but I think my dad is an interesting data point for those developing a personal model for continuing education.</p><h3>Observe other people at work</h3><p>Dad stressed that this is the most important part of his multi-pronged approach to continuing education as a surgeon. He regularly sits in on other surgeries, observing the team’s preparation and procedure. He inevitably learns new techniques, new ways of looking at surgical problems, and how teams work together to pull off a surgery.</p><h3>Attend at least one professional conference every year</h3><p>Conferences create a high density population of surgeons to share ideas, and the planned presentations provide a structured way to learn about the latest happenings in the medical world.</p><h3>Read high-quality material for at least 15 minutes each day</h3><p>Dad reads for at least 15 minutes, every single day. When I questioned the possible depth and breadth of his reading, he said that he wasn’t reading to learn something in particular. He simply cultivates the habit of reading high quality medical information. He has a library full of textbooks and journals that he has “given up on the hope of reading everything in here…that’s just impossible.” So every day he sits down, grabs something from his library, and reads for at least 15 minutes. He puts it away when he’s done, and the next day reads something different.</p><h3>Research to prepare for individual projects</h3><p>While Dad hasn’t read everything in his library, he is familiar with what he can find in there, and knows where to look for specific information. So when he is assigned a surgery case, he reads the case information and then uses it to inform his research through his library. He digs up articles and reference materials that will be relevant to his case, along with materials from previous cases.</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[giternal updated to 1.1 - with an important bug fix]]></title>
    <link href="http://patmaddox.com/blog/giternal-updated-with-an-important-bug-fix.html"/>
    <updated>2011-06-23T00:00:00-07:00</updated>
    <id>http://patmaddox.com/blog/giternal-updated-with-an-important-bug-fix</id>
    <content type="html"><![CDATA[		<p>I just released an update to <a href="http://rubygems.org/gems/giternal">giternal</a> that includes an <a href="https://github.com/patmaddox/giternal/commit/ddba4a257ff4eb7b8fa655b3f579a32507291e2b">important fix</a> for all users.</p><p>0.1.0 has a nasty bug that corrupts a checked out external&#8217;s .git repository. This happens because giternal sorts the files in .git before piping them to tar, in order to minimize repo bloat. Unfortunately, tar doesn&#8217;t seem to like that, and so when unfreezing the repository it loses many of the files in .git/objects. Instant repository corruption.</p><h3>What you can do</h3><p>The best thing to do is probably to wipe your external dir and do a giternal update <b>after upgrading to 1.1</b>. This will check out a fresh copy of the dependency, along with its uncorrupted git repo.</p><p>I don&#8217;t actually think there&#8217;s anything else you can do. Sorry :(</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Pair Programming Session: Word Chain Kata]]></title>
    <link href="http://patmaddox.com/blog/pair-programming-session-word-chain-kata.html"/>
    <updated>2011-06-07T00:00:00-07:00</updated>
    <id>http://patmaddox.com/blog/pair-programming-session-word-chain-kata</id>
    <content type="html"><![CDATA[		<p>In this pairing session, I work with Mike and Isel to solve the Word Chain kata on the PragProg code kata site. We use RSpec to drive the implementation.</p><p>The video is 80 minutes long.</p><iframe src="http://player.vimeo.com/video/24756614?title=0&amp;byline=0&amp;portrait=0" width="400" height="225" frameborder="0"></iframe>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A new way to read]]></title>
    <link href="http://patmaddox.com/blog/a-new-way-to-read.html"/>
    <updated>2011-06-03T00:00:00-07:00</updated>
    <id>http://patmaddox.com/blog/a-new-way-to-read</id>
    <content type="html"><![CDATA[		<p>Back in <a href="digital-reading-revolution-how-i-like-to-read-books.html">The digital reading revolution: How I like to read books, DRMed content, and the future of publishing</a>, I outlined how I approach reading and taking notes on books (aka &#8220;studying&#8221;). I also talked about ways in which I&#8217;d like to improve my reading process. Last night I decided to take a step in that direction.</p><p>To recap, I read both analog and digital books. I prefer reading on Kindle. I buy directly from the publisher when I can, because they usually offer a PDF download bundle. When I can&#8217;t find a book in kindle format, I buy the paper copy.</p><p>Whether I&#8217;m reading on my kindle or riffling through pages, I usually read a book more than once. First I&#8217;ll read through it quickly, without stopping, even if I don&#8217;t understand parts. I bookmark those as difficult sections and move on. I don&#8217;t make many notes at this point – just a few highlights here and there to indentify the author&#8217;s assertions and supporting facts and anecdotes.</p><p>After a quick first pass, I flip back through the book and take a look at my notes. These clues help me understand the book&#8217;s important points. I reconstruct the author&#8217;s arguments by stitching together the highlighted parts. I can tell the solid arguments from the flimsy ones at a glance. The Kindle makes this sort of note-rearranging a breeze because I can import the highlights into my computer [1].</p><p>I don&#8217;t always take great notes. A lot of the time, I don&#8217;t care enough to develop a complete understanding of that particular book at that particular moment. It&#8217;s good enough to mentally index the key themes and structure of the book, and let my computer do the boring task of remembering the actual words. Then I&#8217;ve got more energy to do the fun part, the part that only I can do: unlocking the author&#8217;s secrets when the time is right.</p><p>This works great for digital books, but analog requires more work. I often have vague notions of an idea or fact that I remember reading, but can&#8217;t remember which book it came from. Sadly, I can&#8217;t google my book shelves [2]. Until now.</p><p>I&#8217;ve got a <a href="http://www.amazon.com/dp/B001XWCQO2">fancy Scansnap S1500M</a> that I use to scan documents into DEVONthink. <a href="http://devon-technologies.com/files/screenshots/devonthink/devonthink-1.jpg">DEVONthink</a> OCRs the documents and then proposes possible filing locations. I&#8217;d like to use DT&#8217;s powerful search on my book shelf. Yesterday I took a couple of <a href="http://www.amazon.com/Getting-Things-Done-Stress-Free-Productivity/dp/0142000280/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1307088458&amp;sr=1-1">old</a> <a href="http://www.amazon.com/Eat-Drink-Be-Healthy-Harvard/dp/0743266420/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1307088785&amp;sr=1-1">books</a> to Office Depot and had them slice off the bindings. Then I scanned the books for DT to archive. I&#8217;ll save the details for another post, but the bottom line is that for $2.50 at Office Depot &amp;  15 minutes baby-sitting the scanner, I can take any book from my bookshelf and have all of its contents instantly searchable on my laptop.</p><p>Slicing a book in order to scan it felt weird at first, but it felt great to toss the pages into the recycling bin after scanning. Books (<i>computer</i> books especially) are heavy and a pain to move and take up space in my house. My entire library will fit on my laptop! I can load books onto my kindle or iPad for extra portability. If I want to go old school, I can print out the pages I want to read and fold them into my back pocket. I did the same thing with a few brand new books. After scanning the pages, I stapled the chapters separately. They look and feel like digests.</p><p>I&#8217;m pretty excited about this new approach. I can highlight the paper copy more aggressively and dispose of it when I&#8217;m done. My computer holds onto the master copy and makes it searchable for me. I have some ideas of how this approach could change my reading habits, but for now I&#8217;m going to just run with it and see what happens.</p><p>&#8212;&#8212;&#8211;</p><p>[1] On the flip side, transcribing notes by hand adds <a href="http://pragprog.com/titles/ahptl/pragmatic-thinking-and-learning">sensory experience</a> which can improve your ability to recall information.</p><p>[2] Google Books has its shortcomings. It can&#8217;t constrain its search to my bookshelf. Deep study is difficult due to missing pages.</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A website experiment]]></title>
    <link href="http://patmaddox.com/blog/a-website-experiment.html"/>
    <updated>2011-05-31T00:00:00-07:00</updated>
    <id>http://patmaddox.com/blog/a-website-experiment</id>
    <content type="html"><![CDATA[		<p>I want to do an experiment. I want to change the focus of my website. patmaddox.com has always been &#8220;just a blog.&#8221; I&#8217;ve used a bunch of different systems over the years - it started off as a Typo blog, and I had brief stints with Mephisto, Radiant, Wordpress, and Jekyll. At the moment it is running a hand-made Seaside app, which I built partly as an exercise in deploying Seaside apps.</p><p>I don&#8217;t think I need the &#8220;power&#8221; of any sort of dynamic blogging engine, and I certainly don&#8217;t need all of Seaside&#8217;s power. What I need is something that will let me capture, develop, and publish my ideas. So I&#8217;m going to try something a bit different. I&#8217;m going to use a site generator rather than a dynamic blogging engine. I&#8217;ll use it to publish a blog, but I want my site to also host more structured content. Life happens chronologically, but I can make my information more meaningful and useful if I spend a bit of time organizing it and keeping it up to date.</p><p>My plan is to begin creating skeleton pages for the site. These will be sparse pages that contain some useful bit of information – tools I use, sites I like, random ideas I have, etc. Over time, I&#8217;ll build up the content on these pages, and create new pages and link to them.</p><p>I&#8217;m not going to say what tool I&#8217;m using just yet. Maybe you can figure it out from the generated HTML.</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How to hire programmers]]></title>
    <link href="http://patmaddox.com/blog/how-to-hire-programmers.html"/>
    <updated>2011-05-09T00:00:00-07:00</updated>
    <id>http://patmaddox.com/blog/how-to-hire-programmers</id>
    <content type="html"><![CDATA[		<ol>
<li>Filter out candidates who don&#8217;t have a github / blog / portfolio</li><li>Pair with remaining candidates</li></ol>
<p>You learn a lot from pairing with someone.</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Weighing in on software craftsmanship]]></title>
    <link href="http://patmaddox.com/blog/weighing-in-on-software-craftsmanship.html"/>
    <updated>2011-01-20T00:00:00-08:00</updated>
    <id>http://patmaddox.com/blog/weighing-in-on-software-craftsmanship</id>
    <content type="html"><![CDATA[		<p>I&#8217;d like to take a moment to publicly discuss my thoughts on Software Craftsmanship, a topic that has seen a bit of back and forth in the blog world after Dan North unleashed <a href="http://dannorth.net/2011/01/11/programming-is-not-a-craft/">Programming is Not a Craft</a>.  You can find some of the responses at the bottom of <a href="http://www.martinfowler.com/bliki/CraftmanshipAndTheCrevasse.html">this post by Martin Fowler</a>.</p><p>The two main criticisms of the Software Craftsmanship Manifesto are that it encourages programmers to focus only on the code side, and the low barrier to entry to calling yourself a &#8220;Software Craftsman.&#8221;  Allow me to address these points of criticism.</p><h3>Criticism #1: Programmers will fall in love with the software at a technical level, at the expense of building software that makes users go WOW</h3><p>Martin Fowler may be right that &#8220;those people who primarily self-identify as programmers feel a large part of their life is no longer important in the agile world.&#8221;  They <strong>are</strong> important, obviously, but if they don&#8217;t <strong>feel</strong> important then that&#8217;s something that needs to be addressed.  Part of me thinks that SC is a reaction to broken software organizations that discourage interaction between programmers and users, and so the programmers retreat into their coding cubbies and focus on the only thing they have control over - their technical practices.</p><p>Back when Alan Cooper was stuck in an MS-dominated paradigm, <a href="http://www.amazon.com/Inmates-Are-Running-Asylum-Products/dp/0672326140">he wrote</a>, &#8220;Programmers aren&#8217;t evil. They work hard to make their software easy to use. Unfortunately, their frame of reference is themselves, so they only make it easy to use for other software engineers, not for normal human beings.&#8221;  Some people seem to fear that a focus on craftsmanship will lead to a world of well-tested, well-designed code that powers ugly software that is painful to use.  I don&#8217;t think that&#8217;s the case.  The common theme throughout Agile Roots 2010 was user experience, and how to get UX people working closely with programmers.  The Agile testing crowd is trying to get the message out that testing is about understanding user expectations.  When you get programmers, UXers, and testers collaborating, you have the holy trinity of software development - quality software that solves user&#8217;s problems, with no hidden surprises.</p><h3>Criticism #2: Low barrier to entry to calling yourself a Software Craftsman</h3><p>Anyone can sign his name to the manifesto and call himself a software craftsman.  I can add my dog as a signatory if I want to.  Apparently I&#8217;m supposed to believe that this cheapens the values expressed in the manifesto.  The reality is that anyone can call himself anything he wants!  I&#8217;m the President of the United States.  I&#8217;m dating Angelina Jolie.  I&#8217;m a member of the World Cup-winning US soccer team.  You get the idea&#8230;  Simply calling yourself something doesn&#8217;t make it so.  Who decides what is a &#8220;true&#8221; software craftsman anyway?  It&#8217;s up to you to decide whether people you interact with practice what they preach.  The manifesto doesn&#8217;t say, &#8220;we are craftsmen&#8221; - it says &#8220;we aspire to be craftsmen.&#8221;</p><p>I can&#8217;t accurately assess someone&#8217;s technical abilities or theory of software development based on the presence of his or her name on the SC Manifesto.  I&#8217;d be an idiot for trying.  But I bet that I could share a beer with anyone on that list and have an interesting discussion about software.  Even if they don&#8217;t test like I do.  Especially if they don&#8217;t test like I do.  It&#8217;s perfectly valid for people to hold different theories on how to build software.  I think we&#8217;re all better off if we let those theories mingle with each other, evolve, and even blow up in our faces on occasion.  At the very least, Software Craftsmanship provides one means of recognizing people who give a shit and are worth talking to.</p><h3>What&#8217;s missing from this discussion?</h3><p>SC discussions have focused primarily on the programming side, but it&#8217;s called the <em>Software</em> Craftsmanship Manifesto, not the <em>Typing-code-into-my-One-True-Editor</em> Manifesto.  Programming is only one role in the software creation process.  Wouldn&#8217;t it be great if testers and UXers could organize themselves into groups with hokey names, just like the Software Craftsmen?  Then we could throw one big mixer and invent 99% of the world&#8217;s useful software.  Perhaps they can rally under the banner of Software Craftsmanship.  They <strong>should</strong> rally under the banner of Software Craftsmanship.</p><h3>What are we really talking about?</h3><p>I see the <a href="http://manifesto.softwarecraftsmanship.org/">Software Craftsmanship Manifesto</a> as an evolution of the <a href="http://agilemanifesto.org/">Agile Manifesto</a>.  The key phrasing is not the &#8220;Not only&#8230;but&#8221; clauses, it&#8217;s &#8220;raising the bar of professional software development by practicing it and helping others learn the craft.&#8221;  Let&#8217;s examine it in detail:</p><ul>
<li><p><strong>raising the bar</strong>  - Nobody has a clue how to objectively assess the best software people.  That&#8217;s why licensing boards are so potentially dangerous to the industry, and why certifications are so useless.  If we want to achieve progress, it is the practitioners that must take responsibility for elevating the industry.</p></li><li><p><strong>practicing software development</strong> - Most professions devote as much time to practicing as they do to performing.  Yet for some reason we approach every day like we&#8217;re completely prepared for what&#8217;s to come, despite working on problems riddled with uncertainty.  SC says that we must acknowledge, respect, and prepare for the difficulty inherent in our work.  SC says that the state of the art changes so rapidly that you must continually hone your skills if you are to build useful software over a span of years or decades.  SC says that we must not let ourselves become complacent in our abilities, or make excuses for cutting corners.  If your programming environment doesn&#8217;t provide automated refactorings, then you had better practice common reactorings so that they become second nature to you, and so that you can execute them swiftly and safely on production code.  Above all, SC says never to let &#8220;too much work&#8221; get in the way of &#8220;a job well done.&#8221;</p></li><li><p><strong>helping others learn</strong> - this is the crux of the manifesto, because software development is fundamentally an iterative learning process.  When we share our experience and knowledge with others, we allow them to benefit from our past successes and failures.  When we teach, we also learn, and the mixing of ideas allows us to expand the <a href="http://www.edge.org/3rd_culture/kauffman03/kauffman_index.html">adjacent possible</a>.</p></li></ul>
<h3>Story time</h3><p>I was in Chicago for Agile 2009, the huuuge Agile conference filled with way more scrummasters than programmers.  It&#8217;s where I met Corey Haines, or more specifically I was at David Chelimsky&#8217;s house pairing on RSpec when Corey Haines walked through the door and greeted me with a big hug.  If you know Corey, you know that&#8217;s not a strange way for him to greet a stranger.  Corey told me about the Software Craftsmanship conference taking place across the street from AgileConf and said that I should come.  Some folks whose work I admired would be speaking, like Uncle Bob and Michael Feathers, and I would be exposed to other smart people in the software world who I hadn&#8217;t heard of before.  I almost didn&#8217;t go, because I didn&#8217;t have enough money in my checking account to both pay for the conference and get my bills paid that month, but after a few hours of deliberation I held my breath and fired off an email to Corey asking if he could spot me the registration fee.  He was in the middle of his <a href="http://www.google.com/search?q=pair+programming+tour">pair programming tour</a> where he basically worked for peanuts to put gas in his car to get from place to place, so he wasn&#8217;t exactly in the best position to lend me cash.  I&#8217;m incredibly grateful that he did, because it was one of the best conferences I&#8217;ve been to in my life.  There were talks about design, refactoring, compilers, required reading for programmers&#8230;Ken Auer even spoke about achieving a balanced life by picking four key areas of focus.  Programmers&#8230;talking about life balance???  I thought we&#8217;re supposed to be locked away in our code caves for 72 hours straight surviving on cold pizza and jolt cola!  Clearly this whole software craftsmanship thing is a different way of looking at software development.  But how exactly?</p><p>The Software Craftsmanship Manifesto is valuable because it provides a goal - raising the bar - and a blueprint for getting there - practice, practice, practice, and help others learn.  SC may run the risk of creating an echo chamber and excluding people who are capable of contributing valuable insight to the conversation, but I&#8217;m not afraid of that happening because at its core, SC is about sharing and being open to ideas for how to build software.  Without SC and similar movements, we run a far greater risk of believing that we&#8217;re alone in the battle against crappy software, instead of recognizing that we&#8217;re part of a vibrant community of thinkers and practitioners who want to change the world.</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The digital reading revolution: How I like to read books, DRMed content, and the future of publishing]]></title>
    <link href="http://patmaddox.com/blog/digital-reading-revolution-how-i-like-to-read-books.html"/>
    <updated>2011-01-15T00:00:00-08:00</updated>
    <id>http://patmaddox.com/blog/digital-reading-revolution-how-i-like-to-read-books</id>
    <content type="html"><![CDATA[		<p>I have always been a big reader.  When I was a kid I used to stay up until 2am reading, and I always had a pile of books at the foot of my bed.  When the Kindle came out a few years ago, I had to have one.  Carrying around thousands of books at once?  Yes please.  Downloading new books and periodicals at the click of a button?  Don&#8217;t mind if I do.  Some people will argue that you don&#8217;t <em>need</em> to carry thousands of books at a time, and they&#8217;re probably right.  My kindle has about 75 items on it.  I generally read between 3 and 5 books at a time, because I have ADD and feel like reading something different every day, or at different times in the same day.  Being able to carry those around with me in one device is a big win.</p><p>For the most part, I stick to non-fiction.  My goal in reading any book is to acquire new information, or ideally to elevate my understanding.  Those are different goals, and a lot of books that satisfy the first don&#8217;t satisfy the second.  Either way, in order to get the most out of a book, I follow a basic process:</p><ol>
<li>First, I do a quick skim of the book, reading the table of contents, the index, intros and conclusions of chapters, the final few pages of the book, and just generally flipping through to find interesting sections or visuals.</li><li>Next I read through the book as quickly as I can, bookmarking pages that seem important or are difficult to understand.  I may highlight short passages for later reference, but I don&#8217;t really take notes at this point.</li><li>Once I&#8217;ve finished the book, I go back and look over the sections that gave me difficulty.  This is where I begin to go into more depth, taking notes, writing down my questions and trying to figure out the answers to them.</li></ol>
<p>This process comes pretty much straight from How to Read a Book by Mortimer Adler.  I tell you what, friends give you funny looks when they see that book on your desk.  I don&#8217;t mind though, because since I started reading this way, I am able to go through books faster than I was able to before, and I get a lot more out of them.  Presumably this is the sort of skill I would have learned in college, but I didn&#8217;t attend for long enough.</p><h3>Digital formats change the way I read</h3><p>I&#8217;ve been using this process on paper books for a long time.  It&#8217;s taken me a while to completely adapt it to digital books.  At first I tried to pick a single platform to handle all of my reading.  The biggest problem is that every digital reader has some strengths and weaknesses.  The kindle provides the best reading experience for me.  I think the e-ink is gorgeous, and over all it is the closest I can get to a real book.  It&#8217;s better than a real book in a lot of ways, because the computer books I like to read are hefty and awkward to hold.  The kindle has one glaring weakness for me: navigation.  I can set bookmarks and highlight passages, and fairly easily jump between them, but it isn&#8217;t as natural or efficient as dog-earing pages or sticking my fingers in between the pages to hold a spot.  The kindle provides an excellent linear reading experience, but I find it cumbersome to jump back and forth between different parts of the book.</p><p>The other major downside to kindle is the DRM-protected books you buy from amazon.com.  I understand why companies do DRM, especially for a technology as new as e-readers, where nobody has a secure hold on the market yet.  But the promise of digital books to me is that I can read content on a number of devices, each with different capabilities.  Amazon has a kindle reader for basically every platform, but each one is still locked down with DRM, and most importantly I am limited by amazon&#8217;s ability and willingness to provide features.</p><p>I&#8217;ve started to buy more ebooks directly from publishers rather than amazon, because publishers often let you download the book in more than one format.  Pragmatic Press comes to my mind first, but there are others such as Smashwords who have recently made all of <a href="http://www.smashwords.com/profile/view/JerryWeinberg">Gerald Weinberg&#8217;s excellent books</a> available in PDF and Kindle format for only 10 bucks.  This is important to me because my process for reading digital books, after a good bit of trial and error, looks like this:</p><ol>
<li>Load up the PDF on my computer and do my pre-reading, studying the table of contents and index, and skimming the book a little</li><li>Read through the book on my kindle as quickly as possible, bookmarking difficult pages or highlighting interesting passages</li><li>Return to my computer to go into the book in more detail, take notes, and all that</li></ol>
<p>Steps 1 and 2 involve randomly accessing the book&#8217;s contents.  This is not the kindle&#8217;s strong point, in my experience.  On the other hand, kindle kicks ass when reading linearly, which is what step 2 is all about.</p><p>In addition to random access, PDF&#8217;s strong point is that it&#8217;s a standard format with excellent tool support.  I have a simple use for it, creating rich text notes and copying the links to particular pages of a PDF to embed in the note, or just copying and pasting text from the PDF into the note.  There are more advanced annotation tools that let you add annotations directly to the PDF, if that interests you.</p><p>When I can download a single book in multiple formats, I have the best of all worlds.  Kindle lets me burn through books quickly and comfortably, with an easy mechanism for bookmarks and highlights to refer to later.  PDF lets me pull it up on my computer and jump around, or copy and paste text and images, or links to specific pages.  The multiple formats allow me to use the best tool for the job, so to speak.  Because of this, I have tended to purchase non-fiction books directly from publishers that let me download a PDF version in addition to a kindle version.  I find that I simply get more value from my reading when I can read books in this way.</p><h3>What does this mean for readers?</h3><p>I am interested to see how the digital book revolution plays out.  I suspect that more authors will move toward self-publishing, for a variety of reasons.  One is that they have more control over how their content is distributed.  I think creative folks are coming around to the idea that it&#8217;s more important that their work gets exposure to a large number of people than it is to be fairly compensated by every single person who consumes that work.  Put another way, most authors would rather sell 100k copies of a digital book and have 300k stolen copies out there, than sell 50k copies and have zero piracy.  I have no clue if that scenario is realistic, but the point is that if you can earn double the revenue and have 8x the readership, then you&#8217;d be silly to focus your efforts on combating piracy.</p><p>The other reason is that I&#8217;m pretty sure traditional publishing is dead unless they embrace technology much more than they have so far.  As Jeremy McAnnally points out in his eBook <a href="http://authoringebooks.com/">Authoring eBooks</a>, he was able to publish his Rails 3 upgrade guide right as Rails was released, but the first dead-tree books didn&#8217;t hit stores until a year later.  Many books, especially technical books, are available as &#8220;rough cuts&#8221; or something similar, but there&#8217;s no denying that the publishing industry in general moves at a snail&#8217;s pace when compared with digital publishing.</p><h3>What about you?</h3><p>I am curious to know what other people think.  How are you reading books these days?  Are you addicted to digital readers or do you still prefer paper books?  If you do read digital books, what influences your purchasing decisions?  Is it convenience, price, availability of formats, or something else?  For authors or aspiring authors, how do you plan to publish your content in this day and age?</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA["X sucks" sucks]]></title>
    <link href="http://patmaddox.com/blog/x-sucks-sucks.html"/>
    <updated>2011-01-10T00:00:00-08:00</updated>
    <id>http://patmaddox.com/blog/x-sucks-sucks</id>
    <content type="html"><![CDATA[		<p>What is it with all of the presentations and blog posts titled &#8220;X sucks&#8221;?  Don&#8217;t pretend that you created a content-rich presentation but slapped on a provocative title just for effect.  If your goal is to immediately bias the listeners toward your position, job well done.  But I guarantee you that it does nothing to add to intelligent discussion in the software development community.</p><p>My biggest problem with &#8220;X sucks&#8221; talks is that they are so fucking insulting to my intelligence.  News flash: any tool or technique sucks when used incorrectly or in the wrong context.  And presenting only one side of an argument is the surest sign that you either don&#8217;t know what you&#8217;re talking about, or that you&#8217;re a self-indulgent asshole.  You know who else only presents one side of an argument, and discredits other opinions through hand-waving and strawmen?  Politicians and lawyers.  Congrats on joining such esteemed company!</p><p>When you stand up to present to your local user&#8217;s group, you have a responsibility to give them the highest quality information you can.  This can be in the form of hard data, or experience, or references to other people&#8217;s work, and the ideal presentation will use a combination of these.  Do your best to explain and argue your position, but make sure that you make people aware that there is another side to the debate, one that you aren&#8217;t presenting, that they should go search for themselves if they&#8217;re interested.  I have yet to come across a software-related topic that can be fully explored in a one-hour presentation.  Don&#8217;t insult your audience&#8217;s intelligence by presenting an extremist stance.  At best they&#8217;ll think you&#8217;re an idiot.  At worst you&#8217;ll fuel the FUD machine that has been plowing through the software industry all these years.</p><p>An interesting point about &#8220;X sucks&#8221; is that 6 months later, you will probably find out that you&#8217;re wrong!  I find that desirable, as it demonstrates maturation as a developer and as a person.  In that sense, &#8220;X sucks&#8221; might not be such a bad thing as it represents one step on your path to enlightenment.  Just be sure to <strong>heavily</strong> qualify your talk as presenting your personal experience at this moment in time, and that there are plenty of people who disagree with you, and that a few months from now you may completely reverse your position.  Realistically, you will probably bounce from one extreme to another, with the extremes gradually moving towards each other like the peaks of a fading sine wave, until you reach an equilibrium point.  This equilibrium point is that fine line between &#8220;X sucks&#8221; and &#8220;X rocks,&#8221; where at any given moment you can only know which side you&#8217;re on based on tons of experience.</p><p>The next time you sit down to write an &#8220;X sucks&#8221; blog post or talk, please reconsider.  Honor your abilities as a thinking developer by taking the time to advance our industry&#8217;s dialogue rather than making yourself look clever by trashing other people or techniques.  We&#8217;ll all be better for it.</p>		]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Finding orphaned files in iTunes (a Ruby script)]]></title>
    <link href="http://patmaddox.com/blog/finding-orphaned-files-in-itunes-a-ruby-script.html"/>
    <updated>2010-11-19T00:00:00-08:00</updated>
    <id>http://patmaddox.com/blog/finding-orphaned-files-in-itunes-a-ruby-script</id>
    <content type="html"><![CDATA[		<p>This morning started off not so hot when I discovered that iTunes had randomly deleted a few of my favorite songs.  I went looking through Time Machine for them, and they were nowhere to be found.  I managed to recover all but one of them using <a href="http://www.fadingred.com/senuti/">Senuti</a> to pull the missing files from my iPhone and place them in my iTunes library.</p><p>After I did that, I was curious to know if I had any other broken files in my library.  iTunes identifies broken files with an exclamation point &#8211; but only after you try to play the file!  I spent about an hour googling trying to find a quick way to show me all the broken files. All the tips I found were from 2006 and earlier, and none worked on iTunes 10 on my computer.  That&#8217;s when <a href="http://twitter.com/#!/aniero">aniero</a> suggested I write a script to parse my iTunes library XML file and check it against the file system.</p><p>Here&#8217;s the script I came up with.  No guarantees that it&#8217;s perfect, but it worked for me:</p><script src="https://gist.github.com/707065.js?file=find_orphaned_files.rb"></script>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How I reopen classes in Ruby]]></title>
    <link href="http://patmaddox.com/blog/how-i-reopen-classes-in-ruby.html"/>
    <updated>2010-11-16T00:00:00-08:00</updated>
    <id>http://patmaddox.com/blog/how-i-reopen-classes-in-ruby</id>
    <content type="html"><![CDATA[		<p>If you look at any code I&#8217;ve written that takes advantage of open classes, you&#8217;ll see the following pattern:</p><pre><code>Some::Class::Name.class_eval do  def my_added_method    # something here  end  def existing_method_with_my_extension    # something here    existing_method_without_my_extension  end  alias_method_chain :existing_method, :my_extensionend</code></pre><p>I use class_eval because doing so ensures that my code actually does what I think it does.  For this code to work, Some::Class::Name must already be defined, otherwise I&#8217;ll get an unknown constant error.  That helps me avoid two time-wasting pitfalls: a bad load path, and typos.</p><h3>Get your path right</h3><p>When you extend a gem, you need to have the gem installed in the system and in your load path, and then require it.  If you&#8217;re using Rails, it will automatically require it for you when you reference the constant name.  By using class_eval, I know immediately when my environment isn&#8217;t set up properly, because I get an error.</p><h3>Busting ghost classes</h3><p>Another problem I run into is stupid typos when writing out the class definition, or getting the module heirarchy wrong.  Something like this:</p><pre><code>module Sum  module Klass    class Naem      def my_added_method        # something here      end    end  endend</code></pre><p>In this case, Ruby is all too happy to create a second class for me called Sum::Klass::Naem even though I&#8217;m trying to extend Some::Class::Name.  I call these &#8220;ghost classes.&#8221;  I can&#8217;t figure them out just by looking at them, and they cause lots of mischief.</p><h3>Order of extension</h3><p>As a final note, when you extend a class, order often matters.  It&#8217;s possible to load your &#8220;extension&#8221; before the actual implementation and have it work (assuming you fully-qualified the class name properly, including its superclass, otherwise you get that funky superclass type mismatch error).  Order matters when you want to redefine a method, because Ruby will use the last method definition it comes across.  That means if you and the gem both define #foo, and you load your extension before loading the gem, Ruby will use the gem&#8217;s version.  In order to get the behavior you want, you need to load the gem first.  This also applies to alias_method_chain, which would blow up on you because the method you want to alias doesn&#8217;t exist yet.</p><p>This is just one way to reopen classes in Ruby, it&#8217;s not &#8220;the&#8221; way.  I&#8217;ve found it to be helpful in avoiding stupid mistakes, or catching environment issues, so I use it.  It has the added benefit of being more explicit, I think, about the fact that I&#8217;m opening an existing class.  I hope you find it useful, and if you&#8217;ve got other tricks for opening classes, please share in the comments!</p>		]]></content>
  </entry>
  
</feed>

