<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://edgibbs.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://edgibbs.com/" rel="alternate" type="text/html" /><updated>2026-01-05T12:55:20+00:00</updated><id>https://edgibbs.com/feed.xml</id><title type="html">Musings of a Software Development Manager</title><subtitle>lessons learned managing developers</subtitle><author><name>Ed Gibbs</name></author><entry><title type="html">Testing Patterns: Given-When-Then vs Arrange-Act-Assert</title><link href="https://edgibbs.com/2024/12/21/given-when-then-versus-arrange-act-assert" rel="alternate" type="text/html" title="Testing Patterns: Given-When-Then vs Arrange-Act-Assert" /><published>2025-02-11T00:00:00+00:00</published><updated>2025-02-11T00:00:00+00:00</updated><id>https://edgibbs.com/2024/12/21/given-when-then-versuis-arrange-act-assert</id><content type="html" xml:base="https://edgibbs.com/2024/12/21/given-when-then-versus-arrange-act-assert"><![CDATA[<p>Anecdotally I’ve recently noticed an uptick in presenting the AAA pattern for writing good tests. Most of my career I’ve thought about this from the <a href="https://martinfowler.com/bliki/GivenWhenThen.html">Given/When/Then</a> paradigm. My assumption much like the dominance of RSpec in Ruby was that was the common explanation/mnemonic when describing how to layout tests. The only other pattern I had a sense of was the old xUnit idea based around its minimalist methods:</p>

<ul>
  <li>setup</li>
  <li>assert</li>
  <li>teardown</li>
</ul>

<p>Given/When/Then was such a default that Jim Weyrich even created his own testing framework based on it, <a href="https://github.com/jimweirich/rspec-given">rspec-given</a>.  It comes out of the BDD movement where the focus was to not get so focused on the mechanics of testing, but more on the value of specifying expectations up front before writing the code to implement the tests. Gherkin sprouted out of this and it was further solidified by being built into tools like Cucumber and RSpec Given.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">describe</span> <span class="no">Formatter</span>
  <span class="n">describe</span> <span class="s2">"#add_emojis"</span> <span class="k">do</span>
    <span class="n">it</span> <span class="s2">"adds emojis to the string"</span> <span class="k">do</span>
      <span class="c1"># Given</span>
      <span class="n">formatter</span> <span class="o">=</span> <span class="no">Formatter</span><span class="p">.</span><span class="nf">new</span>
      <span class="n">string</span> <span class="o">=</span> <span class="s2">"Hello, World!"</span>

      <span class="c1"># When</span>
      <span class="n">formatted_string</span> <span class="o">=</span> <span class="n">formatter</span><span class="p">.</span><span class="nf">add_emojis</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>

      <span class="c1"># Then</span>
      <span class="n">expect</span><span class="p">(</span><span class="n">formatted_string</span><span class="p">).</span><span class="nf">to</span> <span class="n">eq</span><span class="p">(</span><span class="s2">"👋, 🌎!"</span><span class="p">)</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Apparently <a href="https://xp123.com/3a-arrange-act-assert/">AAA</a> was coined way back in the fairly early XP days by Bill Wake. Reading through his reasoning I appreciate that he was trying to define the steps as:</p>

<ol>
  <li><strong>Arrange</strong> -&gt; setup the collaborating object, mocks and construct the object</li>
  <li><strong>Act</strong> -&gt; actually perform an action usually calling a method or function</li>
  <li><strong>Assert</strong> -&gt; make the assertions</li>
</ol>

<p>When actually writing these he mentions that a TDD/BDD approach he favors is actually to sort of reverse the order for writing a test as:</p>

<ol>
  <li><strong>Assert</strong> -&gt; write this first because you’re trying to think about what the object should actually do (Test Driven Design)</li>
  <li><strong>Arrange</strong> -&gt; now you have an idea of what you need to setup the object</li>
  <li><strong>Act</strong> -&gt; actually call the method/function</li>
</ol>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">describe</span> <span class="no">ShoppingCart</span> <span class="k">do</span>
  <span class="n">describe</span> <span class="s2">"#total"</span> <span class="k">do</span>
    <span class="n">it</span> <span class="s2">"updates the total when adding a book"</span> <span class="k">do</span>
      <span class="c1"># Arrange</span>
      <span class="n">cart</span> <span class="o">=</span> <span class="no">ShoppingCart</span><span class="p">.</span><span class="nf">new</span>
      <span class="n">keycaps</span> <span class="o">=</span> <span class="no">Product</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">name: </span><span class="s2">"Emoji Keycaps"</span><span class="p">,</span> <span class="ss">unit_price: </span><span class="no">Currency</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mf">59.99</span><span class="p">,</span> <span class="s2">"USD"</span><span class="p">))</span>
      <span class="n">switch</span> <span class="o">=</span> <span class="no">Product</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">name: </span><span class="s2">"Clicky Switches"</span><span class="p">,</span> <span class="ss">unit_price: </span><span class="no">Currency</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="mf">0.27</span><span class="p">,</span> <span class="s2">"USD"</span><span class="p">))</span>

      <span class="c1"># Act</span>
      <span class="n">cart</span><span class="p">.</span><span class="nf">add_item</span><span class="p">(</span><span class="n">keycaps</span><span class="p">)</span>
      <span class="mi">75</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span>
        <span class="n">cart</span><span class="p">.</span><span class="nf">add_item</span><span class="p">(</span><span class="n">switch</span><span class="p">)</span>
      <span class="k">end</span>

      <span class="c1"># Assert</span>
      <span class="n">expect</span><span class="p">(</span><span class="n">cart</span><span class="p">.</span><span class="nf">total</span><span class="p">).</span><span class="nf">to</span> <span class="n">eq</span><span class="p">(</span><span class="mf">80.24</span><span class="p">)</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>I’m still sold on the nice rhyming structure of Given/When/Then as easy to remember and a little nicer sounding. People often shortcut to the <code class="language-plaintext highlighter-rouge">AAA</code> pattern and it becomes easy to forget what it’s trying to remind you of. As I get further in my career I find it encouraging from the early days of TDD where trying to get people to even think about writing a test was a long often fruitless discussion. Nowadays I have time to think about very small aspects of testing like helpful shortcuts to remember the common testing patterns.</p>]]></content><author><name>Ed Gibbs</name></author><category term="software development" /><category term="ruby" /><category term="rspec" /><category term="test driven development" /><summary type="html"><![CDATA[Anecdotally I’ve recently noticed an uptick in presenting the AAA pattern for writing good tests. Most of my career I’ve thought about this from the Given/When/Then paradigm. My assumption much like the dominance of RSpec in Ruby was that was the common explanation/mnemonic when describing how to layout tests. The only other pattern I had a sense of was the old xUnit idea based around its minimalist methods:]]></summary></entry><entry><title type="html">Inline setup versus let in RSpec</title><link href="https://edgibbs.com/2024/06/23/" rel="alternate" type="text/html" title="Inline setup versus let in RSpec" /><published>2024-06-23T00:00:00+00:00</published><updated>2024-06-23T00:00:00+00:00</updated><id>https://edgibbs.com/2024/06/inline-setup-versus-rspec-let</id><content type="html" xml:base="https://edgibbs.com/2024/06/23/"><![CDATA[<p><code class="language-plaintext highlighter-rouge">let</code> has a long history in RSpec having been introduced with a <a href="https://github.com/rspec/rspec-core/commit/4d67748f">commit</a> in 2009 and rolled out as
part of RSpec 2. I adopted it early on as the aesthetics appealed to me with <code class="language-plaintext highlighter-rouge">let</code> variables being defined first in little blocks with symbols. One of
our engineers wrote a macro in vim to quickly hoist instance variables in older style RSpec tests to let declarations. It became the default
style for everyone in RSpec with only a bit of controversy around <code class="language-plaintext highlighter-rouge">let!</code> which could be easy to miss in tests. I knew about the lazy initialization, but
it was the aesthetics I prized.</p>

