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

  <title><![CDATA[@TheKeyboard]]></title>
  <link href="http://www.littlehart.net/atthekeyboard/atom.xml" rel="self"/>
  <link href="http://www.littlehart.net/atthekeyboard/"/>
  <updated>2013-04-30T15:40:12-04:00</updated>
  <id>http://www.littlehart.net/atthekeyboard/</id>
  <author>
    <name><![CDATA[Chris Hartjes]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Testing Smells - try/catch]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2013/04/30/testing-smells-try-catch/"/>
    <updated>2013-04-30T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2013/04/30/testing-smells-try-catch</id>
    <content type="html"><![CDATA[<p>As part of a project to migrate the PHP code at <a href="http://synacor.com">work</a>
from PHP 5.2 to PHP 5.4, I&#8217;m using our extensive test suite to look for instances
where something that changed between the versions of PHP that we are using
has caused some unexpected behaviour.</p>

<p>In one of our code bases, I found some tests that are exhibiting a test smell
through their use of a try / catch block in the test itself.</p>

<p>Here&#8217;s a totally-contrived example:</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>
<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>
<span class='line-number'>26</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="x">    </span><span class="cp">&lt;?php</span>
</span><span class='line'>    <span class="k">public</span> <span class="k">function</span> <span class="nf">testThatExceptionIsThrown</span><span class="p">()</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="c1">// Use a helper to give us a ready-to-go parser</span>
</span><span class='line'>        <span class="nv">$parseHelper</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getHelper</span><span class="p">(</span><span class="s1">&#39;parseHelper&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="sd">/**</span>
</span><span class='line'><span class="sd">         * If we pass a string as the first parameter to parseGrumpyRambling</span>
</span><span class='line'><span class="sd">         * instead of an array, we should get an exception generated because</span>
</span><span class='line'><span class="sd">         * we are using a type hint</span>
</span><span class='line'><span class="sd">         */</span>
</span><span class='line'>        <span class="k">try</span> <span class="p">{</span>
</span><span class='line'>            <span class="nv">$weirdCanadianWords</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span><span class='line'>            <span class="nv">$phrase</span> <span class="o">=</span> <span class="s2">&quot;No doot aboot it, we&#39;re gonna win at hockey!&quot;</span><span class="p">;</span>
</span><span class='line'>            <span class="nv">$parsedText</span> <span class="o">=</span> <span class="nv">$parseHelper</span><span class="o">-&gt;</span><span class="na">parseGrumpyRambling</span><span class="p">(</span>
</span><span class='line'>                <span class="nv">$weirdCanadianWords</span><span class="p">,</span>
</span><span class='line'>                <span class="nv">$phrase</span>
</span><span class='line'>            <span class="p">);</span>
</span><span class='line'>            <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">fail</span><span class="p">();</span>
</span><span class='line'>        <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">Exception</span> <span class="nv">$e</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>            <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">assertContains</span><span class="p">(</span>
</span><span class='line'>                <span class="s1">&#39;must be of the type array, string given&#39;</span><span class="p">,</span>
</span><span class='line'>                <span class="nv">$e</span><span class="o">-&gt;</span><span class="na">getMessage</span><span class="p">()</span>
</span><span class='line'>            <span class="p">);</span>
</span><span class='line'>        <span class="p">}</span>
</span><span class='line'>    <span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Okay, so why does this test offend me so much?</p>

<p>First, I am of the opinion that writing a test to check to make sure you are
enforcing type hinting for your class method parameters is probably not a
good use of your time. I mean, what potential problem are you catching?</p>

<p>Consider the following:</p>

<ul>
<li>you likely have access to info about what type of value each parameter
is expected to be</li>
<li>you are probably much better off filtering for parameter type before you
even call that method</li>
</ul>


<p>I can say with confidence that a test like this is returning very little
value for the effort.</p>

<p>Second, putting any logic inside your unit tests is a great way to end
up with unexpected results. Need an &#8220;if&#8221; statement? Write two tests
for that condition. Need a switch / case? Again, one test per case is a
much better way to logically divide things up.</p>

<p>The worst thing about using try / catch is that <em>PHPUnit gives you two built-in
methods to not ever have to use it</em>. I&#8217;ve had people say to me &#8220;but Chris,
if you use try / catch you get much better control over determining where
in the process to test that the exception was thrown.&#8221; I don&#8217;t buy it, and
I will try and explain why.</p>

<p>If you are using docblocks on your tests (which you should) it is super easy
to indicate what exception you are expecting to be thrown.</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>
<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>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="x">    </span><span class="cp">&lt;?php</span>
</span><span class='line'>    <span class="sd">/**</span>
</span><span class='line'><span class="sd">     * @expectedException Exception</span>
</span><span class='line'><span class="sd">     * @expectedExceptionMessage must be of the type array </span>
</span><span class='line'><span class="sd">     */</span>
</span><span class='line'>    <span class="k">public</span> <span class="k">function</span> <span class="nf">testThatExceptionIsThrown</span><span class="p">()</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="c1">// Use a helper to give us a ready-to-go parser</span>
</span><span class='line'>        <span class="nv">$parseHelper</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getHelper</span><span class="p">(</span><span class="s1">&#39;parseHelper&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="sd">/**</span>
</span><span class='line'><span class="sd">         * If we pass a string as the first parameter to parseGrumpyRambling</span>
</span><span class='line'><span class="sd">         * instead of an array, we should get an exception generated because</span>
</span><span class='line'><span class="sd">         * we are using a type hint</span>
</span><span class='line'><span class="sd">         */</span>
</span><span class='line'>        <span class="nv">$weirdCanadianWords</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span><span class='line'>        <span class="nv">$phrase</span> <span class="o">=</span> <span class="s2">&quot;No doot aboot it, we&#39;re gonna win at hockey!&quot;</span><span class="p">;</span>
</span><span class='line'>        <span class="nv">$parsedText</span> <span class="o">=</span> <span class="nv">$parseHelper</span><span class="o">-&gt;</span><span class="na">parseGrumpyRambling</span><span class="p">(</span>
</span><span class='line'>            <span class="nv">$weirdCanadianWords</span><span class="p">,</span>
</span><span class='line'>            <span class="nv">$phrase</span>
</span><span class='line'>        <span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Now we have a much cleaner-looking test with no conditional logic inside it.</p>

<p>You can also choose to use a built in PHPUnit method to set what exception
you are expecting.</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>
<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>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="x">    </span><span class="cp">&lt;?php</span>
</span><span class='line'>    <span class="k">public</span> <span class="k">function</span> <span class="nf">testThatExceptionIsThrown</span><span class="p">()</span>
</span><span class='line'>    <span class="p">{</span>
</span><span class='line'>        <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">setExpectedException</span><span class="p">(</span>
</span><span class='line'>            <span class="s1">&#39;Exception&#39;</span><span class="p">,</span>
</span><span class='line'>            <span class="s1">&#39;must be of the type array&#39;</span>
</span><span class='line'>        <span class="p">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="c1">// Use a helper to give us a ready-to-go parser</span>
</span><span class='line'>        <span class="nv">$parseHelper</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="na">getHelper</span><span class="p">(</span><span class="s1">&#39;parseHelper&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="sd">/**</span>
</span><span class='line'><span class="sd">         * If we pass a string as the first parameter to parseGrumpyRambling</span>
</span><span class='line'><span class="sd">         * instead of an array, we should get an exception generated because</span>
</span><span class='line'><span class="sd">         * we are using a type hint</span>
</span><span class='line'><span class="sd">         */</span>
</span><span class='line'>        <span class="nv">$weirdCanadianWords</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span><span class='line'>        <span class="nv">$phrase</span> <span class="o">=</span> <span class="s2">&quot;No doot aboot it, we&#39;re gonna win at hockey!&quot;</span><span class="p">;</span>
</span><span class='line'>        <span class="nv">$parsedText</span> <span class="o">=</span> <span class="nv">$parseHelper</span><span class="o">-&gt;</span><span class="na">parseGrumpyRambling</span><span class="p">(</span>
</span><span class='line'>            <span class="nv">$weirdCanadianWords</span><span class="p">,</span>
</span><span class='line'>            <span class="nv">$phrase</span>
</span><span class='line'>        <span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Again, a much cleaner-looking test with no conditional logic in sight.</p>

<p>On Twitter Brian Fenton shared a <a href="http://www.brianfenton.us/2011/09/bad-practice-setting-expected.html">blog post</a>
he wrote back in 2011 that disagrees with me. In it he very briefly talks about
why you should use try / catch in your tests, but I feel like he is contradicting
himself when he talks about why.</p>

<p>Basically, Brian is concerned about how @expectedException and <em>setExpectedException()</em>
can be triggered by other errors in your tests (including other exceptions
being unexpectedly triggered. He feels that by using try / catch you have
much better control over when and where you wish to trigger an exception.</p>

<p>To quote Brain&#8217;s post:</p>

<blockquote><p>&#8220;The basic idea here is that the most specific test is best, because
you have the least likelihood of a false negative or a test error slipping
through the cracks.&#8221;</p></blockquote>

<p>If you are making sure that every test is the most specific test that you
can write, then you NEVER have to worry about whether or not some other
code under test is throwing an exception or other error that is messing up
the current test.</p>

<p>Using try-catch because you want to not miss errors that might occur before
you deliberately throw an exception is a sign that you are doing too much
in that test.</p>

<p>A test failure is a test failure, no matter what caused it. The harder you
work to make sure that a test is actually testing the most specific thing
possible, the less likely you have to worry about the things that Brian
feels require him to use try / catch.</p>

<p>This is the same reason I don&#8217;t like seeing tests like this:</p>

<ul>
<li>do Task A</li>
<li>do an assertion on the results of Task A</li>
<li>do Task B</li>
<li>do an assertion on the results of Task B</li>
</ul>


<p>Those are really two separate tests, so split them up. In fact, you could
write two tests that look like this:</p>

<ul>
<li>do Task A</li>
<li><p>do an assertion on results of Task A</p></li>
<li><p>do Task A</p></li>
<li>do Task B</li>
<li>do an assertion on the results of Task B</li>
</ul>


<p>That second test doesn&#8217;t need to re-assert that Task A did it&#8217;s job because
Task A was already covered in the previous test.</p>

<p>Test smells, testing anti-patterns, whatever you want to call them, do exist
and many programmers are often unaware of the consequences of those decisions
are.</p>

<p>Keep your tests small, keep them very specific, and don&#8217;t use conditional
logic in your tests. I have yet to see a specific example where the use
of conditional logic did anything except reduce the amount of lines of
code a grumpy developer didn&#8217;t want to type.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Grumpy Programmer's Guide To Software Company Culture]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2013/03/30/grumpy-culture/"/>
    <updated>2013-03-30T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2013/03/30/grumpy-culture</id>
    <content type="html"><![CDATA[<p>My co-worker <a href="https://twitter.com/chipersoft">Jarvis</a> wrote a blog post
about how he <a href="http://chipersoft.com/p/I-Dont-Care-About-Your-Culture/">doesn&#8217;t care about your company culture</a>.</p>

<p>I don&#8217;t know what prompted this blog post, but I disagree with many fundamental
parts of it. Jarvis seems like a decent guy (have only met him online and not
yet in person) but I think Jarvis is making a mistake that many people (not
just software developers) make: thinking that the rest of the world should
think like you when it clearly doesn&#8217;t.</p>

<p>Initially I was going to make a point-by-point takedown of his blog post, but
halfway through it I realized I was being an asshole. So instead I want to
discuss where I think he&#8217;s wrong.</p>

<p>I mentioned on Twitter to Jarvis that it&#8217;s just as important to work on your
co-workers as all the other things you do. He said two interesting things in
response:</p>

<ul>
<li>&#8220;This is what I don&#8217;t like about big companies&#8221;</li>
<li>&#8220;I work on computers, not people&#8221;</li>
</ul>


<p>First, I&#8217;ve worked at places both big and small. There is nothing inherently
better about either type. Do not kid yourself thinking only great things
happen at small companies. Great things happen when groups of smart people
get together and are given permission to go make it happen.</p>

<p>I&#8217;ve seen it work at large places where managers &#8220;ran interference&#8221; so their
employees could make stuff happen. I&#8217;ve seen small places stifle creativity
in their employees out of fear of change.</p>

<p>It&#8217;s not the size of the company that matters, it&#8217;s how they choose to work
together that matters.</p>

<p>The second point is the one where I think Jarvis has made the biggest mistake
in his approach.</p>

<p>We work FOR people USING computers. The computer is a tool
to achieve a goal. Those goals are achieved by working with others, whether
you wish to believe that or not.</p>

<p>As someone who has worked from home for a long time, I understand and
sympathize with many of the things Jarvis indicates that bug him. Noise
from co-workers, drive-by meetings, feeling pressure to participate in
social activities.</p>

<p>But at the end of the day, to accomplish anything of substance requires me
to interact with others in REAL TIME. I have proven that I can both get work
done AND not be such an asshole that others choose to ignore the remote
worker instead of working hard to integrate me into the team.</p>

<p>I find that socializing with my co-workers is a good way to learn about the
people I work with, so that when I need something from them later they are
less likely to say &#8220;why the fuck should I help that guy?&#8221; I need their help
as much as they need mine.</p>

<p>Of course, I don&#8217;t think this bit at the end helps much:</p>

<blockquote><blockquote><p>I am extremely productive in this setting. For five years I have cranked out more code in this room than many people have written in their entire careers.</p>

<p>I am exceedingly good at my job and I am sick of being told that my lack of cultural involvement makes me a bad employee.</p>

<p><em>mic drop</em></p></blockquote></blockquote>

<p>Disrespecting co-workers isn&#8217;t always the smartest move. Failing to understand
why others think that being aloof and distant and insisting that results matter
more than how you treat people isn&#8217;t always the smartest move either.</p>

<p>Tech is not a meritocracy, despite our wishes for it to be. Jarvis, you&#8217;re not
alone in wanting people to just leave you the hell alone so you can get some
work done. I am that way many times, but I make sure to create those bonds
with my co-workers so that the amount of time that I spend with them is
enjoyable instead of resenting the time there.</p>

<p>Nothing creates bonds of friendship like a shitty job, but being friendly with
your co-workers costs you nothing but a little time, time you&#8217;re probably
spending doing horrible things like reading the comments on Hacker News.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[What's In Chris' Brain - Birthday Edition]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2013/03/24/whats-in-chris-brain-birthday-edition/"/>
    <updated>2013-03-24T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2013/03/24/whats-in-chris-brain-birthday-edition</id>
    <content type="html"><![CDATA[<p>Today is my 42nd birthday, which is 420 in internet years. I am feeling old
but thankful that I have so many friends who keep lying to me and saying I&#8217;m
not a programming dinosaur.</p>

<p>I haven&#8217;t done one of these blog posts in a while, so I thought I would solicit
some ideas from my Twitter followers and address a few of them.</p>

<h1>Can I unit test in 140 characters or less?</h1>

<p>No. Testing, in general, does not lead itself to brevity. The tools we use
to test our code in an automated fashion can only abstract so much away from
us before we actually have to write some code.</p>

<p>Large amounts of setup work is a sign that perhaps your code-under-test is
doing too much. Sometimes it is unavoidable if you are using dependency
injection to create multiple dependencies.</p>

<p>Of course, &#8220;large&#8221; is also subjective. I would offer my opinion on what &#8220;large
amounts of setup work&#8221; means to me, but that would just lead to people arguing
with me about testing when I&#8217;d rather argue about why dick jokes spoken at
conferences are the tip of the metaphorical iceberg that represents white male
privilege in the tech industry.</p>

<p><em>sigh</em></p>

<h1>What are your favourite Vim plugins?</h1>

<p>I group the plugins I use into two categories: &#8220;essential&#8221; and &#8220;everything else&#8221;.
Right now, I only have four essential plugins:</p>

<ul>
<li><a href="https://github.com/tpope/vim-pathogen">Pathogen</a> for organizing my plugins</li>
<li><a href="https://github.com/ervandew/supertab">Supertab</a></li>
<li><a href="https://github.com/scrooloose/syntastic">Syntastic</a></li>
<li><a href="https://github.com/tpope/vim-surround">Surround.vim</a></li>
</ul>


<p>All other plugins swap in and out depending on my mood and whatever problems
I am attempting to solve in code. Right now I&#8217;ve got the following</p>

<ul>
<li><a href="http://www.vim.org/scripts/script.php?script_id=13">Closetag</a></li>
<li><a href="https://github.com/kien/ctrlp.vim">Ctrl-P</a></li>
<li><a href="https://github.com/scrooloose/nerdcommenter">NERD Commenter</a></li>
<li><a href="https://github.com/scrooloose/nerdtree">NERD Tree</a></li>
<li><a href="https://github.com/troydm/pb.vim">pb.vim</a></li>
<li><a href="https://github.com/kchmck/vim-coffee-script">Vim CoffeeScript</a></li>
<li><a href="https://github.com/airblade/vim-git-gutter">Vim Git Gutter</a></li>
<li><a href="https://github.com/pangloss/vim-javascript">vim-javascript</a></li>
<li><a href="https://github.com/tpope/vim-repeat">repeat.vim</a></li>
</ul>


<h1>Is Grumpy Cat your Cat?</h1>

<p>No.</p>

<h1>Life as a unicorn in Canada</h1>

<p>This was asked tongue-in-cheek by my <a href="https://twitter.com/PolarLava">boss</a>, who
refers to me as his &#8220;Canadian unicorn&#8221; because of my unique status within
the company  but
I think it&#8217;s actually better re-framed as &#8220;what is it like working in a senior
role when you are remote?&#8221;</p>

<p>First, my co-workers go to great lengths to make sure that myself and the
two other remote workers in a group of over a dozen (I cannot remember all
the people who are on the other team that makes up our group) are integrated
into all decisions.</p>

<p>We have been experimenting with using Google+ Hangouts as a way for all the
remote workers to see what&#8217;s going on in the office. Despite my initial
reservations that it&#8217;s simply a way for nervous management to keep an eye on
us I think it has worked out well. They&#8217;ve created a permanent &#8220;remote station&#8221;
and people have walked up to it to find one of us and ask us directly a
question.</p>

<p>It&#8217;s growing on me, and I have also started looking at this awesome site on
<a href="http://remotepairprogramming.com/">making remote pair programming smoother</a>
for inspiration on how to make it better. I already use my iPad as my &#8220;personal device&#8221;
while working from home, so it seems natural to start using it as my visual gateway
into the office.</p>

<p>Second, because I am remote and therefore trusted to work for long stretches
of time with Eyeball Supervision (a.k.a walking up behind you and asking what
you&#8217;re working on) you get assigned tasks that can be done by one person
(sometimes two if the other can be dedicated to the task) and take a while
to do.</p>

<p>Unless you make the commitment to do remote pair-programming (which I have
done with great success) you should get used to working on stuff in a directly-unsupervised
fashion.</p>

<p>This suits me just fine.</p>

<p>Finally, make sure that everyone who has to work with you knows that just because
you are remote does not mean that you are unwilling to do one-on-one communication
with people. I have a soft phone that work has provided me, and I get phone calls
from co-workers asking me stuff. I do Skype calls and lots of text chats.</p>

<p>In other words, I probably talk to my co-workers about work-related stuff
as much as anyone else in the office.</p>

<p>What I miss out on are the social events that happen. That sucks, but I always
make sure to do something at my end (and expense it ;) ) very similar to
what my co-workers are doing. If they get pizza during a tech presentation, I
make sure to order myself something similar.</p>

<p>Remember, being remote does not mean that you are invisible.</p>

<h1>Productivity and task management tips</h1>

<p>How does this grumpy guy get things done while working remotely?</p>

<ul>
<li>pay attention in meetings so that you are not forced into positions that
are untenable for you</li>
<li>work hard to get everything done that you have promised to do</li>
<li>work hard to communicate with everyone because you can&#8217;t just walk over to
their cubicle / office to bitch at them for not getting stuff done on your own
schedule</li>
</ul>


<p>That&#8217;s it really. Get stuff done, do good work, and there will be fewer and
fewer excuses for your employer to prevent others from reaping the rewards
of your trail-blazing efforts.</p>

<h1>A Day in the life of a Grumpy Programmer</h1>

<ul>
<li>woken up at 6am by the Office Manager, who is seeking cat treats for himself
and the HR Manager</li>
<li>lay in bed in a daze until 6:45am when my wife is showered, dressed and heads
downstairs.</li>
<li>wake kids up at 7am and putter around getting breakfast and lunches together</li>
<li>throw kids out of the house between 8am and 8:15am so they are not late for
school</li>
<li>have breakfast, work out, shower and start my day</li>
</ul>


<p>For the rest, just follow me on Twitter to get a feel for my mood. ;)</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Grumpy Programmer's PHPUnit Cookbook launched]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2013/03/07/grumpy-phpunit-launched/"/>
    <updated>2013-03-07T00:00:00-05:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2013/03/07/grumpy-phpunit-launched</id>
    <content type="html"><![CDATA[<p>After I wrote my <a href="http://grumpy-testing.com">first Leanpub book</a> I would get
asked all the time on how to use PHPUnit itself. Again, much like the information
I put into the &#8220;Grumpy Testing&#8221; book, I found lots of shallow information on
how to use PHPUnit itself.</p>

<p>I did some research <a href="http://unicornfree.com/30x500">30x500 style</a>, worked
on my pitch while writing the book, and on March 4th I launched <a href="http://grumpy-phpunit.com">&#8220;The Grumpy Programmer&#8217;s PHPUnit Cookbook&#8221;</a>.</p>

<p>This book is a collection of the most common tips and techniques I use myself
to write effective and quick tests for PHP code. If you&#8217;ve ever wondered
how to create mock objects, or wanted to know how to test code that uses
remote API calls, my book will help you.</p>

<p>As my way of saying thank you to those who read my blog, you can use the code
GRUMPYFEED to get $5 off my book for the next week.</p>

<p>As always, I welcome your feedback via email (chartjes@littlehart.net) or
Twitter (@grmpyprogrammer).</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Standards, soapboxes, and shamans]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2013/01/20/standards-soapboxes-and-shamans/"/>
    <updated>2013-01-20T00:00:00-05:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2013/01/20/standards-soapboxes-and-shamans</id>
    <content type="html"><![CDATA[<p>To paraphrase Batman:</p>

<blockquote><p>&#8220;Programmers are a cowardly, superstitious lot&#8221;</p></blockquote>

<p>Programmers often look to external sources for validation of
all sorts of things they do. Did they choose the right
language? Are they writing good code? Will they be
accepted by their peers.</p>

<p>Of course, there are those who are leaders within a
community. Those who manage to do great things
but with an idiosyncratic way of doing things.
Let&#8217;s call these people shamans. In many ways
programming is a mystical thing: you conjure
up solutions to problems using tools that
often require strange incantations.</p>

<p>For those who pay attention to the workings of the PHP community
you might have heard about the &#8220;PHP Standards Recommendations&#8221;
that have been coming out of the <a href="http://www.php-fig.org/">PHP Framwork Interop Group</a>.</p>

<p>It&#8217;s first contribution was <a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md">PSR-0</a>, which covers recommended standards for
autoloading of PHP code (no more remembering to require/include files
any more to load your class files), then followed by <a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md">PSR-1</a> (which covers basic coding standards) and <a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md">PSR-2</a> which is about a coding style guideline.</p>

<p>More recently this group has been working on a standard for logging
interfaces called <a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md">PSR-3</a>.</p>

<p>I spoke about this on Twitter, and I will repeat it here:
I think PHP programmers should get behind PSR-0 and efforts like
PSR-3. I feel that PSR-1 and PSR-2 are solutions looking for
a problem and seem, to me anyway, to me out of place with
the solutions offered by PSR-0 and PSR-3.</p>

<p>Standards that are enforced by the community have a power
that people really don&#8217;t understand. The classic example of
this are the <a href="http://www.python.org/dev/peps/">Python Enhancement Proposals</a>.
They cover a incredible range of ideas and concepts that a Python
developer needs to worry about.</p>

<p>PEP-8, which covers coding standards, is probably the one most
casual Python programmers are familiar with. The whole community followed
it, which might have been easier due to Python&#8217;s use of significant
whitespace. But more importantly, it was championed by
Python&#8217;s Benevolent Dictator For Life, Guido van Rossum.
He was able to use his soapbox as the guiding force behind it.</p>

<p>PSR-1 and PSR-2 are generating a lot of, well, pissing and moaning
from people. I get it: I often grind my teeth when looking at
code written in a style that deviates quite a bit from my
normal coding style and practices.</p>

<p>However, it&#8217;s far more important to be able to understand
what the code is doing. PSR-0, in my opinion, serves to standardize
application layout for the purpose of making it easier to
load classes you need in your code. PSR-3 (and similar interface
standard recommendations) serves to allow you to integrate
3rd party code with yours a lot quicker.</p>

<p>Standards, soapboxes and shamans are an integral part of
any programming community that wants to move forward and keep
producing better and better tools and applications. Any programming
language community that does not work as hard as possible to
make it easier to integrate other&#8217;s libraries of code together
is asking for irrelevancy.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[One year of Grumpy Testing]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2013/01/11/one-year-of-grumpy-testing/"/>
    <updated>2013-01-11T00:00:00-05:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2013/01/11/one-year-of-grumpy-testing</id>
    <content type="html"><![CDATA[<p>It was one year ago today that I released <a href="http://grumpy-testing.com">&#8220;The Grumpy Programmer&#8217;s Guide To Building Testable PHP Applications&#8221;</a>. 650+ customers later (about 10% of those are free copies)
I am happy with some of the outcomes, and unhappy about others.</p>

<p>Just for the sake of openness, here&#8217;s an awesome ASCII bar graph made with
<a href="https://github.com/stefanschramm/barg">barg</a> to show you week-by-week sales
counts and numbers. I apologize for the scrolling you might have to do to see it.</p>

<pre>
Week Starting          #  Paid
2012-01-09 00:00:00-05 56 $673.06 ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 
2012-01-16 00:00:00-05 29 $306.05 |||||||||||||||||||||||||||||||||||||||||                                         
2012-01-23 00:00:00-05 17 $95.00  ||||||||||||||||||||||||                                                          
2012-01-30 00:00:00-05 19 $203.50 |||||||||||||||||||||||||||                                                       
2012-02-06 00:00:00-05 17 $160.00 ||||||||||||||||||||||||                                                          
2012-02-13 00:00:00-05 7  $73.05  ||||||||||                                                                        
2012-02-20 00:00:00-05 14 $162.2  ||||||||||||||||||||                                                              
2012-02-27 00:00:00-05 7  $89.71  ||||||||||                                                                        
2012-03-05 00:00:00-05 6  $69     ||||||||                                                                          
2012-03-12 00:00:00-04 7  $70.93  ||||||||||                                                                        
2012-03-19 00:00:00-04 15 $128.67 |||||||||||||||||||||                                                             
2012-03-26 00:00:00-04 55 $356.97 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||   
2012-04-02 00:00:00-04 11 $131.00 |||||||||||||||                                                                   
2012-04-09 00:00:00-04 1  $8.50   |                                                                                 
2012-04-16 00:00:00-04 25 $277.30 ||||||||||||||||||||||||||||||||||||                                              
2012-04-23 00:00:00-04 16 $157.83 |||||||||||||||||||||||                                                           
2012-04-30 00:00:00-04 8  $95.00  |||||||||||                                                                       
2012-05-07 00:00:00-04 7  $81.50  ||||||||||                                                                        
2012-05-14 00:00:00-04 8  $75.04  |||||||||||                                                                       
2012-05-21 00:00:00-04 13 $43.00  ||||||||||||||||||                                                                
2012-05-28 00:00:00-04 2  $21.50  ||                                                                                
2012-06-04 00:00:00-04 19 $149.41 |||||||||||||||||||||||||||                                                       
2012-06-11 00:00:00-04 8  $74.42  |||||||||||                                                                       
2012-06-18 00:00:00-04 10 $92.00  ||||||||||||||                                                                    
2012-06-25 00:00:00-04 7  $30.00  ||||||||||                                                                        
2012-07-02 00:00:00-04 11 $104.08 |||||||||||||||                                                                   
2012-07-09 00:00:00-04 14 $157.47 ||||||||||||||||||||                                                              
2012-07-16 00:00:00-04 3  $26.99  ||||                                                                              
2012-07-23 00:00:00-04 3  $34.50  ||||                                                                              
2012-07-30 00:00:00-04 11 $120.50 |||||||||||||||                                                                   
2012-08-06 00:00:00-04 4  $43.00  |||||                                                                             
2012-08-13 00:00:00-04 10 $108.00 ||||||||||||||                                                                    
2012-08-20 00:00:00-04 4  $47.50  |||||                                                                             
2012-08-27 00:00:00-04 7  $82.00  ||||||||||                                                                        
2012-09-03 00:00:00-04 6  $55.50  ||||||||                                                                          
2012-09-10 00:00:00-04 6  $464.98 ||||||||                                                                          
2012-09-17 00:00:00-04 6  $62.01  ||||||||                                                                          
2012-09-24 00:00:00-04 3  $34.50  ||||                                                                              
2012-10-01 00:00:00-04 5  $61.40  |||||||                                                                           
2012-10-08 00:00:00-04 55 $624.92 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||   
2012-10-15 00:00:00-04 21 $218.78 ||||||||||||||||||||||||||||||                                                    
2012-10-22 00:00:00-04 16 $169.50 |||||||||||||||||||||||                                                           
2012-10-29 00:00:00-04 6  $105.00 ||||||||                                                                          
2012-11-05 00:00:00-05 12 $120.00 |||||||||||||||||                                                                 
2012-11-12 00:00:00-05 4  $43.00  |||||                                                                             
2012-11-19 00:00:00-05 10 $112.02 ||||||||||||||                                                                    
2012-11-26 00:00:00-05 9  $101.25 |||||||||||||                                                                     
2012-12-03 00:00:00-05 15 $159.00 |||||||||||||||||||||                                                             
2012-12-10 00:00:00-05 6  $72.30  ||||||||                                                                          
2012-12-17 00:00:00-05 13 $142.03 ||||||||||||||||||                                                                
2012-12-24 00:00:00-05 4  $38.50  |||||                                                                             
2012-12-31 00:00:00-05 1  $13.90  |                                                                                 
</pre>


<p>What am I disappointed about? I think, to use the old expression, I left a lot
of money on the table. I could&#8217;ve charged more for the book, but this was
before I started learning more about the marketing of info products and
how to do research to find solutions to problems people are experiencing.</p>

<p>Setting that aside, I think my Testing Crusade is paying dividends for the
community as a whole. The more developers who are exposed to the ideas
that people like myself are promoting, the higher quality code that
is likely to be produced.</p>

<p>If you&#8217;re a customer of mine, thanks so much for supporting my efforts through
your paid contributions. Writing automated tests and code that you can easily test doesn&#8217;t have to suck.
I can show you how to do it, and I look forward to bringing you more of it
in 2013.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[You need tests...just not yet]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2013/01/07/you-need-tests-just-not-yet/"/>
    <updated>2013-01-07T00:00:00-05:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2013/01/07/you-need-tests-just-not-yet</id>
    <content type="html"><![CDATA[<p>Every once in a while I come across a blog post or a presentation that helps
me figure out something that has been bothering but I was having problems
articulating. Lately I&#8217;ve been struggling to come up with strategies to help
developers figure out when they should REALLY be writing tests for their code.</p>

<p>If you believe in the power of TDD, then the answer is &#8220;you write tests from
the beginning of the project and forever after.&#8221; I am a believer that TDD can
be a very powerful design tool for building things at the unit / module / component
level.</p>

<p>Then some people asked me my thoughts on the comments by the creator of the
Rails project about the usefulness of dependency injection. As happens when
I am feeling frustrated, I started firing out the tweets on my feelings on
testing and the lonely Crusade that I am on.</p>

<p>Then I saw a talk by Dan North called <a href="http://www.infoq.com/presentations/Decisions-Decisions">&#8220;Decisions, Decisions&#8221;</a> at the recommendation of <a href="https://twitter.com/ianbarber">Ian Barber</a> that made me realize that someone else has articulated my feelings on
when you should be doing testing. Slides for the presentation can be found
<a href="http://qconlondon.com/dl/qcon-london-2012/slides/DanNorth_DecisionsDecisions.pdf">here</a>.</p>

<p>You should watch the whole presentation. So many decisions about programming
are made without understanding, REALLY understanding the trade-offs involved
when making one decision vs. another.</p>

<p>Let&#8217;s look at TDD vs. Test whenever. The trade-off being made here is not
about quality of code or guarding against regressions. It&#8217;s about opportunity cost.
This had occurred to me but I had dismissed it as being &#8220;anti-testing&#8221;.</p>

<p>But I think I was wrong, and here&#8217;s why.</p>

<p>In that awesome presentation he talks about &#8220;patterns&#8221; he observed on the team
he was working with at the time. He was amazed at how much work this team was
getting done, so he spent time analyzing what they were doing and trying to
turn some of their activities into patterns of behaviour. Repeatable processes
are good, right?</p>

<p>The one that he saw being related to writing was a pattern he called &#8220;Spike
and Stabilize.&#8221; Basically, you write code without any tests until it becomes
a solid part of your application&#8217;s architecture. Once this code has proven
it&#8217;s usefulness, you start writing comprehensive tests in order to verify
that it is in fact doing the job and doesn&#8217;t break going forward.</p>

<p>This is so obvious to me now. Clearly, you are leaving yourself open to the
potential of writing not just application code but testing code that gets
tossed away if the idea you are implementing is unable to prove it&#8217;s value.</p>

<p>Opportunity cost is huge and often dismissed by developers too. If you have
some prototype code, or even functionality with a half-life measured
in 3-month-increments, what else could be worked on while tests for this
code are being written?</p>

<p>Could this hybrid approach be an easier sell to skeptical managers or
other stakeholders? That&#8217;s hard to say. The &#8220;too busy to write tests&#8221;
camp still has many members, and is still seems that it takes catastrophic
failures before many people join the Testing Crusade.</p>

<p>To be perfectly clear: I find great value in prototyping code and then
committing to tests once the prototype is ready to move to a more stable
environment.</p>

<p>I try and do prototyping before I commit to writing code, because I often
feel that way. My prototypes are usually command-line scripts that try
and accomplish the task I&#8217;ve been assigned. That way, it&#8217;s easier to
actually write some tests once I know what I&#8217;m doing and guard against
regressions later.</p>

<p>The key to all this is being able to identify at what stage in this particular
pattern your code is at. Is it still a spike, meaning you are working out
implementation details and trying to figure out if it will even have the
desired result? Or is it stable, providing solid value to the application
as a whole and ready to be wrapped in tests to protect against regressions?</p>

<p>Next time you are thinking about &#8220;I need some tests for this&#8221;, consider the
Spike and Stabilize pattern. The answer might be &#8220;you need tests&#8230;but not yet.&#8221;</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[2012 Review]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/12/31/2012-review/"/>
    <updated>2012-12-31T00:00:00-05:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/12/31/2012-review</id>
    <content type="html"><![CDATA[<p>2012 was a very interesting year for me. It started with me being tired
and unhappy&#8230;and this year ended with me being tired and unhappy. For
different reasons, though.</p>

<p>I had a much different blog post written, and decided to scrap it in favour
of a different approach. Buckle up, here we go, starting with January and
continuing to the end of the year:</p>

<ul>
<li>unhappy with start-up life</li>
<li>started grinding out episodes of a <a href="http://devhell.info">podcast</a> with <a href="https://twitter.com/funkatron">Ed</a></li>
<li>released my <a href="http://grumpy-testing.com">&#8220;write testable PHP applications&#8221; book</a> on January 11th</li>
<li>spoke to a near-empty room at CodeMash 2012, they seem to not like PHP there</li>
<li>started working for an online learning company</li>
<li>made plans to attend <a href="http://tek12.phparch.com">PHP|Tek 2012</a></li>
<li>found softball enjoyable this year as I could actually bend over to field balls. Still can&#8217;t hit</li>
<li>did a live episode of the podcast at PHP|Tek, which was awesome</li>
<li>started mentoring three developers on ways of being grumpy programmers</li>
<li>found the benefits of test-centric development to be ruined by a terrible work environment</li>
<li>Ed and I hit our groove with the podcast in the summer</li>
<li>started looking for another job</li>
<li>taught my PHP testing bootcamp course of the first time, in person though</li>
<li>switched to my third job in 2012</li>
<li>got accepted to speak at a conference in Sweden</li>
<li>helped organize a <a href="http://truenorthphp.ca">PHP conference</a> up here in Kanuckistan</li>
<li>spoke to a near-empty room at the conference in Sweden, guess they don&#8217;t like PHP there either</li>
<li>got accepted to speak at a PHP conference in Belgium</li>
<li>created an online version of my PHP testing bootcamp course</li>
<li>worked on my <a href="http://grumpy-phpunit.com">next book</a></li>
<li>wondered what the hell happened to everything I wanted to do in 2012.</li>
</ul>


<p>Like so many things in life, you can only plan for so much. At the beginning of
2012 the only thing I knew for sure was (a) I wasn&#8217;t liking my job and (b) my
book was coming out extremely soon. At the same time I was worrying about the
fact that my ENTIRE FUCKING CAREER is basically built upon the pile of web-enabled
spaghetti that is PHP. What the hell should I do?</p>

<p>So I took some babysteps towards learning server-side Javascript and played around
with Node.js. I like it, I think I am understanding how to build applications using
it in a more idiomatic way.</p>

<p>But there is still lots of PHP. Can&#8217;t escape it, it&#8217;s all I know. Well, that and
a whole bunch of actual theory on how to build web applications as small modules
of code that talk to each other.</p>

<p>I didn&#8217;t set any goals for 2012 other than &#8220;sell $10K worth of books&#8221; and I did
manage to almost accomplish that. $6,547.25 in royalties for the ebook, $2K
in licensing fees and some-amount-I-have-not-added-up in paper copies of the book.
I think I can say that I <em>almost</em> made it, and that my next book will do
even better because of the success of the first one.</p>

<p>So what is in store for me in 2013? The plan is to keep pushing the info-products
(books, courses, screencasts later in the year) while continuing to make solid
contributions at the day job. There is no lack of interesting things for me
to do at the day job, more than enough to keep the gears going.</p>

<p>I enter 2013 feeling like I&#8217;m stuck in low gear mentally, though. I&#8217;ve clearly
over-committed myself and I just have to grind through it until March 2013.</p>

<p>I will say that I have decided to focus on becoming a better programmer, no
matter what languages I tackle. I have a bunch of reading material cued up
to help me get better at taking real-world problems and figuring out how
to solve them in the context of programming environments and domain models.</p>

<p>That is the last piece that I personally feel is missing from my skill set:
learning how to figure out how to turn business objectives into techincal
solutions. I&#8217;m in a good spot to do it, and I know my <a href="https://twitter.com/PolarLava">boss</a>
has all sorts of &#8220;fun&#8221; things lined up for me to do.</p>

<p>So thanks for another year of watching what I do with some interest and I aim
to provide you with more entertainment and knowledge throughout 2013.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[So you want to write tests]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/12/17/so-you-want-to-write-tests/"/>
    <updated>2012-12-17T00:00:00-05:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/12/17/so-you-want-to-write-tests</id>
    <content type="html"><![CDATA[<p>I often get asked for some advice on how to get started with writing tests
for your PHP code. It&#8217;s a fair question, since I am presenting myself as an
expert-ninja-rockstar-sensei-opinionated-egomaniac on the topic.
I often struggle with coming up with an answer that can fit into the 140
characters available via Twitter, but clearly this is not a good strategy.</p>

<p>As an early Christmas 2012 present to all my loyal followers, who put up with
my never-ending stream of nonsense and provide a slowly-increasing portion
of my income, here are my thoughts on how to get started with testing your
PHP code.</p>

<h2>Learn how to recognize untestable code</h2>

<p>The worst feeling in a programmer&#8217;s world has to be sitting in front of a
piece of code that you didn&#8217;t write yourself but is critical to the success
of your business. You will be told that it&#8217;s of the utmost importance
that you GOD SAKES DON&#8217;T BREAK ANYTHING OR ELSE WE ARE DOOMED.</p>

<p>While I don&#8217;t get the same kinds of warnings from my employers, I am familiar
with that feeling of trying to figure out not only what the code in front
of you is supposed to do, but what the developer who came along before you was
even THINKING ABOUT in that code.</p>

<p>When it comes to testing code, there are two principles that you have to
strive to aim for:</p>

<ul>
<li>find a way to pass dependencies into your code</li>
<li>find a way to break down your code into the smallest modules possible</li>
</ul>


<p>By following this two simple-but-extremely-difficult-to-do ideas, you will
end up with code where writing tests becomes so easy you will be doing it
without a second thought.</p>

<p>No more static method calls. Get rid of those private and protected methods.
Stop creating new objects inside a method. Think about passing data around
instead of objects. Work hard to make sure your methods have little-to-no
<a href="http://en.wikipedia.org/wiki/Side_effect_(computer_science">side effects</a>).
Decouple your data source from the code that manipulates results from it. More
importantly, understand why all these things are barriers to having an easily-testable
code base.</p>

<p>In short: do all the kind of hard work and drudgery that many managers tell
you is a waste of time and will not return any value to your employer. I say
screw those guys and instead feel awesome about working on building light, nimble systems full
of tests that let you go home from work on time.</p>

<h2>Keep learning the language</h2>

<p>Tests are just code. Keep learning how to write better PHP code. Understand why
so much of what is on <a href="http://phpsadness.com">PHP Sadness</a> is actually trying
to help us get better. Understand why the array in PHP is awesome. Learn
the <a href="http://www.meetup.com/dallasphp/events/59505212/">iterator drinking game</a>.</p>

<p>In short, the more you know about the language the more likely you are to learn
how to solve problems using core functionality instead of constantly implementing
solutions in code you wrote yourself.</p>

<h2>Chain units of code together for greatness</h2>

<p>I&#8217;ve talked about in other places
about my thoughts on the UNIX philosophy. For the impatient, it is about creating
small, single-purpose units of code and then chaining them together to
accomplish awesome things.</p>

<p>If you&#8217;re ever searched online for ways to do things from the command line
in various flavours of Linux distributions, you will understand what I mean.
&#8220;Take sed and cat and awk and grep and pipe it through cut and then to sort
and you will get exactly what you want.&#8221;</p>

<p>That sort of stuff is awesome, and fits in rather nicely with the concept of
writing small modules of easily-testable code.</p>

<h2>Start asking &#8220;how am I going to test this?&#8221;</h2>

<p>This is the first question I ask when I am presented with a problem that I need
to solve using code. From that one extremely important question all the best
practices that are associated with building highly-testable code emerge from.</p>

<p>If it is not obvious how you are going to be able to create automated tests
for a particular set of functionality, it probably means you haven&#8217;t thought
hard enough about the problem you are trying to solve.</p>

<p>I&#8217;m not saying every problem has a testable solution. But any problem where
you have expected results based on known input is a scenario that you can
test for. Database queries. 3rd party API&#8217;s. Request routing. Fizz Buzz.
These are all things that we can test, by making sure to follow some of
those key ideas I advocated above.</p>

<p>Test-centric development is about using tools as a way to create API&#8217;s and
interfaces that are simple, easily testable, and easy to modify going
forward.</p>

<p>Adding new features becomes a potentially-simple process consisting of:</p>

<ul>
<li>design new feature</li>
<li>write tests for these new features</li>
<li>write code until the tests pass</li>
<li>go home on time</li>
</ul>


<h2>Stop people from pushing code without proof it&#8217;s fixed</h2>

<p>Sure, you don&#8217;t have any tests RIGHT NOW. But I&#8217;m sure you&#8217;ve got bugs to fix
in your code. Write tests to verify that the bug exists. I&#8217;m sure you&#8217;ll find
your code isn&#8217;t as modular or testable as you thought it was.</p>

<p>Once you&#8217;ve reproduced the bug, then write some code until the bug GOES AWAY.
Then push your updated code into production. Rinse and repeat until you have
a very highly-targeted test suite and a bunch of highly-targeted fixes for
known mistakes in the application. That is what I call real-world testing.</p>

<p>So make sure that nothing that fixes something goes up into production, no
matter how desperate the circumstances, without proof that this fix actually
is a fix instead of a wild guess.</p>

<h2>Stop people from doing things manually</h2>

<p>It&#8217;s the 2nd year of the 2nd decade of the 21st century. The internet is
full of instructions on how to automate just about anything. Spend an afternoon
studying that instead of dreaming about an advertising-driven disruptive
startup.</p>

<p><a href="http://www.opscode.com/">Chef</a>. <a href="http://puppetlabs.com">Puppet</a>. Shell scripts. <a href="http://jenkins-ci.org">Jenkins</a>. <a href="http://travis-ci.org">Travis</a>. Virtualized servers. Learn these things. Use them. You
will thank me. Maybe enough to send me money via PayPal. Automate everything
that you keep finding yourself doing manually, and then figure out if there
are ways to not even do those things. You might be surprised.</p>

<h2>Stop using tools without test suites</h2>

<p>I treat any PHP tool that does not have its own test suite as a black box
that cannot be trusted. Tests show that the developer cares about the quality
of the work they do, and also provides real examples on how to do things.</p>

<p>Black boxes are not things you should be relying on when the going gets tough.
Treat any code that you cannot easily test as being suspicious and likely
broken. I feel the same way about code <em>I</em> have written, so imagine what
I must think of other people&#8217;s stuff.</p>

<h2>Always wonder if you&#8217;re doing it right</h2>

<p>Integration tests are a scam. Unit tests don&#8217;t fix bugs. Simple enough code
doesn&#8217;t require tests. Pair programming is a cargo-cult practice. PHP sucks.
Mobile applications are the future. Documentation comes after the work is
done. Nobody likes a developer who asks too many questions. You work in the
real world where results matter. Exit statuses are better than throwing
exceptions. Asynchronous calls always result in callback hell.</p>

<p>Not everything in the above paragraph is true. The only way to find out is
to get out there and figure out if it is true or not for yourself.</p>

<p>Keep on testing. I&#8217;m here to help. Merry Christmas everyone.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The birth of Grumpy Learning]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/12/02/the-birth-of-grumpy-learning/"/>
    <updated>2012-12-02T00:00:00-05:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/12/02/the-birth-of-grumpy-learning</id>
    <content type="html"><![CDATA[<p>It&#8217;s no secret that I have been pushing my &#8220;grumpy programmer&#8221; brand hard.
Why not? It&#8217;s delivering a non-trivial amount of side income for me and I
have been really enjoying it.</p>

<p>This past fall I taught an in-person course that I called my &#8220;PHP Testing
Bootcamp&#8221; where I spent about 6 hours showing a bunch of PHP programmers
how to twist their code into testable shape. That got me to thinking that
I want to do more of that, as I found that process enjoyable as well.</p>

<p>As I also create more products I need a place for them all to live. I have
books, and now a course I can teach and I am planning on producing
screencasts for sale as well. With that in mind, I am happy to announce
I have created <a href="http://grumpy-learning.com">Grumpy Learning</a>, an umbrella
site for all my training and teaching efforts to hang from. While you are
there, please join the mailing list via the form I have up there. I promise
to not give your email address to anyone else and will give you something
every two weeks related to testing or share other thoughts I have.</p>

<p>As part of this, I will be teaching my &#8220;PHP Testing Bootcamp&#8221; course again
but this time doing it online. Check out the <a href="http://phptestingbootcamp.eventbrite.com/">site for the course</a>
for details, but here&#8217;s the summary:</p>

<p>9 tickets available to do the course with me live at $250 per student. Three
session (January 3, 10 and 17) running from 9pm until about 11pm Eastern
Standard Time. I&#8217;ve already sold 3 of the 9, so you might want to hurry up.</p>

<p>Then I have up to 50 tickets available to get just the recordings of the
course for $125. If you can&#8217;t make it due to time zone differences or
prior commitments, the videos of me teaching the course and answering
questions is a great option. I&#8217;ve sold 2 of these, so plenty of them
left.</p>

<p>Students who participate in the live sessions will also get access to the
videos as part of their tickets.</p>

<p>If you&#8217;ve ever wondered how someone who takes coding and testing seriously
works in a test-centric manner, this is your chance. Give yourself an
awesome gift for the holiday: a chance to learn how to write testable
code and the tools that make it happen.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Not Really Rebels: My Øredev 2012 Experience]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/11/17/not-really-rebels/"/>
    <updated>2012-11-17T00:00:00-05:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/11/17/not-really-rebels</id>
    <content type="html"><![CDATA[<p>Many months ago I found out about <a href="http://oredev.org">Øredev 2012</a> and submitted
a proposal to give my talk on building testable PHP applications. Much to my
surprise it was accepted and plans were hatched to fly me across the Atlantic
and give my talk.</p>

<p>The theme of this year&#8217;s edition of the conference was &#8220;Viva La Rebellion&#8221;.
I&#8217;m guessing that they were hoping by accepting talks that seemed to fall out
of the mainstream they would inspire people to want to do things differently.</p>

<p>In that regard, I think they can declare it a success. The content was
widely varied, as you would expect from a conference featuring multiple
platforms and multiple programming languages.</p>

<p>However, the sad reality is that, in my opinion, it&#8217;s really only the speakers
who were there doing something revolutionary. I ended up spending quite a
bit of time hanging around with legendary Internet curmudgeon <a href="https://twitter.com/zedshaw">Zed Shaw</a>.
He was generous with his time and his comments, even after he found out that PHP was my bread-and-butter.</p>

<p>He gave a lightning talk where he explained his own experiences in rebelling
from inside a large monolithic organization, the US army, in order to prevent
himself from doing something he didn&#8217;t want to do. He also brought up the
point that so many people project an aura of rebellion through clothes, or
programming language of choice, but still start each day by sitting down
in front of a computer and essentially asking their boss &#8220;how can I make
you rich today, sir?&#8221;</p>

<p>From my own perspective, that&#8217;s bang on. I joke all the time when on IRC that
all the perks that employers attempt to provide their employees are really
just things to distract you from the fact that you are a slave, a digital
sharecropper. I instead prefer to work from home as a way of making my
chains fit a little less snug and to not have to hear the constant rattling.</p>

<p>I will also be truthful when I say that my current <a href="http://synacor.com">employer</a>
treats me very well, allowing me some real freedom in terms of projects I get
to work on. A shitty job is one where you little to no say in what you get to
do. Been there, won&#8217;t ever do that again.</p>

<p>So if you have the fire that is &#8220;in your belly&#8221;, that yearning to do something
more with your time than just help someone else get rich, you speak at
conferences. Those are opportunities to teach people about things, to speak
to other like-minded people, to really take chances and find out whether you
really know what you are talking about.</p>

<p>More importantly, it provides a way for you to gauge your own knowledge and
skills compared to those who are your peers in terms of willingness to share
knowledge. I was pleasantly surprised to find that when I went to talks
about technologies I don&#8217;t use, I was understanding the concepts they were
talking about.</p>

<p>I&#8217;m only a rebel in the sense that I am attempting to popularize an approach
to writing code that most PHP developers don&#8217;t use, by using automated tests to
drive the design of the code. The real rebels are people who challenge
pre-conceived notions within a community and then share what they&#8217;ve found.
Just because you use Rails doesn&#8217;t make you a rebel. More like using PHP
makes you one these days.</p>

<p>I did attend sessions about 2/3 of the time, the rest of the time spent
either working on my PHPUnit book or just relaxing in the super-awesome
speakers &#8220;cave&#8221; they set up for us.</p>

<p>On Tuesday I only went to a morning workshop given by <a href="http://vimcasts.org">Drew Neil</a>
about &#8220;Vim Mastery&#8221;. I had ulterior motives to go: I had sponsored an episode
two years ago and I bought a copy of his book <a href="http://pragprog.com/book/dnvim/practical-vim">&#8220;Practical Vim&#8221;</a>.
After I got him to sign it I got 3 hours of good instruction on how to best
use Vim by learning how to do things more efficiently. Text objects and figuring
out repeatable sequences were the two big takeaways for me.</p>

<p>After that I hung out with a few of the other speakers and somehow a group of
us who were supposed to go out on a tour of Malmo missed the bus for the
tour. Oh well.</p>

<p>Wednesday was the first day of the conference proper, with Monday and Tuesday
being just for half-day and day-long tutorials. The keynote speaker was
David Rowan, who is the editor for the UK edition of WIRED magazine. Lots
of talk about how technology is awesome and how the world has been changed
by software, and how software will be used to help solve some really tough
problems going forward.</p>

<p>All I could think of was the future is already kind of looking like <a href="http://zenarchery.com/full-text-of-the-grim-meathook-future-thing/">this</a>.</p>

<p>I skipped the first set of talks to work on putting the final touches on
my own presentation that was later in the day and then watched /dev/hell
guest <a href="http://twitter.com/searls">Justin Searls</a> give a talk about the
value of mock objects in your tests. Justin is an awesome speaker, despite
his protests to the contrary and presented a very compelling set of strategies
for using mock objects in your tests.</p>

<p>My favourite part of the talk (besides the end, HAHAHAH just kidding) was
where he talked about mocking anti-patterns. Yes, there is such a thing as
using mocks incorrectly. You can check out the talk <a href="http://oredev.org/2012/sessions/budgeting-reality-a-new-approach-to-mock-objects">here</a>.</p>

<p>After lunch I sequestered myself again to make sure I was ready to give my
talk, and then popped up at 3:45pm to give my talk. Yes, it&#8217;s true, there
were only 5 people in the room for my talk. PHP is not popular in Sweden
and I was also up against some good speakers, including the creator of
<a href="http://jenkins-ci.org">Jenkins</a>. These things happen, but my talk was
<a href="http://vimeo.com/53065670">recorded</a> for anyone who was not there to see.</p>

<p>After my talk I stuck around to watch Konstantin Haase from <a href="http://travis-ci.org">Travis-CI</a>
talk about what they do at Travis and provide a little bit of insight into the
challenges they face in running a Continuous-Integration-As-A-Service application.</p>

<p>Finally, at 6pm there was a closing keynote by Jim McCarthy, one of those guys
who kept popping up at key points in the history of software development and
he talked about his experiences leading the team that ended up building
Visual C++.</p>

<p>He went on to talk about how he and his wife have devoted a number of years
now to studying how groups of developers work and on techinques that can be
applied to help them get more interesting work done. Not that he shared many
of them as that is how he makes his living.</p>

<p>Can&#8217;t say that I agreed with his statement that the fact that
people in China were banned from seeing Facebook and Twitter was &#8220;no big deal&#8221;.
I had expected to hear more stuff about &#8220;culture hacking&#8221;, but maybe I just
had some preconceived ideas as to what that really meant.</p>

<p>Then I had dinner and drinks with some of the other speakers, and went to
bed happy that I delivered what I thought was a good talk.</p>

<p>Thursday&#8217;s opening keynote was by fellow Canadian <a href="https://twitter.com/raganwald">Reg Braithwaite</a>
where he really talked about rebellious people, and the 4 most common roles
we find within any marketplace of ideas: Leader, Rival, Innovater, Everyone Else.
Fascinating analysis of how people&#8217;s refusal to understand these four roles
leads to much unhappiness and even how entities move from one role to another.</p>

<p>Again, I highly recommend
<a href="http://oredev.org/2012/sessions/the-rebellion-imperative">watching the video</a></p>

<p>Next I went to Fred George&#8217;s talk on Micro-service architectures, where
he talked about how he led a team that went to extremes while building a
service-oriented architecture, by creating services so small (on the order
of 100 lines of code) that some of the concerns about unit testing and
versioning just went away due to size.</p>

<p>I have my own concerns about how to scale something like this, but it provides
a valuable lesson in really breaking down functionality of services into
the smallest pieces possible and then monitoring services to make sure they
are being used. Sort of like a survival-of-the-fittest contest for services,
giving developers the freedom to create multiple versions of services, running
them at the same time. Being so small, the cost of rewriting them, even using a
new language, was minimal.</p>

<p>Next up was a talk on automated testing strategies for databases. It&#8217;s rare that
I see a talk that really disappoints me. This was one. Nothing new, nothing
unconventional, nothing that a few people with more than a couple of years&#8217; experience
using databases could not have come up with.</p>

<p>After lunch I watched a talk about the <a href="http://geteventstore.com">Event Store</a> and
felt weirded out by the talk. I wasn&#8217;t quite sure what it was for, what problem
it was solving, and the whole talk felt like a very smooth and practiced sales
pitch for a commercial technology. Yes, they had some impressive stats in terms
of how it performed on the presenters laptop but I came out of that talk not
really understanding what it was for. I also was 99.999% certain that one part
of the demo was completely faked. The presenter entered some data into a
form for an online chat application built with it, and what was displayed on
the screen did not match AT ALL what he had typed in. Very strange.</p>

<p>Next was a series of lightning talks. I sat in the set from Hampus Jakobsson
(talked about learing if you really loved something by doing it every day
for a month and then giving it up), Chris Hughes (talked about his experiences
with really doing things the way he wanted and not caring about the consequences)
and then Zed Shaw talked about why none of the attendees to the conference were
really rebels.</p>

<p>Finally, I watched <a href="https://twitter.com/steveklabnick">Steve Klabnik</a> talk about
building Hypermedia API&#8217;s. I think that anyone who is designing an API they
really expect people to use should <a href="http://oredev.org/2012/sessions/designing-hypermedia-apis">watch the talk</a>
to get a feel for how tough a task it is to really build one.</p>

<p>The next talk was &#8220;Why Mud Rules&#8221; by Brian Footer. Brian talked about the
tendency of code to become a big ball of mud, and why that offends so many
developers. The money quote in his talk was &#8220;What do you call people who
ship big balls of mud? Millionaires.&#8221; It&#8217;s a reminder that shipping still
matters, even if the code is terrible in quality.</p>

<p>I had dinner with Felix Geisendörfer and Drew after this talk and spent more time hanging
out with Felix while he hacked on the code for controlling his drone.</p>

<p>On Friday, what could&#8217;ve been an interesting keynote by someone working
extremely hard to get fibre and high-bandwidth internet connections to homes
around Sweden was
wrecked and cut short by the MC, who wasted a lot of time on an audience
participation stunt. Also a diversion into Swedish rape laws was unwelcome.</p>

<p>After the keynote I watched Felix give a talk about
Node.js by demonstrating the library he had written for controlling his
AR drone quadcopter using Node.js. You have not really been to a conference
until you&#8217;ve watched someone fly a drone using cURL CLI commands that speak
to a web server RUNNING ON THE DRONE.</p>

<p>After that I sat in <a href="https://twitter.com/denisejacobs">Denise Jacobs&#8217;</a> talk
about sparking creativity, and some techniques for getting yourself into
The Zone, The Flow, whatever you want to call that state where you can be
really productive. Lots of good reminders on removing distractions and
obstacles to being productive at work.</p>

<p>Following Denise&#8217;s talk, I went to José Valim&#8217;s talk about <a href="http://elixir-lang.org">Elixir</a>, which is
a Ruby/Python style language that sits on top of the Erlang VM. It looked
very interesting to me, definitely worth checking out for potential future
use in applications where concurrency become an issue. Plus you can drop down
into the weirdness that is Erlang when required.</p>

<p>After that I just kind of hung out with people in the speaker area, having some
great conversations with all sorts of people, until it was time for Hojun Song&#8217;s
presentation about his project to send an open source satellite into orbit.
I have to admire his persistence, and how he&#8217;s financing the project by
selling t-shirts! I was going to buy one, but he was not selling one in my
size&#8230;</p>

<p>Then the conference was over. One last dinner with the speakers I had met
and then I spent Saturday doing a day trip with Reg Braithwaite to Copenhagen
to meet with two <a href="https://twitter.com/jippi">new</a> <a href="https://twitter.com/jose_zap">friends</a>
who are PHP devs working in Copenhagen. Christian and Jose were awesome hosts
as they led us on a walking tour of the city. I also found out just how expensive
alcohol really is in Northern Europe. Two Irish coffees with double shots of
whiskey: CDN$40. Yikes.</p>

<p>All in all, I had an awesome time.</p>

<p>Even though I was the only PHP talk at this conference, I realized that
I understood a lot more about programming than I realized. So much is
transferable across languages and platforms. Go to conferences like this
to broaden your skill set, to check out how users of other languages
are solving problems, and you cannot stop from becoming a better programmer.</p>

<p>Øredev treated me very well, and I would consider going back again to speak
if my future plans allow me to fit it in.</p>

<p>Please, PLEASE check out the <a href="http://oredev.org/2012/videos">recordings of the presentations</a>
they have made available. Not every presentation is there yet, but they have
plans to make them all available under a Creative Commons license.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[PHPSpec and the new wave of testing]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/10/18/phpspec-and-the-new-wave-of-testing/"/>
    <updated>2012-10-18T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/10/18/phpspec-and-the-new-wave-of-testing</id>
    <content type="html"><![CDATA[<p>I promised <a href="https://twitter.com/everzet">@everzet</a> almost two weeks ago that
I would take a look at his latest project, <a href="http://www.phpspec.net">phpspec</a>,
and let him know what I think.</p>

<p>I think that we are witnessing the first wave of new testing tools in the PHP
community that allow developers to wrap their applications in automated tests.</p>

<p>I am familiar with the BDD-style that is being promoted in PHPSpec, through
my work with <a href="http://behat.org">Behat</a> to create automated user acceptance
tests. I think if you want a tl;dr version of PHPSpec I would tell you
&#8220;write hybrid unit/integration tests using plain language&#8221;.</p>

<p>The concept that is being promoted is &#8220;SpecBDD&#8221;. It means &#8220;writing tests
to a specification and then writing code until that specification is met.&#8221;
Not a lot different than writing tests using tools like PHPUnit.</p>

<p>Your still going to have to write code that you can test if you want to
use phpspec. That means you still need to know about dependency injection
and other characteristics of testable code. Sorry, no magic testing pixie
dust here.</p>

<p>I was also surprised to see the use of mock objects, which are being
called &#8220;Prophet Objects&#8221;, but that means that you can really write specs
that test for things in isolation.</p>

<p>Mock objects are, in my opinion, the conceptual stumbling block that
developers need to get over in order to really, deeply understand how
to write effective tests. I am happy to see phpspec promote this idea
and provide a fairly simple API to do it.</p>

<p>The process is the same as it would be if you were using PHPUnit: write
the test / spec, and write the damn code until everything passes. Again,
no magic testing pixie dust.</p>

<p>(By the way, if someone makes me a &#8220;magic testing pixie&#8221; t-shirt, men&#8217;s size
XXL or larger, I will purchase it YESTERDAY).</p>

<p>Keep on cranking out the tools, make them useful for people OTHER than testing
zealots to use them, and you have yourself an unstoppable wave of automated
testing.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[First steps in Node testing]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/10/15/first-steps-in-node-testing/"/>
    <updated>2012-10-15T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/10/15/first-steps-in-node-testing</id>
    <content type="html"><![CDATA[<p>As I&#8217;ve been promising, I wanted to share my thoughts as I am starting to
brush up on my JavaScript and learn how to do something non-trivial with
<a href="http://nodejs.org">Node.js</a>. Of course, I want to use tests to
help me drive my work, and also as a way to keep me focused on small iterations
of work.</p>

<p>I am intending to write some code to act as an API for the <a href="http://www.ibl.org">site that runs my simulation baseball league</a>
and refactor the existing PHP code to consume that API instead of speaking
to the database through CakePHP (really OLD CakePHP at that too) models.</p>

<p>So, it took me a while to search around and find enough information to create
my first integration test. In the end, the stack is <a href="http://visionmedia.github.com/mocha/">Mocha</a>
to do the testing, with <a href="https://github.com/visionmedia/supertest">SuperTest</a> to handle
all the HTTP testing.</p>

<p>So, the app itself is built on <a href="http://expressjs.com/">Express</a> and
talking to a Postgres database using <a href="https://github.com/brianc/node-postgres">node-postgres</a>.
It seemed to me that express was the best solution for a newcomer to Node but
familiar with MVC / modern web application paradigms.</p>

<p>So, let&#8217;s take a look at some of the code:</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>
<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>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="c1">// Front controller for our API</span>
</span><span class='line'>
</span><span class='line'><span class="kd">var</span> <span class="nx">application_root</span> <span class="o">=</span> <span class="nx">__dirname</span><span class="p">;</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&quot;express&quot;</span><span class="p">);</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">path</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&quot;path&quot;</span><span class="p">);</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">pg</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;pg&#39;</span><span class="p">);</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">model</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./transactionmodel&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// Create our database connection</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">connectionString</span> <span class="o">=</span> <span class="s2">&quot;pg://chartjes:@localhost:5432/ibl_stats&quot;</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="nx">pg</span><span class="p">.</span><span class="nx">connect</span><span class="p">(</span><span class="nx">connectionString</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">client</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">pg</span><span class="p">.</span><span class="nx">Client</span><span class="p">(</span><span class="nx">connectionString</span><span class="p">);</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">tm</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">model</span><span class="p">.</span><span class="nx">TransactionModel</span><span class="p">(</span><span class="nx">client</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// Config things we need to get the app going</span>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">configure</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">bodyParser</span><span class="p">());</span>
</span><span class='line'>  <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">methodOverride</span><span class="p">());</span>
</span><span class='line'>  <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">app</span><span class="p">.</span><span class="nx">router</span><span class="p">);</span>
</span><span class='line'>  <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="kr">static</span><span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">application_root</span><span class="p">,</span> <span class="s2">&quot;public&quot;</span><span class="p">)));</span>
</span><span class='line'>  <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">errorHandler</span><span class="p">({</span> <span class="nx">dumpExceptions</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">showStack</span><span class="o">:</span> <span class="kc">true</span> <span class="p">}));</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/transactions/archived&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="kd">var</span> <span class="nx">done</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">transactions</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">if</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s2">&quot;Error querying transactions&quot;</span><span class="p">,</span> <span class="mi">500</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">transactions</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">var</span> <span class="nx">currentTransactions</span> <span class="o">=</span> <span class="nx">tm</span><span class="p">.</span><span class="nx">getArchived</span><span class="p">(</span><span class="nx">done</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/transactions/current&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="kd">var</span> <span class="nx">done</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">transactions</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">if</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s2">&quot;Error querying transactions&quot;</span><span class="p">,</span> <span class="mi">500</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">transactions</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="p">};</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">var</span> <span class="nx">currentTransactions</span> <span class="o">=</span> <span class="nx">tm</span><span class="p">.</span><span class="nx">getCurrent</span><span class="p">(</span><span class="nx">done</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">app</span><span class="p">;</span>
</span></code></pre></td></tr></table></div></figure>


<p>I am also using the awesome <a href="http://postgresapp.com/">Postgress.app</a>
while working on this app on my laptop.</p>

<p>One of the things I learned while I started to build my tests was that if I
wanted to test stuff in isolation, I needed to alter things slightly and
export my Express &#8220;app&#8221; as a module instead of including the command
necessary to make it run and listen for requests on a specific port.</p>

<p>Now, I did find some blog posts about how to write integration tests, but
they either wanted to use <a href="http://coffeescript.org/">CoffeeScript</a>
or was using custom modifications to the testing tools. I am not familiar
enough to write stuff like that (not in JavaScript anyway) so out of
frustration I looked at the source code of Express since <a href="http://brianstoner.com/blog/testing-in-nodejs-with-mocha/">this blog post</a>
mentioned how he created a custom version of something used to help in
testing.</p>

<p>When I looked at the source of Express, the author had replaced a bunch
of stuff with code that simply imported SuperTest. I think I swore
really loudly at myself for not looking sooner.</p>

<p>Armed with the knowledge that I had my missing piece for the integration
test, I wrote a simple one.</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>
<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>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;../app&#39;</span><span class="p">);</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">request</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;supertest&#39;</span><span class="p">);</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">assert</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;assert&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">describe</span><span class="p">(</span><span class="s1">&#39;Transaction API&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">it</span><span class="p">(</span><span class="s1">&#39;GET /transactions/current should return 200&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="nx">request</span><span class="p">(</span><span class="nx">app</span><span class="p">)</span>
</span><span class='line'>      <span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/transactions/current&#39;</span><span class="p">)</span>
</span><span class='line'>      <span class="p">.</span><span class="nx">expect</span><span class="p">(</span><span class="s1">&#39;Content-Type&#39;</span><span class="p">,</span> <span class="sr">/json/</span><span class="p">)</span>
</span><span class='line'>      <span class="p">.</span><span class="nx">expect</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="nx">done</span><span class="p">);</span>
</span><span class='line'>  <span class="p">});</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>


<p>It worked, which is the first step. How about another test? Let&#8217;s make
sure that if we do that call to /transactions/current and verify that
we are getting back a result we expect</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>
<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>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">it</span><span class="p">(</span><span class="s1">&#39;GET /transactions/current should return expected results&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;fs&#39;</span><span class="p">);</span>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">currentData</span> <span class="o">=</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span><span class="p">(</span><span class="s1">&#39;./current&#39;</span><span class="p">,</span> <span class="s1">&#39;utf8&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span> <span class="k">throw</span> <span class="nx">err</span><span class="p">;</span> <span class="p">}</span>
</span><span class='line'>      <span class="k">return</span> <span class="nx">data</span><span class="p">;</span>
</span><span class='line'>    <span class="p">});</span>
</span><span class='line'>    <span class="nx">request</span><span class="p">(</span><span class="nx">app</span><span class="p">)</span>
</span><span class='line'>      <span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/transactions/current&#39;</span><span class="p">)</span>
</span><span class='line'>      <span class="p">.</span><span class="nx">expect</span><span class="p">(</span><span class="nx">currentData</span><span class="p">,</span> <span class="nx">done</span><span class="p">);</span>
</span><span class='line'>  <span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>


<p>For this test, I am reading in a text file that contains, for a known database,
a JSON representation of that data. Then I do a call to my API call, and
compare the result I get back to my fixture. Just like any test I would
write in PHP. Compare the expected to the actual.</p>

<p>In <a href="http://devhell.info/post/2012-10-06/the-grace-hopper-rape-whistle/">episode 21 of /dev/hell</a>
I talked a bit about how I felt that testing skills from one language are
transferrable to another. I think the fact that once I figured out that SuperTest
was the missing tool, it took me less than 30 minutes to write those two tests.
That includes research time reading the documentation for both Mocha and SuperTest.</p>

<p>More tests are sure to come, but I think I&#8217;ve found the right set of tools
for the time being.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Grumpy Programmer's PHPUnit Cookbook]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/10/12/grumpy-phpunit/"/>
    <updated>2012-10-12T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/10/12/grumpy-phpunit</id>
    <content type="html"><![CDATA[<p>TL;DR: I&#8217;ve started working on <a href="http://grumpy-phpunit.com">a new book</a>.</p>

<p>Having written a book that shows you how to <a href="http://grumpy-testing.com">write code that is testable</a>
it seemed natural to write a companion book for that, to give people a better
understanding of how to use some of the testing tools.</p>

<p>To that end, I&#8217;ve started working on &#8220;The Grumpy Programmer&#8217;s PHPUnit Cookbook&#8221;
to be released in early 2013 (I&#8217;m thinking end of January / beginning of February
if everything works out).</p>

<p>The book will be a collection of tips and tricks on how to use the gold standard
of PHP unit testing frameworks, the mighty <a href="https://github.com/sebastianbergmann/phpunit/">PHPUnit</a>. If you visit
the <a href="http://grumpy-phpunit.com">website for the book</a> you can join a mailing list
to be notified when the book is ready.</p>

<p>By joining that mailing list, you will also receive some goodies along the way
as the book gets written. No, I&#8217;m not going to tell you what they are.</p>

<p>The book will be $25. No, I don&#8217;t know how big it will be. Maybe you will end up paying
$1 per page, but let&#8217;s hope not.</p>

<p>The book will also be published through <a href="http://leanpub.com">Leanpub</a> as I am
110% happy with what they have done for me, and I encourage anyone else who wants
to write their own technical book and keep most of the money from their efforts
to consider using them.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Happy Thoughts]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/10/10/happy-thoughts/"/>
    <updated>2012-10-10T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/10/10/happy-thoughts</id>
    <content type="html"><![CDATA[<p>Contrary to urban legend, I do have the occasional happy thought. You can&#8217;t
raise 2 little girls with a tolerant wife unless you are able to get into that
happy place almost on demand.</p>

<p>I do have friends who appear to be bottomless sources of happiness and good
cheer, their Twitter feeds full of positive messages to all. That is not my
path, but not for the reasons you might suspect.</p>

<p>I seem to generate a lot more feelings of &#8220;satisfaction&#8221; than outright
&#8220;happiness&#8221;. I also think, that being an agnostic person when it comes to organized religion, that I don&#8217;t put a
lot of stock in prayer or &#8220;the power of positive thinking&#8221; and other related
things. I also believe that Fate and Destiny plays a big role in people&#8217;s lives, and
while we are in control of our day-to-day lives, you are moving down a pre-destined
path in the greater scheme of things.</p>

<p>My mother (a retired high-school teacher) always told her students that they
are &#8220;not losers, but choosers&#8221;. When my thread has played out to a point
where it intersects with someone else&#8217;s, I always have to make a choice.
So don&#8217;t think I am a fatalist who believes all is pre-ordained. I believe
a wise person once said &#8220;luck is the intersection of opportunity and skill.&#8221;</p>

<p>Not that I believe I am destined for greatness in any way. My programming skills
are not in the field of inventing (or reinventing) awesome pieces of technology
for the greater good of all. I am more the type that likes to combine things
together and figure out how to make something BETTER come out of all of it.</p>

<p>Hence my like for testing, and codified programming practices for a given
language. How I like to go to conferences, and organize meet-ups, and take
time out of my after-work schedule to just shoot the shit over Skype with
people who are willing to toss away the grumpy cartoon character I play on
Twitter to talk to the person underneath it.</p>

<p>So, not a lot of happy thoughts come out of me, more like &#8220;man, I am glad
this shit worked out in a way I am satisfied with&#8221;. Satisfaction IS what I
aim for, because my <a href="https://twitter.com/internet_widow">wife</a> can tell me
that I am my harshest critic, holding myself up to a pretty high standard
for whatever tasks I tackle when I am confident I can do a good job.</p>

<p>You can be happy. I&#8217;ll be over here feeling satisfied.</p>

<p>Thanks to <a href="https://twitter.com/CalEvans">the icon of the PHP community</a> for
the topic suggestion.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Biz Lessons Learned]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/09/21/biz-lessons-learned/"/>
    <updated>2012-09-21T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/09/21/biz-lessons-learned</id>
    <content type="html"><![CDATA[<p>It all started with me thinking &#8220;Let&#8217;s write a technical book as part of
National Novel Writing Month&#8221; and has progressed to me recently signing an
agreement to license copies of my book to an online tutorial site for
a number that is very close to all sales for the first book I ever wrote on
<a href="http://www.wjgilmore.com/books/read/refactoring_legacy_applications_using_cakephp">refactoring PHP applications to use CakePHP</a>.</p>

<p>Along the way I have learned some valuable lessons about the process, and at
the same time have been getting some great insights via Amy Hoy&#8217;s &#8220;I cannot
stop telling people who want to build their own things to go plunk the money
down for it&#8221; <a href="http://unicornfree.com/30x500/">30x500 course</a>.</p>

<p>So has my <a href="http://grumpy-testing.com">book</a> been a success? That depends on your point of view. Initially
I said I would be happy if I doubled the number of sales of my first book.
That would mean pulling in almost $5000. I gave myself a year. With this
licensing agreement, I have passed that number in 8 months.</p>

<p>But I always felt that while I was a pretty decent programmer and also good
at expressing my ideas to other people, I was missing something. That something
is MARKETING, folks. I was confident that I could write a book that people
would want, I just didn&#8217;t have the skills to convince people of that.</p>

<p>In a way, I was partially right.</p>

<p>I built up interest via social media. I promoted the book at least once
a week, almost always resulting in sales within minutes of the messages.
I gave away copies to user groups, who in turn promoted my book for me
and that also resulted in cool conversations AND book sales.</p>

<p>I don&#8217;t mind putting in the effort to promote my book this way. How else
are people going to know about it if I don&#8217;t share? Yes, making money off of
it is good. I was more concerned about making sure people knew there were
ways of making their lives as PHP programmers easier. Testing doesn&#8217;t have
to suck.</p>

<p>It felt good, and money was coming in. While I slept, and it was cool to
wake up every morning to emails from my <a href="http://leanpub.com">publisher</a>
telling me that someone had bought my book.</p>

<p>But it wasn&#8217;t enough. I felt like I could be making more money from my
efforts. I&#8217;ve been selling copies of my book at a pretty consistent rate since the
first big push when I launched, but that got me hungry for more. More books.
More courses. More training. More anything that can convert what I know
into money that I can then use to work for myself.</p>

<p>That&#8217;s where Amy&#8217;s course comes in. If you take it, you WILL LEARN HOW TO
MAKE IT HAPPEN. Amy shows you how to find audiences and figure out what&#8217;s
causing them pain or what they need to make more money. Amy also has an
awesome collection of alumni who also step up and share what they learned
as well.</p>

<p>Here&#8217;s the catch though: you have to do the work yourself. There is no
magic. You are going to work, and work hard. But at the end of it you are
going to be armed with the ability to go out there and build stuff that
people will be yelling &#8220;SHUT UP AND TAKE MY MONEY!&#8221; at you.</p>

<p>Isn&#8217;t that what you want?</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[5 Minute TDD]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/08/16/5-minute-tdd/"/>
    <updated>2012-08-16T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/08/16/5-minute-tdd</id>
    <content type="html"><![CDATA[<p>I created a screencast for you. No really, just for <em>you</em>.</p>

<script src="http://www.littlehart.net/atthekeyboard/javascripts/flowplayer-3.2.11.min.js"></script>


<p><a
href="https://s3.amazonaws.com/grumpy-testing/5m-TDD.mp4"
style="display:block;width:800px;height:600px;"
id="player">
</a></p>

<script language="JavaScript">
flowplayer("player", "http://www.littlehart.net/atthekeyboard/assets/flowplayer-3.2.14.swf");
</script>


<p>If you can&#8217;t view the video because you&#8217;re on a device that doesn&#8217;t support flash, or you want
to view it offline later, then
you can view it <a href="https://s3.amazonaws.com/grumpy-testing/5m-TDD.mp4">here</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How did I end up here?]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/08/08/how-did-i-end-up-here/"/>
    <updated>2012-08-08T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/08/08/how-did-i-end-up-here</id>
    <content type="html"><![CDATA[<h2>Challenge 0: have a computer around as a kid</h2>

<p>I&#8217;ve been programming computers since I was 10 years old. That&#8217;s 31 years and counting. I had my first paid programming
job at age 15, when I created a program for my mother&#8217;s private school to display a salary grid based on numbers they
entered via the program itself, written in Apple basic. Sadly, there was no testing framework available to me.</p>

<p>When I went to community college, it was before the Rise Of The Internet. I had net access and an email account,
but there was no graphical web browser I had access to. I remember seeing something called &#8220;Mosaic&#8221; on the desktops
in the computer labs, but I did not have access to it. So I surfed, hard core style, using Lynx. Yes, I am that
old.</p>

<h2>Challenge 1: get an IT job</h2>

<p>Once I was done with school, I landed a job working for a company that produced fully-licensed CD compilations for
professional DJ&#8217;s. I was their &#8220;IT guy&#8221; but ended up building my first web app: an online searchable catalog
that used MySQL. I wrote code that imported a CSV export from Microsoft Access and then built a form to let
people search for stuff. It sort of worked. I didn&#8217;t know about wild card searches or <a href="http://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_soundex">Soundex</a>
but I was pretty proud of myself.</p>

<ul>
<li>learned PHP</li>
<li>learned some MySQL</li>
<li>discovered I still liked programming</li>
</ul>


<h2>Challenge 2: get a programming-only job</h2>

<p>When that job ended, I found a job with a company that was using <a href="http://metahtml.sourceforge.net/">some programming language</a>
I had never seen before, and haven&#8217;t seen since. I also got to use PHP to build an online shopping store for a
specialty retailer.</p>

<p>Everything went well&#8230;until it didn&#8217;t, and people who weren&#8217;t stock holders (it was a publically-traded company)
got the boot.</p>

<ul>
<li>learned more PHP</li>
<li>learned to work as part of small team</li>
<li>failed the political office game</li>
</ul>


<h2>Challenge 3: Get a job on a bigger team</h2>

<p>After that job, I got to sit on my couch with my infant daughter and watch 9/11 happen in real time on my TV. A few
months later I got a job working for a company that dealt with online adult content and wanted to build a dating
site. The company still is around, and it&#8217;s not hard to google around to figure out who it is. It is a different
place now, but when I worked there I committed the first line of code for the project into a CVS repository.</p>

<p>It was a great education in what it takes to build a scalable PHP application, but my attitude was terrible while
I worked there. I was argumentative, belligerent, and basically acted like everything that was done that I disagreed
with was the worst decision ever. I learned what it was like to work on a large team, and I learned again that
getting along with your co-workers mattered when it was time to do things you really wanted to do.</p>

<p>I lost the political game, and lost it hard. My own damn fault, to be sure.</p>

<ul>
<li>learned even more PHP</li>
<li>used my first MVC-style framework (Mojavi!)</li>
<li>first exposed to unit testing</li>
<li>first exposed to virtual envrionments for dev work (BSD jails!)</li>
<li>learned that I needed to pay attention to the political game</li>
</ul>


<h2>Challenge 4: Go someplace you feel you&#8217;re wanted</h2>

<p>After leaving that job, I took a job working for a company that owned a network of online forums for sports and
auto enthusiasts, along with publishing several auto magazines. Terrible fit, never got to do anything except
play with CakePHP and start really blogging more. My blogging while working there led to me getting my next
job&#8230;and every job since.</p>

<ul>
<li>learned how to do technical blogging</li>
<li>learned how to contribute to an open source project (CakePHP)</li>
<li>learned epic trolling skills on a mailing list</li>
</ul>


<h2>Challenge 5: Work from home</h2>

<p>After leaving the forum job, I bounced through two jobs (left one cuz funding was pulled, left the other due
to severe personality conflict with boss) and landed my first serious telecommuting gig working for a
sports data integration company. I was sick of the long commute (90 minutes in the morning, two hours home)
and held out for a job where I could work from home.</p>

<p>Loved the job. Lots of freedom to build things the way I saw fit, with a few
constraints of language and associated tools (had to be ones we where using already). I also started ramping
up the blogging, and grew my reputation through speaking at conferences and trying to find people I could
always learn things from.</p>

<p>I also learned that when you build things for customers, you really should try to talk to those customers
as much as you can to understand how to build what they want.</p>

<ul>
<li>learned some Python</li>
<li>learned how to work remotely without someone needing to check up on you</li>
<li>learned how to explain technical things to non-techincal people given a proper context</li>
<li>learned how to self-promote on Twitter and build your &#8220;brand&#8221;</li>
<li>learned how to get accepted at conferences</li>
<li>learned how to get mad about getting rejected to speak at conferences</li>
<li>developed ridonkulous levels of confidence in both my own skills and my abilities to find jobs I want to do</li>
<li>started co-organizing a PHP user&#8217;s group in Toronto</li>
</ul>


<h2>Challenge 6: Find a job doing what you want to do</h2>

<p>Potential NFL and NBA strikes had me nervous about my awesome-to-work-for employer going under, so I jumped
ship and joined a start-up that was focussing on ecommerce within social media tools and networks. I liked
the guys I worked with, but felt out of place: the things I was passionate about (best practices and testing)
weren&#8217;t a good fit for the place they were in (OMG WE HAVE TO BUILD THIS THING AND GET IT LAUNCHED) so after
a personally-frustrating year I left to join a place doing the types of things I wanted to do.</p>

<ul>
<li>learned how to wrap tests around reluctant code bases</li>
<li>learned how to write an ebook</li>
<li>learned how to do a podcast about programming issues</li>
<li>started organzing a PHP conference in Toronto</li>
</ul>


<h2>Challenge 7: Keep finding challenges</h2>

<p>Which of course leads me to the present. I&#8217;m now doing the type of coding work I want to do: focusing on
testing practices, researching tools to improve our developer work flow, and also branching out in the outside
world to helping more developers be aware of just how valuable adding good testing practices to your skill
set could be.</p>

<p>You can see all the challenges I put in front of myself, and how things didn&#8217;t always end up the way I had hoped.
If I can overcome all this stuff, imagine what you can get done! There will never be a better time to get
involved in building stuff for the web. You are spoiled for choice on tools, languages and opportunities.</p>

<p>Don&#8217;t be scared. Be excited. It only gets crazier from here on out!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Watering Holes]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/07/31/watering-holes/"/>
    <updated>2012-07-31T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/07/31/watering-holes</id>
    <content type="html"><![CDATA[<p>I&#8217;m taking a product research and development course this summer and as
part of the course I am doing some research into where certain people
I am interested in hang out. As you know, I&#8217;m a big proponent of both
automated testing and best practices. I do a lot of very shallow
research via Twitter, but I want to know what places YOU all hang out
in to find out information about things like how to structure your
tests or what sort of practices you think could help you and your
team get better.</p>

<p>Share them in the comments!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[PHP Application Testing Bootcamp]]></title>
    <link href="http://www.littlehart.net/atthekeyboard/2012/07/27/php-application-testing-bootcamp/"/>
    <updated>2012-07-27T00:00:00-04:00</updated>
    <id>http://www.littlehart.net/atthekeyboard/2012/07/27/php-application-testing-bootcamp</id>
    <content type="html"><![CDATA[<p>If you are in the Greater Toronto Area and can make it out to York University&#8217;s
campus in North York, I will be teaching a <a href="http://phptesting-estw.eventbrite.ca/">PHP Application Testing Bootcamp course</a>
over three nights: August 13, 20 and 27th. Come out from 8pm to 10pm and push
your PHP and application testing skills to the next level.</p>

<p>Space is limited (15 students), so act fast and I hope to see some of you there!</p>
]]></content>
  </entry>
  
</feed>