<p>I remember a bit of a community debate a few years later with a famous Thoughtbot blog post entitled <a href="https://robots.thoughtbot.com/lets-not">Let’s
Not</a>. It argued pretty convincingly that let was a mystery guest pattern which you don’t want when writng
clear tests. Since our team’s default at that point was to use let, but we wrote pretty small Sandi Metz style classes with a single responsibility,
the <code class="language-plaintext highlighter-rouge">let</code>s weren’t causing a big headache. If the code and the specs were visible in a single editor window, it was easy to see what was going on.</p>

<p>Fast forward to working on one of the largest Ruby codebases in the world and I got reintroduced to the idea of containing the entire test inline.
Much of the codebase doesn’t fit in a single editor window and suddenly those little <code class="language-plaintext highlighter-rouge">let</code>s are screens away and hard to find. Add with nested contexts,
shared examples and the like I was really hating <code class="language-plaintext highlighter-rouge">let</code>. Some of the more painful specs potentially executed up to 100 <code class="language-plaintext highlighter-rouge">let</code>s before running an
individual spec and often fired hundreds of SQL queries. I continued to use it on newer refactored code, but eventually the team started to cut
back to allowing fewer lets in a given spec as a compromise. Today my default is to write the entire context of the test inline with no <code class="language-plaintext highlighter-rouge">let</code>s at all.</p>

<p>So a let heavy spec like the following is forced into:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">RSpec</span><span class="p">.</span><span class="nf">describe</span> <span class="no">BlogPost</span> <span class="k">do</span>
  <span class="n">let</span><span class="p">(</span><span class="ss">:author</span><span class="p">)</span> <span class="p">{</span> <span class="no">Author</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">name: </span><span class="s2">"Gunther Hemingway"</span><span class="p">)</span> <span class="p">}</span>
  <span class="n">let</span><span class="p">(</span><span class="ss">:editor</span><span class="p">)</span> <span class="p">{</span> <span class="no">Editor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">name: </span><span class="s2">"Jordon Adams"</span><span class="p">)</span> <span class="p">}</span>
  <span class="n">let</span><span class="p">(</span><span class="ss">:category</span><span class="p">)</span> <span class="p">{</span> <span class="no">Category</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">name: </span><span class="s2">"technology"</span><span class="p">)</span> <span class="p">}</span>
  <span class="n">let</span><span class="p">(</span><span class="ss">:comments</span><span class="p">)</span> <span class="k">do</span>
    <span class="p">[</span>
      <span class="no">Comment</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">author: </span><span class="s2">"hank"</span><span class="p">,</span> <span class="ss">content: </span><span class="s2">"great post!"</span><span class="p">),</span>
      <span class="no">Comment</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">author: </span><span class="s2">"lisa"</span><span class="p">,</span> <span class="ss">content: </span><span class="s2">"very informative."</span><span class="p">),</span>
    <span class="p">]</span>
  <span class="k">end</span>
  <span class="n">let</span><span class="p">(</span><span class="ss">:tags</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="s2">"ruby"</span><span class="p">,</span> <span class="s2">"software development"</span><span class="p">,</span> <span class="s2">"tdd"</span><span class="p">]</span> <span class="p">}</span>
  <span class="n">let</span><span class="p">(</span><span class="ss">:blog_post</span><span class="p">)</span> <span class="k">do</span>
    <span class="no">BlogPost</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span>
      <span class="ss">title: </span><span class="s2">"rspec and let"</span><span class="p">,</span>
      <span class="ss">content: </span><span class="s2">"using let in rspec can help with..."</span><span class="p">,</span>
      <span class="ss">author: </span><span class="n">author</span><span class="p">,</span>
      <span class="ss">editor: </span><span class="n">editor</span><span class="p">,</span>
      <span class="ss">category: </span><span class="n">category</span><span class="p">,</span>
      <span class="ss">comments: </span><span class="n">comments</span><span class="p">,</span>
      <span class="ss">tags: </span><span class="n">tags</span>
    <span class="p">)</span>
  <span class="k">end</span>

  <span class="n">describe</span> <span class="s2">"#publish"</span> <span class="k">do</span>
    <span class="n">it</span> <span class="s2">"notifies the author and editor when published"</span> <span class="k">do</span>
      <span class="n">blog_post</span><span class="p">.</span><span class="nf">publish</span>

      <span class="n">expect</span><span class="p">(</span><span class="n">author</span><span class="p">.</span><span class="nf">notifications</span><span class="p">.</span><span class="nf">last</span><span class="p">).</span><span class="nf">to</span> <span class="n">eq</span><span class="p">(</span><span class="s2">"your post 'rspec and let' has been published."</span><span class="p">)</span>
      <span class="n">expect</span><span class="p">(</span><span class="n">editor</span><span class="p">.</span><span class="nf">notifications</span><span class="p">.</span><span class="nf">last</span><span class="p">).</span><span class="nf">to</span> <span class="n">eq</span><span class="p">(</span><span class="s2">"the post 'rspec and let' you edited has been published."</span><span class="p">)</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>This much more explict style:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">RSpec</span><span class="p">.</span><span class="nf">describe</span> <span class="no">BlogPost</span> <span class="k">do</span>
  <span class="n">describe</span> <span class="s2">"#publish"</span> <span class="k">do</span>
    <span class="n">it</span> <span class="s2">"notifies the author and editor when published"</span> <span class="k">do</span>
      <span class="n">blog_post</span> <span class="o">=</span> <span class="no">BlogPost</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span>
        <span class="ss">title: </span><span class="s2">"rspec and let"</span><span class="p">,</span>
        <span class="ss">content: </span><span class="s2">"using let in rspec can help with..."</span><span class="p">,</span>
        <span class="ss">author: </span><span class="no">Author</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">name: </span><span class="s2">"Gunther Hemingway"</span><span class="p">)</span>
        <span class="ss">editor: </span><span class="no">Editor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">name: </span><span class="s2">"Jordon Adams"</span><span class="p">)</span>
        <span class="ss">category: </span><span class="n">category</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">name: </span><span class="s2">"technology"</span><span class="p">),</span>
        <span class="ss">comments: </span><span class="p">[</span>
          <span class="n">comment</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">author: </span><span class="s2">"leslie"</span><span class="p">,</span> <span class="ss">content: </span><span class="s2">"great post!"</span><span class="p">),</span>
          <span class="n">comment</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">author: </span><span class="s2">"bob"</span><span class="p">,</span> <span class="ss">content: </span><span class="s2">"very informative."</span><span class="p">)</span>
        <span class="p">],</span>
        <span class="ss">tags: </span><span class="p">[</span><span class="s2">"ruby"</span><span class="p">,</span> <span class="s2">"software development"</span><span class="p">,</span> <span class="s2">"tdd"</span><span class="p">]</span>
      <span class="p">)</span>

      <span class="n">blog_post</span><span class="p">.</span><span class="nf">publish</span>

      <span class="n">expect</span><span class="p">(</span><span class="n">blog_post</span><span class="p">.</span><span class="nf">author</span><span class="p">.</span><span class="nf">notifications</span><span class="p">.</span><span class="nf">last</span><span class="p">).</span><span class="nf">to</span> <span class="n">eq</span><span class="p">(</span><span class="s2">"your post 'rspec and let' has been published."</span><span class="p">)</span>
      <span class="n">expect</span><span class="p">(</span><span class="n">blog_post</span><span class="p">.</span><span class="nf">editor</span><span class="p">.</span><span class="nf">notifications</span><span class="p">.</span><span class="nf">last</span><span class="p">).</span><span class="nf">to</span> <span class="n">eq</span><span class="p">(</span><span class="s2">"the post 'rspec and let' you edited has been published."</span><span class="p">)</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Inline default leads to several happy impacts:</p>

<ul>
  <li>If you ever need to move this spec, copy it as a starting point, etc, it’s all intact as a single unit</li>
  <li>Sure you’ll probably duplicate some of this for a second spec, but deep in a spec file you’ll never need to scroll around to see what’s going on</li>
  <li>If your setup code looks like many lines of boilerplate perhaps your class has way to many dependencies and needs reactoring</li>
</ul>

<p>So if you haven’t tried this recently I’d invite you to do an experiment for a week and write zero <code class="language-plaintext highlighter-rouge">let</code>s.</p>]]></content><author><name>Ed Gibbs</name></author><category term="ruby" /><category term="software development" /><category term="test driven development" /><summary type="html"><![CDATA[let has a long history in RSpec having been introduced with a commit in 2009 and rolled out as part of RSpec 2. I adopted it early on as the aesthetics appealed to me with let variables being defined first in little blocks with symbols. One of our engineers wrote a macro in vim to quickly hoist instance variables in older style RSpec tests to let declarations. It became the default style for everyone in RSpec with only a bit of controversy around let! which could be easy to miss in tests. I knew about the lazy initialization, but it was the aesthetics I prized.]]></summary></entry><entry><title type="html">Interview Tip: Checkout Online Code Environments before the Interview</title><link href="https://edgibbs.com/2024/01/10/checkout-online-coding-environments-before-the-interview/" rel="alternate" type="text/html" title="Interview Tip: Checkout Online Code Environments before the Interview" /><published>2024-01-10T00:00:00+00:00</published><updated>2024-01-10T00:00:00+00:00</updated><id>https://edgibbs.com/2024/01/10/checkout-online-coding-environments-before-interview</id><content type="html" xml:base="https://edgibbs.com/2024/01/10/checkout-online-coding-environments-before-the-interview/"><![CDATA[<p>Live coding is a stressful experience. One of the simplest ways to reduce stress around solving a
unknown problem in less than an hour is to setup your environment before the interview. My anecdotal experience is that
so few developers do this in practice. As an interviewer its a good sign when you check the coding environment
before and see the candidate has already setup the environment and got a test up and running.</p>

<p>It’s a signal to the interviewer of several things in the interview:</p>

<ul>
  <li>You are naturally prepared</li>
  <li>You are able to take full advantage of any tools/libraries provided</li>
  <li>You are pretty motivated to work for this organization</li>
</ul>

<p>Using <a href="https://coderpad.io">CoderPad</a> as an example:</p>

<ul>
  <li>You can login ahead of time into the pad setup for your interview or at least login to CoderPad’s site and try out a sandbox.</li>
  <li>Select a few of the coding environments you are most comfortable with. Unless you are forced into a specific language always choose your day-to-day language.</li>
  <li>See what libraries you have access to like RSpec, ActiveSupport in Ruby for example.</li>
  <li>Look at the settings for including important things like vim/emac support, Intellisense, etc.</li>
  <li>Get a test running in the environment, so you can TDD right away using your favorite testing framework or at least an available one.</li>
  <li>Test drive a simple problem in the space like FizzBuzz just to get a feel for the environment and how it works.</li>
  <li>If this is the actual coding environment for the interview leave your code in there for the interviewer to discover.</li>
</ul>

<p>I know I see this level of preperation maybe 5-10% of the time, so it’s an easy way to start off strong.</p>]]></content><author><name>Ed Gibbs</name></author><category term="management" /><category term="software development" /><summary type="html"><![CDATA[Live coding is a stressful experience. One of the simplest ways to reduce stress around solving a unknown problem in less than an hour is to setup your environment before the interview. My anecdotal experience is that so few developers do this in practice. As an interviewer its a good sign when you check the coding environment before and see the candidate has already setup the environment and got a test up and running.]]></summary></entry><entry><title type="html">Quick Inline Vim Keymap Shortcut</title><link href="https://edgibbs.com/2022/08/01/quick-inline-vim-keymap-shortcut/" rel="alternate" type="text/html" title="Quick Inline Vim Keymap Shortcut" /><published>2022-08-01T00:00:00+00:00</published><updated>2022-08-01T00:00:00+00:00</updated><id>https://edgibbs.com/2022/08/01/quick-inline-vim-keymap-shortcut</id><content type="html" xml:base="https://edgibbs.com/2022/08/01/quick-inline-vim-keymap-shortcut/"><![CDATA[<p>I often forget the exact syntax for writing a quick shortcut in in vim/neovim. After hunting for several minutes
this morning I made a decision to memorialize the approach. Usually it’s for a simple command like running tests in
an Elixir mix console:</p>

<figure class="highlight"><pre><code class="language-vim" data-lang="vim"><span class="p">:</span>nnoremap <span class="p">,</span><span class="k">e</span> <span class="p">:!</span>mix test<span class="p">&lt;</span>CR<span class="p">&gt;</span></code></pre></figure>

<p>So the first <code class="language-plaintext highlighter-rouge">n</code> means it applies just to normal mode. The <code class="language-plaintext highlighter-rouge">noremap</code> means it won’t follow any other mapping so it’s
non-recursive. The <code class="language-plaintext highlighter-rouge">,e</code> is the what the shortcut is mapped to. And finally the <code class="language-plaintext highlighter-rouge">:!mix test&lt;CR&gt;</code> puts the mix command
into the terminal and hits a carriage return to execute the command.</p>]]></content><author><name>Ed Gibbs</name></author><category term="software development" /><category term="vim" /><summary type="html"><![CDATA[I often forget the exact syntax for writing a quick shortcut in in vim/neovim. After hunting for several minutes this morning I made a decision to memorialize the approach. Usually it’s for a simple command like running tests in an Elixir mix console:]]></summary></entry><entry><title type="html">Aggregate Failures</title><link href="https://edgibbs.com/2022/04/17/aggregate-failures/" rel="alternate" type="text/html" title="Aggregate Failures" /><published>2022-04-17T00:00:00+00:00</published><updated>2022-04-17T00:00:00+00:00</updated><id>https://edgibbs.com/2022/04/17/aggregate-failures</id><content type="html" xml:base="https://edgibbs.com/2022/04/17/aggregate-failures/"><![CDATA[<p>After working on several large rails codebases in the last 10 years I’ve seen a familiar pattern.
Many tests in Rails projects are integration tests because they rely on actual database objects existing.
One assertion per test is great rule when you don’t have tens of thousands of specs running. <code class="language-plaintext highlighter-rouge">:aggregate-failures</code>
allows you to have multiple assertions while still reporting on each failure clearly.</p>

<p>As a bonus it is honored by <code class="language-plaintext highlighter-rouge">Rubocop RSpec RSpec/MultipleExpectations</code>. Not sure why this isn’t
documented better with Rubocop RSpec. Here is the code within the <code class="language-plaintext highlighter-rouge">MultipleExpectations</code> class that
enforces the one assert per spec rule:</p>

<p><a href="https://github.com/rubocop/rubocop-rspec/blob/master/lib/rubocop/cop/rspec/multiple_expectations.rb">MultipleExpectations</a></p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">on_block</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
  <span class="k">return</span> <span class="k">unless</span> <span class="n">example?</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>

  <span class="k">return</span> <span class="k">if</span> <span class="n">example_with_aggregate_failures?</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>

  <span class="n">expectations_count</span> <span class="o">=</span> <span class="n">to_enum</span><span class="p">(</span><span class="ss">:find_expectation</span><span class="p">,</span> <span class="n">node</span><span class="p">).</span><span class="nf">count</span>

  <span class="k">return</span> <span class="k">if</span> <span class="n">expectations_count</span> <span class="o">&lt;=</span> <span class="n">max_expectations</span>

  <span class="nb">self</span><span class="p">.</span><span class="nf">max</span> <span class="o">=</span> <span class="n">expectations_count</span>

  <span class="n">flag_example</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="ss">expectation_count: </span><span class="n">expectations_count</span><span class="p">)</span>
<span class="k">end</span></code></pre></figure>

<p>And you don’t need to feel guilty about adding aggregate failures:</p>

<ul>
  <li>It speeds up test runs because it doesn’t do multiple setups</li>
  <li>By default anything that uses ActiveRecord is not a true unit test</li>
  <li>You still get all the errors if multiple lines fail</li>
  <li>Speed of test run on any significant Rails project should almost always win</li>
</ul>]]></content><author><name>Ed Gibbs</name></author><category term="software development" /><category term="test driven development" /><category term="ruby" /><category term="rspec" /><summary type="html"><![CDATA[After working on several large rails codebases in the last 10 years I’ve seen a familiar pattern. Many tests in Rails projects are integration tests because they rely on actual database objects existing. One assertion per test is great rule when you don’t have tens of thousands of specs running. :aggregate-failures allows you to have multiple assertions while still reporting on each failure clearly.]]></summary></entry><entry><title type="html">RSpec Instance Double With Class Names</title><link href="https://edgibbs.com/2020/07/11/rspec-instance-double-with-class-names/" rel="alternate" type="text/html" title="RSpec Instance Double With Class Names" /><published>2020-09-13T00:00:00+00:00</published><updated>2020-09-13T00:00:00+00:00</updated><id>https://edgibbs.com/2020/07/11/rspec-instance-double-with-constants</id><content type="html" xml:base="https://edgibbs.com/2020/07/11/rspec-instance-double-with-class-names/"><![CDATA[<p>After many years working with RSpec I discovered a nice little feature and a small gotcha with instance doubles.
I’ve used <code class="language-plaintext highlighter-rouge">instance_double</code> since before it was ported from <a href="https://github.com/xaviershay/rspec-fire">rspec-fire</a>.</p>

<p>My practice and all the current Relish RSpec examples of <code class="language-plaintext highlighter-rouge">instance_double</code> use the following format:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">let</span><span class="p">(</span><span class="ss">:public_policy</span><span class="p">)</span> <span class="p">{</span> <span class="n">instance_double</span><span class="p">(</span><span class="s1">'Users::PublicPolicy'</span><span class="p">)</span> <span class="p">}</span></code></pre></figure>

<p>It turns out the actual <code class="language-plaintext highlighter-rouge">instance_double()</code> method takes a string representing the class or just the class constant:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">instance_double</span><span class="p">(</span><span class="n">doubled_class</span><span class="p">)</span></code></pre></figure>

<p>And the important part here is the parameter:</p>

<p><code class="language-plaintext highlighter-rouge">doubled_class(String, Class)</code></p>

<p>No String is required here and class constants are auto-verifying. According to a long discussion
on <a href="https://github.com/rspec/rspec-mocks/issues/842">rspec-mocks</a> this behavior exists to avoid some
auto-loading of classes that aren’t needed so that tests can be a bit faster in some cases. For me this breaks
the expectation that I the mock is actually verifying that the class and methods actually exist. If I
wanted just a pure mock I could just use <code class="language-plaintext highlighter-rouge">double</code>.  And for Rails projects that make up a lot of the day to day
paid developer work everything auto-loads anyway. Using class constants is just simpler. If you’re on a legacy
project you can probably just add the config to verify the strings ahead of time anyway with the following:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">config</span><span class="p">.</span><span class="nf">mock_with</span> <span class="ss">:rspec</span> <span class="k">do</span> <span class="o">|</span><span class="n">mocks</span><span class="o">|</span>
  <span class="n">mocks</span><span class="p">.</span><span class="nf">verify_doubled_constant_names</span> <span class="o">=</span> <span class="kp">true</span>
<span class="k">end</span></code></pre></figure>

<p>This example code shows what happens when you make a typo in the string constant name and you don’t have the config to verify set:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
</pre></td><td class="code"><pre><span class="nb">require</span> <span class="s1">'spec_helper'</span>
<span class="nb">require_relative</span> <span class="s1">'../../lib/users/policy_enforcer'</span>
<span class="nb">require_relative</span> <span class="s1">'../../lib/users/public_policy'</span>

<span class="no">RSpec</span><span class="p">.</span><span class="nf">describe</span> <span class="no">Users</span><span class="o">::</span><span class="no">PolicyEnforcer</span> <span class="k">do</span>
  <span class="n">describe</span> <span class="s1">'#allowed?'</span> <span class="k">do</span>
    <span class="n">let</span><span class="p">(</span><span class="ss">:policy_enforcer</span><span class="p">)</span> <span class="p">{</span> <span class="no">Users</span><span class="o">::</span><span class="no">PolicyEnforcer</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">public_policy</span><span class="p">)</span> <span class="p">}</span>

    <span class="n">context</span> <span class="s1">'with correct string instance_double class constant'</span> <span class="k">do</span>
      <span class="n">let</span><span class="p">(</span><span class="ss">:public_policy</span><span class="p">)</span> <span class="p">{</span> <span class="n">instance_double</span><span class="p">(</span><span class="s1">'Users::PublicPolicy'</span><span class="p">)</span> <span class="p">}</span>

      <span class="n">before</span> <span class="k">do</span>
        <span class="n">allow</span><span class="p">(</span><span class="n">public_policy</span><span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:allowed?</span><span class="p">)</span>
      <span class="k">end</span>

      <span class="n">it</span> <span class="s1">'returns true'</span> <span class="k">do</span>
        <span class="n">policy_enforcer</span><span class="p">.</span><span class="nf">allowed?</span>
        <span class="n">expect</span><span class="p">(</span><span class="n">public_policy</span><span class="p">).</span><span class="nf">to</span> <span class="n">have_received</span><span class="p">(</span><span class="ss">:allowed?</span><span class="p">)</span>
      <span class="k">end</span>
    <span class="k">end</span>

    <span class="n">context</span> <span class="s1">'with typo string instance_double class constant'</span> <span class="k">do</span>
      <span class="n">let</span><span class="p">(</span><span class="ss">:public_policy</span><span class="p">)</span> <span class="p">{</span> <span class="n">instance_double</span><span class="p">(</span><span class="s1">'Use::PublicPolicy'</span><span class="p">)</span> <span class="p">}</span>

      <span class="n">before</span> <span class="k">do</span>
        <span class="n">allow</span><span class="p">(</span><span class="n">public_policy</span><span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:allowed?</span><span class="p">)</span>
      <span class="k">end</span>

      <span class="n">it</span> <span class="s1">'lies and returns true'</span> <span class="k">do</span>
        <span class="n">policy_enforcer</span><span class="p">.</span><span class="nf">allowed?</span>
        <span class="n">expect</span><span class="p">(</span><span class="n">public_policy</span><span class="p">).</span><span class="nf">to</span> <span class="n">have_received</span><span class="p">(</span><span class="ss">:allowed?</span><span class="p">)</span>
      <span class="k">end</span>
    <span class="k">end</span>

    <span class="n">context</span> <span class="s1">'with a proper class constant instance_double'</span> <span class="k">do</span>
      <span class="n">let</span><span class="p">(</span><span class="ss">:public_policy</span><span class="p">)</span> <span class="p">{</span> <span class="n">instance_double</span><span class="p">(</span><span class="no">Users</span><span class="o">::</span><span class="no">PublicPolicy</span><span class="p">)</span> <span class="p">}</span>

      <span class="n">before</span> <span class="k">do</span>
        <span class="n">allow</span><span class="p">(</span><span class="n">public_policy</span><span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:allowed?</span><span class="p">)</span>
      <span class="k">end</span>

      <span class="n">it</span> <span class="s1">'returns true'</span> <span class="k">do</span>
        <span class="n">policy_enforcer</span><span class="p">.</span><span class="nf">allowed?</span>
        <span class="n">expect</span><span class="p">(</span><span class="n">public_policy</span><span class="p">).</span><span class="nf">to</span> <span class="n">have_received</span><span class="p">(</span><span class="ss">:allowed?</span><span class="p">)</span>
      <span class="k">end</span>
    <span class="k">end</span>

    <span class="n">context</span> <span class="s1">'with an typoed class constant instance_double'</span> <span class="k">do</span>
      <span class="n">let</span><span class="p">(</span><span class="ss">:public_policy</span><span class="p">)</span> <span class="p">{</span> <span class="n">instance_double</span><span class="p">(</span><span class="no">User</span><span class="ss">:PublicPolicy</span><span class="p">)</span> <span class="p">}</span>

      <span class="n">before</span> <span class="k">do</span>
        <span class="n">allow</span><span class="p">(</span><span class="n">public_policy</span><span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:allowed?</span><span class="p">)</span>
      <span class="k">end</span>

      <span class="n">it</span> <span class="s1">'fails because the constant is not defined'</span> <span class="k">do</span>
        <span class="n">policy_enforcer</span><span class="p">.</span><span class="nf">allowed?</span>
        <span class="n">expect</span><span class="p">(</span><span class="n">public_policy</span><span class="p">).</span><span class="nf">to</span> <span class="n">have_received</span><span class="p">(</span><span class="ss">:allowed?</span><span class="p">)</span>
      <span class="k">end</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></figure>

<p>The result is the spec <code class="language-plaintext highlighter-rouge">with typo string instance double class constant</code> on line 22 lies to you.  It behaves like a plain old double and allows you to accept methods on classes that don’t exist.</p>

<figure class="highlight"><pre><code class="language-shell" data-lang="shell">Users::PolicyEnforcer
  <span class="c">#allowed?</span>
    with correct string instance_double class constant
      returns <span class="nb">true
    </span>with typo string instance_double class constant
      lies and returns <span class="nb">true
    </span>with a proper class constant instance_double
      returns <span class="nb">true
    </span>with an typoed class constant instance_double
      fails because the constant is not defined <span class="o">(</span>FAILED - 1<span class="o">)</span>

Failures:

  1<span class="o">)</span> Users::PolicyEnforcer#allowed? with an typoed class constant instance_double fails because the constant isn not defined
     Failure/Error: <span class="nb">let</span><span class="o">(</span>:public_policy<span class="o">)</span> <span class="o">{</span> instance_double<span class="o">(</span>User:PublicPolicy<span class="o">)</span> <span class="o">}</span>

     NameError:
       uninitialized constant PublicPolicy
     <span class="c"># ./spec/users/policy_enforcer_spec.rb:49:in `block (4 levels) in &lt;top (required)&gt;'</span>
     <span class="c"># ./spec/users/policy_enforcer_spec.rb:52:in `block (4 levels) in &lt;top (required)&gt;'</span>

Finished <span class="k">in </span>0.0175 seconds <span class="o">(</span>files took 0.45833 seconds to load<span class="o">)</span>
4 examples, 1 failure

Failed examples:

rspec ./spec/users/policy_enforcer_spec.rb:55 <span class="c"># Users::PolicyEnforcer#allowed? with an typoed class constant instance_double fails because the constant isn not</span>
 defined</code></pre></figure>]]></content><author><name>Ed Gibbs</name></author><category term="software development" /><category term="ruby" /><category term="test driven development" /><summary type="html"><![CDATA[After many years working with RSpec I discovered a nice little feature and a small gotcha with instance doubles. I’ve used instance_double since before it was ported from rspec-fire.]]></summary></entry><entry><title type="html">More Testable Rake Tasks</title><link href="https://edgibbs.com/2020/02/9/more-testable-rake-tasks/" rel="alternate" type="text/html" title="More Testable Rake Tasks" /><published>2020-02-09T00:00:00+00:00</published><updated>2020-02-09T00:00:00+00:00</updated><id>https://edgibbs.com/2020/02/9/more-testable-rake-tasks</id><content type="html" xml:base="https://edgibbs.com/2020/02/9/more-testable-rake-tasks/"><![CDATA[<p>A few months ago I had a brief pairing session where I attempted to help another
developer with getting some working tests around a rake task they had created.
They were having issues testing within rake and executing tasks which is a
common issue in rake testing.  My suggesion was to build the entire logic of the
task in a PORO to avoid the pain of testing rake plumbing.</p>

<p>The approach takes the following steps:</p>

<ul>
  <li>Create a spec file to test the new class</li>
  <li>Create a class that handles doing the thing</li>
  <li>Create a spec file for the rake task</li>
  <li>Add the rake task and defer everything to the new class</li>
</ul>

<p>For this example say you have some rake task that should just return the current
versions of ruby and bundler locally.  Not super useful, but it will involve executing
some local commands.  We want to be able to run:</p>

<figure class="highlight"><pre><code class="language-console" data-lang="console"><span class="go">rake display_versions</span></code></pre></figure>

<p>And have it dump out:</p>

<figure class="highlight"><pre><code class="language-console" data-lang="console"><span class="go">Gathering versions
Ruby VERSION: ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin19]
Bundler VERSION: Bundler version 2.1.4</span></code></pre></figure>

<p>Instead of diving in and just doing all the logic in rake and having to figure out
how to test it in that context, we start with the class that we want to build the
results, say <code class="language-plaintext highlighter-rouge">VersionDisplayer</code>, and we start with the spec:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="code"><pre><span class="nb">require_relative</span> <span class="s1">'version_displayer'</span>

<span class="n">describe</span> <span class="no">VersionDisplayer</span> <span class="k">do</span>
  <span class="n">describe</span> <span class="s1">'#display'</span> <span class="k">do</span>
    <span class="n">let</span><span class="p">(</span><span class="ss">:version_displayer</span><span class="p">)</span> <span class="p">{</span> <span class="no">VersionDisplayer</span><span class="p">.</span><span class="nf">new</span> <span class="p">}</span>
    <span class="n">let</span><span class="p">(</span><span class="ss">:expected_output</span><span class="p">)</span> <span class="k">do</span>
      <span class="o">&lt;&lt;~</span><span class="no">OUTPUT</span><span class="sh">
        Gathering versions
        Ruby VERSION: ruby 2.7.0
        Bundler VERSION: bundler 2.0
</span><span class="no">      OUTPUT</span>
    <span class="k">end</span>

    <span class="n">before</span> <span class="k">do</span>
      <span class="n">allow</span><span class="p">(</span><span class="no">Open3</span><span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:capture2</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">with</span><span class="p">(</span><span class="s1">'ruby --version'</span><span class="p">).</span><span class="nf">and_return</span><span class="p">([</span><span class="s1">'ruby 2.7.0'</span><span class="p">,</span> <span class="kp">nil</span><span class="p">])</span>
      <span class="n">allow</span><span class="p">(</span><span class="no">Open3</span><span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:capture2</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">with</span><span class="p">(</span><span class="s1">'bundler --version'</span><span class="p">).</span><span class="nf">and_return</span><span class="p">([</span><span class="s1">'bundler 2.0'</span><span class="p">,</span> <span class="kp">nil</span><span class="p">])</span>
    <span class="k">end</span>

    <span class="n">it</span> <span class="s1">'returns the current bundler and ruby version'</span> <span class="k">do</span>
      <span class="n">expect</span> <span class="p">{</span> <span class="n">version_displayer</span><span class="p">.</span><span class="nf">display</span> <span class="p">}.</span><span class="nf">to</span> <span class="n">output</span><span class="p">(</span><span class="n">expected_output</span><span class="p">).</span><span class="nf">to_stdout</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></figure>

<p>This leads us to the VersionDisplayer class that satisfies the spec:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre><span class="nb">require</span> <span class="s1">'open3'</span>

<span class="k">class</span> <span class="nc">VersionDisplayer</span>
  <span class="k">def</span> <span class="nf">display</span>
    <span class="nb">puts</span> <span class="s2">"Gathering versions"</span>
    <span class="n">ruby_version</span><span class="p">,</span> <span class="n">_status</span> <span class="o">=</span> <span class="no">Open3</span><span class="p">.</span><span class="nf">capture2</span><span class="p">(</span><span class="s1">'ruby --version'</span><span class="p">)</span>
    <span class="n">bundler_version</span><span class="p">,</span> <span class="n">_status</span> <span class="o">=</span> <span class="no">Open3</span><span class="p">.</span><span class="nf">capture2</span><span class="p">(</span><span class="s1">'bundler --version'</span><span class="p">)</span>
    <span class="nb">puts</span> <span class="s2">"Ruby VERSION: </span><span class="si">#{</span><span class="n">ruby_version</span><span class="si">}</span><span class="s2">"</span>
    <span class="nb">puts</span> <span class="s2">"Bundler VERSION: </span><span class="si">#{</span><span class="n">bundler_version</span><span class="si">}</span><span class="s2">"</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></figure>

<p>Now we can write a simple rake integration spec:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="code"><pre><span class="nb">require</span> <span class="s1">'rake'</span>

<span class="n">describe</span> <span class="s1">':display_versions'</span> <span class="k">do</span>
  <span class="n">let</span><span class="p">(</span><span class="ss">:version_displayer</span><span class="p">)</span> <span class="p">{</span> <span class="n">instance_double</span><span class="p">(</span><span class="s1">'VersionDisplayer'</span><span class="p">)</span> <span class="p">}</span>

  <span class="n">before</span> <span class="k">do</span>
    <span class="nb">load</span> <span class="no">File</span><span class="p">.</span><span class="nf">expand_path</span><span class="p">(</span><span class="s1">'Rakefile'</span><span class="p">)</span>
    <span class="n">allow</span><span class="p">(</span><span class="no">VersionDisplayer</span><span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:new</span><span class="p">).</span><span class="nf">and_return</span><span class="p">(</span><span class="n">version_displayer</span><span class="p">)</span>
    <span class="n">allow</span><span class="p">(</span><span class="n">version_displayer</span><span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:display</span><span class="p">).</span><span class="nf">with</span><span class="p">(</span><span class="n">no_args</span><span class="p">)</span>
  <span class="k">end</span>

  <span class="n">it</span> <span class="s1">'uses version displayer to output the version information'</span> <span class="k">do</span> 
    <span class="no">Rake</span><span class="o">::</span><span class="no">Task</span><span class="p">[</span><span class="s1">'display_versions'</span><span class="p">].</span><span class="nf">invoke</span>
    <span class="n">expect</span><span class="p">(</span><span class="n">version_displayer</span><span class="p">).</span><span class="nf">to</span> <span class="n">have_received</span><span class="p">(</span><span class="ss">:display</span><span class="p">).</span><span class="nf">with</span><span class="p">(</span><span class="n">no_args</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></figure>

<p>And finally we a simple rake task that delegates all everything:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="code"><pre><span class="nb">require_relative</span> <span class="s1">'version_displayer'</span>

<span class="n">desc</span> <span class="s1">'Displays versions of bundler and ruby'</span>
<span class="n">task</span> <span class="ss">:display_versions</span> <span class="k">do</span>
  <span class="no">VersionDisplayer</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">display</span>
<span class="k">end</span>
</pre></td></tr></tbody></table></code></pre></figure>

<p>I much prefer this to embedding the logic in the rake task and writing
complex tests around the rake context.</p>]]></content><author><name>Ed Gibbs</name></author><category term="software development" /><category term="ruby" /><category term="test driven development" /><summary type="html"><![CDATA[A few months ago I had a brief pairing session where I attempted to help another developer with getting some working tests around a rake task they had created. They were having issues testing within rake and executing tasks which is a common issue in rake testing. My suggesion was to build the entire logic of the task in a PORO to avoid the pain of testing rake plumbing.]]></summary></entry><entry><title type="html">Configuring Jenkins Properties As Code</title><link href="https://edgibbs.com/2019/07/14/configuring-jenkins-properties/" rel="alternate" type="text/html" title="Configuring Jenkins Properties As Code" /><published>2019-07-14T00:00:00+00:00</published><updated>2019-07-14T00:00:00+00:00</updated><id>https://edgibbs.com/2019/07/14/configuring-jenkins-properties</id><content type="html" xml:base="https://edgibbs.com/2019/07/14/configuring-jenkins-properties/"><![CDATA[<p>Jenkins appears to be the single most popular CI/CD tool despite its age and corresponding legacy tradeoffs.
When I landed on the State of <a href="https://cwds.ca.gov">California’s Child Welfare project</a> Jenkins was already the default option.
I brushed up on the new features since I had largely missed out on the new pipeline features with an actual
code as configuration option that was added to Jenkins around 2016.</p>

<p>We moved to the state’s infrastructure and Jenkins server by making heavy use of Jenkinsfiles and a few triggering
plugins like <a href="https://wiki.jenkins.io/display/JENKINS/GitHub+pull+request+builder+plugin">Github Pull Request Builder</a>
and the <a href="https://wiki.jenkins.io/display/JENKINS/Generic+Webhook+Trigger+Plugin">Generic Webhook Trigger</a>.  Later in the project, I volunteered to lead the
pipeline team to ‘Automate All the Things’. Eventually, we experimented with writing Jenkins Shared Libraries which is a
somewhat clunky way to share code between Jenkinsfiles without breaking down and writing whole Jenkins plugins.
After some early successes, we eventually moved to write a significant library of shared steps which were then used
on dozens of the organization’s projects.</p>

<p>After a time it occurred to me that we could embed many of the settings in the projects that were a pain to set up in the GUI from
within a shared library custom step.  One of the most elaborate plugins to configure was Github PullRequestBuilder, but we were
eventually able to capture all of its settings in a fairly simple step.</p>

<figure class="highlight"><pre><code class="language-groovy" data-lang="groovy"><span class="n">node</span><span class="o">(</span><span class="s1">'buildNode'</span><span class="o">)</span> <span class="o">{</span>
  <span class="n">triggerProperties</span> <span class="o">=</span> <span class="n">githubPullRequestBuilderTriggerProperties</span><span class="o">()</span>
  <span class="n">properties</span><span class="o">([</span>
    <span class="n">pipelineTriggers</span><span class="o">([</span><span class="n">triggerProperties</span><span class="o">])</span>
  <span class="o">])</span>
  <span class="o">...</span>
<span class="o">}</span></code></pre></figure>

<p>Under the covers it sets up an Frankenstien sort of object:</p>

<figure class="highlight"><pre><code class="language-groovy" data-lang="groovy"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
</pre></td><td class="code"><pre><span class="o">[</span><span class="n">$class</span><span class="o">:</span> <span class="s1">'org.jenkinsci.plugins.ghprb.GhprbTrigger'</span><span class="o">,</span>
  <span class="nl">spec:</span> <span class="s1">'H/5 * * * *'</span><span class="o">,</span>
  <span class="nl">configVersion:</span> <span class="mi">3</span><span class="o">,</span>
  <span class="nl">allowMembersOfWhitelistedOrgsAsAdmin:</span> <span class="kc">true</span><span class="o">,</span>
  <span class="nl">orgslist:</span> <span class="s1">'ca-cwds'</span><span class="o">,</span>
  <span class="nl">cron:</span> <span class="s1">'H/5 * * * *'</span><span class="o">,</span>
  <span class="nl">onlyTriggerPhrase:</span> <span class="kc">false</span><span class="o">,</span>
  <span class="nl">useGitHubHooks:</span> <span class="kc">true</span><span class="o">,</span>
  <span class="nl">permitAll:</span> <span class="kc">false</span><span class="o">,</span>
  <span class="nl">autoCloseFailedPullRequests:</span> <span class="kc">false</span><span class="o">,</span>
  <span class="nl">displayBuildErrorsOnDownstreamBuilds:</span> <span class="kc">false</span><span class="o">,</span>
  <span class="nl">triggerPhrase:</span> <span class="s1">'retest this please'</span><span class="o">,</span>
  <span class="nl">skipBuildPhrase:</span> <span class="s1">'.*\\[skip\\W+ci\\].*'</span><span class="o">,</span>
  <span class="nl">extensions:</span> <span class="o">[</span>
                <span class="o">[</span>
                    <span class="n">$class</span><span class="o">:</span> <span class="s1">'org.jenkinsci.plugins.ghprb.extensions.build.GhprbCancelBuildsOnUpdate'</span><span class="o">,</span>
                    <span class="nl">overrideGlobal:</span> <span class="kc">false</span>
                <span class="o">],</span>
                <span class="o">[</span>
                    <span class="n">$class</span><span class="o">:</span> <span class="s1">'org.jenkinsci.plugins.ghprb.extensions.status.GhprbSimpleStatus'</span><span class="o">,</span>
                    <span class="nl">commitStatusContext:</span> <span class="s1">'Pull Request Testing'</span><span class="o">,</span>
                    <span class="nl">statusUrl:</span> <span class="s1">'https://jenkins.example.com'</span><span class="o">,</span>
                    <span class="nl">addTestResults:</span> <span class="kc">false</span><span class="o">,</span>
                    <span class="nl">completedStatus:</span> <span class="o">[</span>
                      <span class="o">[</span>
                        <span class="n">$class</span><span class="o">:</span> <span class="s1">'org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage'</span><span class="o">,</span>
                        <span class="nl">message:</span> <span class="s1">'Success'</span><span class="o">,</span>
                        <span class="nl">result:</span> <span class="s1">'SUCCESS'</span>
                      <span class="o">],</span>
                      <span class="o">[</span>
                        <span class="n">$class</span><span class="o">:</span> <span class="s1">'org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage'</span><span class="o">,</span>
                        <span class="nl">message:</span> <span class="s1">'Build Failed'</span><span class="o">,</span>
                        <span class="nl">result:</span> <span class="s1">'FAILURE'</span>
                      <span class="o">],</span>
                      <span class="o">[</span>
                        <span class="n">$class</span><span class="o">:</span> <span class="s1">'org.jenkinsci.plugins.ghprb.extensions.comments.GhprbBuildResultMessage'</span><span class="o">,</span>
                        <span class="nl">message:</span> <span class="s1">'Build Error'</span><span class="o">,</span>
                        <span class="nl">result:</span> <span class="s1">'ERROR'</span>
                      <span class="o">]</span>
                    <span class="o">]</span>
                  <span class="o">]</span>
              <span class="o">]</span>
    <span class="o">]</span>
</pre></td></tr></tbody></table></code></pre></figure>

<p>This saved significant time for any team trying to set up their first pull-request based build in their Jenkinsfile, as
they no longer had to figure out all of the boxes to check and text fields to fill out.  So if you’re just getting started
trying to reuse code among Jenkinfiles don’t forget the option of embedding complex config as well.</p>

<p>Notes:</p>

<p>We’ve pulled in three things now Jenkins Github plugin, GHPRB, Generic Webhook Trigger.
Had to deal with them as steps.
Eventual goal is to move all config out of Jenkins into code.
Unfortunate bootstrap issue especially with triggers, or a first time project.
Jenkins X is supposed to provide some of this functionality.</p>]]></content><author><name>Ed Gibbs</name></author><category term="software development" /><category term="automated builds" /><summary type="html"><![CDATA[Jenkins appears to be the single most popular CI/CD tool despite its age and corresponding legacy tradeoffs. When I landed on the State of California’s Child Welfare project Jenkins was already the default option. I brushed up on the new features since I had largely missed out on the new pipeline features with an actual code as configuration option that was added to Jenkins around 2016.]]></summary></entry><entry><title type="html">Evaluating Concourse CI</title><link href="https://edgibbs.com/2019/01/13/concourse-ci-eval/" rel="alternate" type="text/html" title="Evaluating Concourse CI" /><published>2019-01-13T00:00:00+00:00</published><updated>2019-01-13T00:00:00+00:00</updated><id>https://edgibbs.com/2019/01/13/concourse-ci-eval</id><content type="html" xml:base="https://edgibbs.com/2019/01/13/concourse-ci-eval/"><![CDATA[<p>Over the holidays I had a chance to do a review of the CI options out there. I’m more than happy with something like Travis, and
I’ve often said Jenkins is the Wordpress of CI Servers even though I’ve used it now for the bulk of my career.  Currently, I’m working
on building out a full production pipeline for the State of California where we are attempting to be transparent and use AGPL 3.0 for all of
our code.  That pretty much eliminated Travis CI, Codeship, and Circle CI.  I realize they’re free for open source projects in general, but
suffice it to say that getting a SASS solution, even a free one approved with some level of access to our Github organization is a tall order
with the existing policies in place.  So self-hosted open source was going to be our options.</p>

<p>So one of our options was <a href="https://concourse-ci.org">Concourse CI</a>, so I sat down with several hours to dive in and take a good look at it.</p>

<p>There is a lengthy <a href="https://concoursetutorial.com">tutorial</a> put out by some developers from <a href="https://starkandwayne.com">Stark and Wayne</a>. The
tutorial gives you a good sense of how it would be to use Concourse CI. I did find a few stumbling blocks running through it:</p>

<h3 id="fly-install">Fly Install</h3>
<p><a href="https://concoursetutorial.com">Introduction</a></p>

<p>There isn’t a convenient brew install, so I had to go looking for this command to install instead. (You can download from the initial docker container,
but it downloaded a strange fly.dms file for me, and I found it easier to download and install directly.)</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-Lo</span> fly https://github.com/concourse/concourse/releases/download/v4.2.2/fly_darwin_amd64 <span class="o">&amp;&amp;</span> <span class="nb">chmod</span> +x fly <span class="o">&amp;&amp;</span> <span class="nb">mv </span>fly /usr/local/bin/
</code></pre></div></div>
<h3 id="private-keys">Private Keys</h3>
<p><a href="https://concoursetutorial.com/basics/publishing-outputs/">Publishing Outputs</a></p>

<p>The tutorial step where you publish outputs involves putting private keys in your pipeline.yml file which feels terrible. I was able to swap
it out to use a personal access token on GitHub by switching the out the :uri under the git resource for username and password where password is
just the reference to the personal access token. I was surprised to see the use of private keys at all in the tutorial. I also made sure
to lock down the token to only be able to create gists since this tutorial step updates a particular gist.</p>

<p><em>Original Config</em></p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">resource-gist</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">git</span>
  <span class="na">source</span><span class="pi">:</span>
    <span class="na">uri</span><span class="pi">:</span> <span class="s">git@gist.github.com:e028e491e42b9fb08447a3bafcf884e5.git</span>
    <span class="na">branch</span><span class="pi">:</span> <span class="s">master</span>
    <span class="na">private_key</span><span class="pi">:</span> <span class="pi">|-</span>
      <span class="s">-----BEGIN RSA PRIVATE KEY-----</span>
      <span class="s">MIIEpQIBAAKCAQEAuvUl9YU...</span>
      <span class="s">...</span>
      <span class="s">HBstYQubAQy4oAEHu8osRhH...</span>
      <span class="s">-----END RSA PRIVATE KEY-----</span>
</code></pre></div></div>

<p><em>Config With Personal Access Token</em></p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">resource-gist</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">git</span>
  <span class="na">source</span><span class="pi">:</span>
    <span class="na">uri</span><span class="pi">:</span> <span class="s">https://gist.github.com/e028e491e42b9fb08447a3bafcf884e5.git</span>
    <span class="na">branch</span><span class="pi">:</span> <span class="s">master</span>
    <span class="na">username</span><span class="pi">:</span> <span class="s">edgibbs</span>
    <span class="na">password</span><span class="pi">:</span> <span class="s">ddf78dffcaf4398bec2323</span>
</code></pre></div></div>

<h3 id="credhub">CredHub</h3>
<p><a href="https://concoursetutorial.com/basics/secret-parameters/">Secrets With Credentials Manager</a></p>

<p>After the step of making sure I had an up to date VirtualBox and cloning Stark and Wayne’s CLI <code class="language-plaintext highlighter-rouge">bucc</code>, it
failed right away. They have a note about needing <code class="language-plaintext highlighter-rouge">direnv</code>, but I had to do a bit more config with it:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'eval "$(./bin/bucc env)"'</span> <span class="o">&gt;</span> .envrc
brew <span class="nb">install </span>direnv
direnv allow
</code></pre></div></div>

<p>Despite these few missteps I was able to work my way through the tutorial and get an overall impression.</p>

<h1 id="takeaways">Takeaways</h1>

<h2 id="overall-architecture">Overall Architecture</h2>

<p>Under the covers Concourse relies on three main parts:</p>

<ul>
  <li>A master server, the ATC or air traffic controller that is the heart of concourse</li>
  <li>The TSA which is an ssh server for registering workers with the ATC</li>
  <li>Postgres for storing persistent data</li>
</ul>

<p>A pipeline in Concourse also has three main items:</p>

<ul>
  <li>Resources are things like git, artifact creation, or Slack</li>
  <li>Resource types are custom resources that you can define or use other community contributed resources</li>
  <li>Jobs are where the work of the pipeline happens</li>
</ul>

<p>In contrast with Jenkins, there is a UI with the TSA, but it is used only for reporting or potentially
kicking off jobs.  The main interface is the <code class="language-plaintext highlighter-rouge">fly</code> CLI. And everything essentially runs inside containers like
Docker.</p>

<h2 id="impressions">Impressions</h2>

<p>Much of the workflow derives from the CLI, and pipelines are first class citizens. The ability to test
out a pipeline locally with <code class="language-plaintext highlighter-rouge">fly</code> is way ahead of setting up something like Jenkins especially if your organization
uses a lot of plugins. Another change is because Concourse is designed to have atomic jobs so you can actually retrigger
a pipeline from a particular stage.</p>

<p>The UI in Concourse is a minimalist dark mode style web interface. Jenkins still feels like it’s straight out of 2002, so
it was nice to see a visual representation with boxes and lines versus the tables of Jenkins current pipeline representations.</p>

<p>One area that looks like it might be a pain with Concourse is its support for artifacts. Since each job is atomic, you have to
handle passing things between jobs by pushing it out and storing it with a resource. Then some late job can pick it up
and process it further.</p>

<p>The declarative style syntax of the pipelines appears to be fine, though I wouldn’t have minded the option to escape out to a full
programming language.</p>

<p>Overall I thought it was an novel direction on CI servers and worth a deeper dive down the road.</p>]]></content><author><name>Ed Gibbs</name></author><category term="software development" /><category term="automated builds" /><summary type="html"><![CDATA[Over the holidays I had a chance to do a review of the CI options out there. I’m more than happy with something like Travis, and I’ve often said Jenkins is the Wordpress of CI Servers even though I’ve used it now for the bulk of my career. Currently, I’m working on building out a full production pipeline for the State of California where we are attempting to be transparent and use AGPL 3.0 for all of our code. That pretty much eliminated Travis CI, Codeship, and Circle CI. I realize they’re free for open source projects in general, but suffice it to say that getting a SASS solution, even a free one approved with some level of access to our Github organization is a tall order with the existing policies in place. So self-hosted open source was going to be our options.]]></summary></entry><entry><title type="html">The Dark Side of Javascript Fatigue</title><link href="https://edgibbs.com/2016/02/08/the-dark-side-of-javascript-fatigue/" rel="alternate" type="text/html" title="The Dark Side of Javascript Fatigue" /><published>2016-02-08T20:54:20+00:00</published><updated>2016-02-08T20:54:20+00:00</updated><id>https://edgibbs.com/2016/02/08/the-dark-side-of-javascript-fatigue</id><content type="html" xml:base="https://edgibbs.com/2016/02/08/the-dark-side-of-javascript-fatigue/"><![CDATA[<p>Javascript fatigue is a real experience for many developers who don’t spend their day to day in Node.js bashing out javascript. For many developers javascript is an occasional concern. The thing I can’t figure out about the javascript development world is the incredible churn. Churn is often disaster for a programming community. It frustrates anyone trying to build a solid application that will have a shelf life of a decade or more. Newcomers are treated to overwhelming choices without enough knowledge to choose. Then they find what they’ve learned is no longer the new and shiny tool only a few months later. And anyone on the outside feels validated in not jumping in.</p>

<p>Many in the javascript community attempt to couch all the churn as a benefit. It’s the incredible pace of innovation. I see sentiments like this:</p>

<blockquote>
  <p>The truth is, if you don’t like to constantly be learning new things, web development is probably not for you. You might have chosen the wrong career!</p>
</blockquote>

<blockquote>
  <p>— <a href="https://medium.com/@joshburgess/javascript-fatigue-an-alternative-perspective-b6ae411e89ac#.io6cl65k9">Josh Burgess</a></p>
</blockquote>

<p>Even if we accept that it all the ‘innovation’ is moving things forward more quickly, there is rarely the reflection on the consequences. I’ve worked on an approximately 9 year old Rails app for about 5 years now and I’m still shocked by the number different frameworks and styles of javascript that litter the app:</p>

<ul>
  <li>Hand rolled pre JQuery javascript</li>
  <li>Javascript cut and paste style</li>
  <li>RJS (an attempt to avoid writing javascript altogether in early rails)</li>
  <li>YUI</li>
  <li>Prototype</li>
  <li>Google Closure</li>
  <li>JQuery</li>
  <li>Angular</li>
</ul>

<p>Eight different frameworks in about as many years. And though we adopted Angular about 2 years ago we’re already dealing with non-backwards compatibility, Angular 2.0. This is a large burden on maintenance and it costs us very real time to spin up on each one when we have to enhance the app or fix a bug.</p>

<p>This is a monolithic app that’s been built over quite a few years, but the big difference is the Rails app was opinionated and stuck to a lot of default conventions. The framework churn of Rails has been much more gradual and generally backwards compatible. The largest pain we experience was going from Rails 2 to 3, when Rails was merged with Merb. The knowledge someone built up in their first few years working in Ruby and Rails still applies. The churn is certainly exists, but at a measure pace.</p>

<p>In phone screens when I describe our main app, I list off the myriad javascript frameworks we use as a negative they should know about. And almost none of the candidates have heard of Google Closure, even though a critical piece of the app was written in it. They often assume I must be talking about the JVM Clojure.</p>

<p>Javascript has never been popular because of elegance or syntax. Rants like the following are not hard to find:</p>

<blockquote>
  <p>You see the Node.js philosophy is to take the worst fucking language ever designed and put it on the server.</p>
</blockquote>

<blockquote>
  <p>— <a href="https://medium.com/@wob/the-sad-state-of-web-development-1603a861d29f#.2v49dasi5">Drew Hamlett</a></p>
</blockquote>

<p>Large majorities of developers would rather avoid it completely to focus on any modern language and hopefully use a transpiler if they have to touch Javascript. In this environment it might do the javascript community some good to settle down some and focus on some stability.</p>]]></content><author><name>Ed Gibbs</name></author><category term="javascript" /><category term="ruby" /><category term="software development" /><summary type="html"><![CDATA[Javascript fatigue is a real experience for many developers who don’t spend their day to day in Node.js bashing out javascript. For many developers javascript is an occasional concern. The thing I can’t figure out about the javascript development world is the incredible churn. Churn is often disaster for a programming community. It frustrates anyone trying to build a solid application that will have a shelf life of a decade or more. Newcomers are treated to overwhelming choices without enough knowledge to choose. Then they find what they’ve learned is no longer the new and shiny tool only a few months later. And anyone on the outside feels validated in not jumping in.]]></summary></entry></feed>